From: Ma Wupeng <[email protected]>
Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
introduced mirrored memory support for x86. This support rely on UEFI to
report mirrored memory address ranges. See UEFI 2.5 spec pages 157-158:
http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf
Memory mirroring is a technique used to separate memory into two separate
channels, usually on a memory device, like a server. In memory mirroring,
one channel is copied to another to create redundancy. This method makes
input/output (I/O) registers and memory appear with more than one address
range because the same physical byte is accessible at more than one
address. Using memory mirroring, higher memory reliability and a higher
level of memory consolidation are possible.
Arm64 can support this too. So mirrored memory support is added to support
arm64.
Efi_fake_mem is used for testing mirrored features and will not be used in
production environment. This test features can fake memory's attribute
values.
The reason why efi_fake_mem support is put first is that memory's attribute
is reported by BIOS which is hard to simulate. With this support, any arm64
machines with efi support can easily test mirrored features.
The main purpose of this patchset is to introduce mirrored support for
arm64 and we have already fixed the problems we had which is shown in
patch #5 to patch #7 and try to bring total isolation in patch #8 which
will disable mirror feature if kernelcore is not specified.
In order to test this support in arm64:
- patch this patchset
- add efi_fake_mem=8G@0:0x10000 in kernel parameter to simulate mirrored
memroy between phy addr 0-8G.
- add kernelcore=mirror in kernel parameter
- start you kernel
Patch #1-#2 introduce efi_fake_mem support for arm64.
Patch #3-#4 introduce mirrored memory support form arm64.
Patch #5-#7 fix some bugs for arm64 if memory reliable is enabled.
Patch #8 disable mirror feature if kernelPHYS_PFNcore is not specified.
Patch #9 remove some redundant code in ia64 efi_init.
Changelog since v1:
- update changelog in cover letter
- use PHYS_PFN in patch #7
Ma Wupeng (9):
efi: Make efi_print_memmap() public
arm64: efi: Add fake memory support
efi: Make efi_find_mirror() public
arm64/mirror: arm64 enabling - find mirrored memory ranges
mm: Ratelimited mirrored memory related warning messages
mm: Demote warning message in vmemmap_verify() to debug level
mm: Calc the right pfn if page size is not 4K
efi: Disable mirror feature if kernelcore is not specified
ia64/efi: Code simplification in efi_init
.../admin-guide/kernel-parameters.txt | 4 +-
arch/arm64/kernel/setup.c | 3 ++
arch/ia64/kernel/efi.c | 37 +-----------------
arch/x86/include/asm/efi.h | 5 ---
arch/x86/platform/efi/efi.c | 39 -------------------
drivers/firmware/efi/Kconfig | 2 +-
drivers/firmware/efi/efi.c | 26 +++++++++++++
drivers/firmware/efi/memmap.c | 16 ++++++++
include/linux/efi.h | 4 ++
include/linux/mm.h | 2 +
mm/memblock.c | 4 +-
mm/page_alloc.c | 4 +-
mm/sparse-vmemmap.c | 2 +-
13 files changed, 60 insertions(+), 88 deletions(-)
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
Make efi_print_memmap() public in preparation for adding fake memory
support for architecture with efi support, eg, arm64.
Signed-off-by: Ma Wupeng <[email protected]>
---
arch/x86/include/asm/efi.h | 1 -
arch/x86/platform/efi/efi.c | 16 ----------------
drivers/firmware/efi/memmap.c | 16 ++++++++++++++++
include/linux/efi.h | 1 +
4 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 98938a68251c..686968073f48 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -150,7 +150,6 @@ extern asmlinkage u64 __efi_call(void *fp, ...);
#endif /* CONFIG_X86_32 */
extern int __init efi_memblock_x86_reserve_range(void);
-extern void __init efi_print_memmap(void);
extern void __init efi_map_region(efi_memory_desc_t *md);
extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
extern void efi_sync_low_kernel_mappings(void);
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 147c30a81f15..7b130f39d841 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -323,22 +323,6 @@ static void __init efi_clean_memmap(void)
}
}
-void __init efi_print_memmap(void)
-{
- efi_memory_desc_t *md;
- int i = 0;
-
- for_each_efi_memory_desc(md) {
- char buf[64];
-
- pr_info("mem%02u: %s range=[0x%016llx-0x%016llx] (%lluMB)\n",
- i++, efi_md_typeattr_format(buf, sizeof(buf), md),
- md->phys_addr,
- md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1,
- (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
- }
-}
-
static int __init efi_systab_init(unsigned long phys)
{
int size = efi_enabled(EFI_64BIT) ? sizeof(efi_system_table_64_t)
diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c
index 4df55a55da84..04cc1f2cdfa4 100644
--- a/drivers/firmware/efi/memmap.c
+++ b/drivers/firmware/efi/memmap.c
@@ -376,3 +376,19 @@ void __init efi_memmap_insert(struct efi_memory_map *old_memmap, void *buf,
}
}
}
+
+void __init efi_print_memmap(void)
+{
+ efi_memory_desc_t *md;
+ int i = 0;
+
+ for_each_efi_memory_desc(md) {
+ char buf[64];
+
+ pr_info("mem%02u: %s range=[0x%016llx-0x%016llx] (%lluMB)\n",
+ i++, efi_md_typeattr_format(buf, sizeof(buf), md),
+ md->phys_addr,
+ md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1,
+ (md->num_pages >> (20 - EFI_PAGE_SHIFT)));
+ }
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index ccd4d3f91c98..de05682b233b 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -684,6 +684,7 @@ extern int __init efi_memmap_split_count(efi_memory_desc_t *md,
struct range *range);
extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap,
void *buf, struct efi_mem_range *mem);
+extern void __init efi_print_memmap(void);
#ifdef CONFIG_EFI_ESRT
extern void __init efi_esrt_init(void);
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory
ranges") introduce the efi_find_mirror function on x86. In order to reuse
the API we make it public in preparation for arm64 to support mirrord
memory.
Signed-off-by: Ma Wupeng <[email protected]>
---
arch/x86/include/asm/efi.h | 4 ----
arch/x86/platform/efi/efi.c | 23 -----------------------
drivers/firmware/efi/efi.c | 23 +++++++++++++++++++++++
include/linux/efi.h | 3 +++
4 files changed, 26 insertions(+), 27 deletions(-)
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 686968073f48..6be838c0f109 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -368,7 +368,6 @@ static inline bool efi_is_64bit(void)
extern bool efi_reboot_required(void);
extern bool efi_is_table_address(unsigned long phys_addr);
-extern void efi_find_mirror(void);
extern void efi_reserve_boot_services(void);
#else
static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
@@ -380,9 +379,6 @@ static inline bool efi_is_table_address(unsigned long phys_addr)
{
return false;
}
-static inline void efi_find_mirror(void)
-{
-}
static inline void efi_reserve_boot_services(void)
{
}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7b130f39d841..fedbb228faea 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -105,29 +105,6 @@ static int __init setup_add_efi_memmap(char *arg)
}
early_param("add_efi_memmap", setup_add_efi_memmap);
-void __init efi_find_mirror(void)
-{
- efi_memory_desc_t *md;
- u64 mirror_size = 0, total_size = 0;
-
- if (!efi_enabled(EFI_MEMMAP))
- return;
-
- for_each_efi_memory_desc(md) {
- unsigned long long start = md->phys_addr;
- unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
-
- total_size += size;
- if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
- memblock_mark_mirror(start, size);
- mirror_size += size;
- }
- }
- if (mirror_size)
- pr_info("Memory: %lldM/%lldM mirrored memory\n",
- mirror_size>>20, total_size>>20);
-}
-
/*
* Tell the kernel about the EFI memory map. This might include
* more than the max 128 entries that can fit in the passed in e820
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 5502e176d51b..eb9ebf4efea1 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -438,6 +438,29 @@ static int __init efisubsys_init(void)
subsys_initcall(efisubsys_init);
+void __init efi_find_mirror(void)
+{
+ efi_memory_desc_t *md;
+ u64 mirror_size = 0, total_size = 0;
+
+ if (!efi_enabled(EFI_MEMMAP))
+ return;
+
+ for_each_efi_memory_desc(md) {
+ unsigned long long start = md->phys_addr;
+ unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
+
+ total_size += size;
+ if (md->attribute & EFI_MEMORY_MORE_RELIABLE) {
+ memblock_mark_mirror(start, size);
+ mirror_size += size;
+ }
+ }
+ if (mirror_size)
+ pr_info("Memory: %lldM/%lldM mirrored memory\n",
+ mirror_size>>20, total_size>>20);
+}
+
/*
* Find the efi memory descriptor for a given physical address. Given a
* physical address, determine if it exists within an EFI Memory Map entry,
diff --git a/include/linux/efi.h b/include/linux/efi.h
index de05682b233b..950c84ce3f16 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -853,6 +853,7 @@ static inline bool efi_rt_services_supported(unsigned int mask)
{
return (efi.runtime_supported_mask & mask) == mask;
}
+extern void efi_find_mirror(void);
#else
static inline bool efi_enabled(int feature)
{
@@ -870,6 +871,8 @@ static inline bool efi_rt_services_supported(unsigned int mask)
{
return false;
}
+
+static inline void efi_find_mirror(void) {}
#endif
extern int efi_status_to_err(efi_status_t status);
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
With this patch, kernel will check mirrored_kernelcore before calling
efi_find_mirror() which will enable basic mirrored feature.
If system have some mirrored memory and mirrored feature is not specified
in boot parameter, the basic mirrored feature will be enabled and this will
lead to the following situations:
- memblock memory allocation perfers mirrored region. This may have some
unexpected influence on numa affinity.
- contiguous memory will be splited into several parts if parts of them
is mirrored memory via memblock_mark_mirror().
Signed-off-by: Ma Wupeng <[email protected]>
---
drivers/firmware/efi/efi.c | 3 +++
include/linux/mm.h | 2 ++
mm/page_alloc.c | 2 +-
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index eb9ebf4efea1..18d86602424a 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -446,6 +446,9 @@ void __init efi_find_mirror(void)
if (!efi_enabled(EFI_MEMMAP))
return;
+ if (!mirrored_kernelcore)
+ return;
+
for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e34edb775334..544717cc7a75 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2536,6 +2536,8 @@ extern void get_pfn_range_for_nid(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn);
extern unsigned long find_min_pfn_with_active_regions(void);
+extern bool mirrored_kernelcore;
+
#ifndef CONFIG_NUMA
static inline int early_pfn_to_nid(unsigned long pfn)
{
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 570d0ebf98df..909d5f7d97bb 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -355,7 +355,7 @@ static unsigned long required_kernelcore_percent __initdata;
static unsigned long required_movablecore __initdata;
static unsigned long required_movablecore_percent __initdata;
static unsigned long zone_movable_pfn[MAX_NUMNODES] __initdata;
-static bool mirrored_kernelcore __meminitdata;
+bool mirrored_kernelcore __meminitdata;
/* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
int movable_zone;
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
Previous 0x100000 is used to check the 4G limit in
find_zone_movable_pfns_for_nodes(). This is right in x86 because
the page size can only be 4K. But 16K and 64K are available in
arm64. So replace it with PHYS_PFN(SZ_4G).
Signed-off-by: Ma Wupeng <[email protected]>
---
mm/page_alloc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 6e5b4488a0c5..570d0ebf98df 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
usable_startpfn = memblock_region_memory_base_pfn(r);
- if (usable_startpfn < 0x100000) {
+ if (usable_startpfn < PHYS_PFN(SZ_4G)) {
mem_below_4gb_not_mirrored = true;
continue;
}
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
Fake memory map is used for faking memory's attribute values.
Commit 0f96a99dab36 ("efi: Add "efi_fake_mem" boot option") introduce the
efi_fake_mem function. Now it can support arm64 with this patch.
For example you can mark 0-6G memory as EFI_MEMORY_MORE_RELIABLE by adding
efi_fake_mem=6G@0:0x10000 in the bootarg. You find more info about
fake memmap in kernel-parameters.txt.
Variable memstart_addr is only confirmed after arm64_memblock_init(). So
efi_fake_memmap() is needed to add after arm64_memblock_init().
Otherwise:
efi_memmap_alloc
memblock_phys_alloc
kmemleak_alloc_phys
kmemleak_alloc(__va(phys), size, min_count, gfp);
this __va() will convert phys to a fault va and lead to a kmemleak error.
Signed-off-by: Ma Wupeng <[email protected]>
---
Documentation/admin-guide/kernel-parameters.txt | 2 +-
arch/arm64/kernel/setup.c | 2 ++
drivers/firmware/efi/Kconfig | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3f1cc5e317ed..ea47c0ba7593 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1357,7 +1357,7 @@
you are really sure that your UEFI does sane gc and
fulfills the spec otherwise your board may brick.
- efi_fake_mem= nn[KMG]@ss[KMG]:aa[,nn[KMG]@ss[KMG]:aa,..] [EFI; X86]
+ efi_fake_mem= nn[KMG]@ss[KMG]:aa[,nn[KMG]@ss[KMG]:aa,..] [EFI; X86; ARM64]
Add arbitrary attribute to specific memory range by
updating original EFI memory map.
Region of memory which aa attribute is added to is
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 3505789cf4bd..daade64889ff 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -344,6 +344,8 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
arm64_memblock_init();
+ efi_fake_memmap();
+
paging_init();
acpi_table_upgrade();
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 2c3dac5ecb36..3c91bbd4097a 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -50,7 +50,7 @@ config EFI_RUNTIME_MAP
config EFI_FAKE_MEMMAP
bool "Enable EFI fake memory map"
- depends on EFI && X86
+ depends on EFI && (X86 || ARM64)
default n
help
Saying Y here will enable "efi_fake_mem" boot option.
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
introduced mirrored memory support for x86 and this could be used on arm64.
So efi_find_mirror() is added in efi_init() so on EFI enabled systems scan
the memory map and tell memblock about any mirrored ranges.
Signed-off-by: Ma Wupeng <[email protected]>
---
Documentation/admin-guide/kernel-parameters.txt | 2 +-
arch/arm64/kernel/setup.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index ea47c0ba7593..1d87dc4e3cef 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2270,7 +2270,7 @@
keepinitrd [HW,ARM]
- kernelcore= [KNL,X86,IA-64,PPC]
+ kernelcore= [KNL,X86,IA-64,PPC,ARM64]
Format: nn[KMGTPE] | nn% | "mirror"
This parameter specifies the amount of memory usable by
the kernel for non-movable allocations. The requested
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index daade64889ff..3957290d9ade 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -345,6 +345,7 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
arm64_memblock_init();
efi_fake_memmap();
+ efi_find_mirror();
paging_init();
--
2.18.0.huawei.25
From: Ma Wupeng <[email protected]>
If system has mirrored memory, memblock will try to allocate mirrored
memory firstly and fallback to non-mirrored memory when fails, but if with
limited mirrored memory or some numa node without mirrored memory, lots of
warning message about memblock allocation will occur.
This patch ratelimit the warning message to avoid a very long print during
bootup.
Signed-off-by: Ma Wupeng <[email protected]>
---
mm/memblock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/memblock.c b/mm/memblock.c
index e4f03a6e8e56..b1d2a0009733 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -327,7 +327,7 @@ static phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start,
NUMA_NO_NODE, flags);
if (!ret && (flags & MEMBLOCK_MIRROR)) {
- pr_warn("Could not allocate %pap bytes of mirrored memory\n",
+ pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n",
&size);
flags &= ~MEMBLOCK_MIRROR;
goto again;
@@ -1384,7 +1384,7 @@ phys_addr_t __init memblock_alloc_range_nid(phys_addr_t size,
if (flags & MEMBLOCK_MIRROR) {
flags &= ~MEMBLOCK_MIRROR;
- pr_warn("Could not allocate %pap bytes of mirrored memory\n",
+ pr_warn_ratelimited("Could not allocate %pap bytes of mirrored memory\n",
&size);
goto again;
}
--
2.18.0.huawei.25
On Thu, 14 Apr 2022 at 11:54, Wupeng Ma <[email protected]> wrote:
>
> From: Ma Wupeng <[email protected]>
>
> Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
> introduced mirrored memory support for x86. This support rely on UEFI to
> report mirrored memory address ranges. See UEFI 2.5 spec pages 157-158:
>
> http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf
>
> Memory mirroring is a technique used to separate memory into two separate
> channels, usually on a memory device, like a server. In memory mirroring,
> one channel is copied to another to create redundancy. This method makes
> input/output (I/O) registers and memory appear with more than one address
> range because the same physical byte is accessible at more than one
> address. Using memory mirroring, higher memory reliability and a higher
> level of memory consolidation are possible.
>
> Arm64 can support this too. So mirrored memory support is added to support
> arm64.
>
> Efi_fake_mem is used for testing mirrored features and will not be used in
> production environment. This test features can fake memory's attribute
> values.
>
> The reason why efi_fake_mem support is put first is that memory's attribute
> is reported by BIOS which is hard to simulate. With this support, any arm64
> machines with efi support can easily test mirrored features.
>
> The main purpose of this patchset is to introduce mirrored support for
> arm64 and we have already fixed the problems we had which is shown in
> patch #5 to patch #7 and try to bring total isolation in patch #8 which
> will disable mirror feature if kernelcore is not specified.
>
> In order to test this support in arm64:
> - patch this patchset
> - add efi_fake_mem=8G@0:0x10000 in kernel parameter to simulate mirrored
> memroy between phy addr 0-8G.
> - add kernelcore=mirror in kernel parameter
> - start you kernel
>
As I explained before:
- NAK to EFI fake_mem support on arm64
- NAK to the whole series until you come up with a proposal on how to
locate the static kernel image itself into more reliable memory, as
there is really no point to any of this otherwise.
在 2022/4/14 18:22, Ard Biesheuvel 写道:
> On Thu, 14 Apr 2022 at 11:54, Wupeng Ma <[email protected]> wrote:
>>
>> From: Ma Wupeng <[email protected]>
>>
>> Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
>> introduced mirrored memory support for x86. This support rely on UEFI to
>> report mirrored memory address ranges. See UEFI 2.5 spec pages 157-158:
>>
>> http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf
>>
>> Memory mirroring is a technique used to separate memory into two separate
>> channels, usually on a memory device, like a server. In memory mirroring,
>> one channel is copied to another to create redundancy. This method makes
>> input/output (I/O) registers and memory appear with more than one address
>> range because the same physical byte is accessible at more than one
>> address. Using memory mirroring, higher memory reliability and a higher
>> level of memory consolidation are possible.
>>
>> Arm64 can support this too. So mirrored memory support is added to support
>> arm64.
>>
>> Efi_fake_mem is used for testing mirrored features and will not be used in
>> production environment. This test features can fake memory's attribute
>> values.
>>
>> The reason why efi_fake_mem support is put first is that memory's attribute
>> is reported by BIOS which is hard to simulate. With this support, any arm64
>> machines with efi support can easily test mirrored features.
>>
>> The main purpose of this patchset is to introduce mirrored support for
>> arm64 and we have already fixed the problems we had which is shown in
>> patch #5 to patch #7 and try to bring total isolation in patch #8 which
>> will disable mirror feature if kernelcore is not specified.
>>
>> In order to test this support in arm64:
>> - patch this patchset
>> - add efi_fake_mem=8G@0:0x10000 in kernel parameter to simulate mirrored
>> memroy between phy addr 0-8G.
>> - add kernelcore=mirror in kernel parameter
>> - start you kernel
>>
>
> As I explained before:
>
> - NAK to EFI fake_mem support on arm64
fake_mem support on arm64 will be removed in subsequent version.
> - NAK to the whole series until you come up with a proposal on how to
> locate the static kernel image itself into more reliable memory, as
> there is really no point to any of this otherwise.
Sorry I am not familiar with this, as you metioned before,
> you have to iterate over the memory map and look for regions with
> the desired attribute, and allocate those pages explicitly.
Do you mean this is x86, commit c05cd79750fb
("x86/boot/KASLR: Prefer mirrored memory regions for the kernel physical address").
I will do some research.
> I'd prefer to implement this in the bootloader, and only add minimal
> logic to the stub to respect the placement of the kernel by the loader
> if the loader signals it to do so.
Does this bootloader refer to grub and then add minimal logic to arm64-stub.c?
What is the loader signal?
System exists mirrored memory reported by uefi?
Thanks for reviewing, sorry for my ignorance on this.
> .
On 14.04.22 12:13, Wupeng Ma wrote:
> From: Ma Wupeng <[email protected]>
>
> Previous 0x100000 is used to check the 4G limit in
> find_zone_movable_pfns_for_nodes(). This is right in x86 because
> the page size can only be 4K. But 16K and 64K are available in
> arm64. So replace it with PHYS_PFN(SZ_4G).
>
> Signed-off-by: Ma Wupeng <[email protected]>
> ---
> mm/page_alloc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 6e5b4488a0c5..570d0ebf98df 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
>
> usable_startpfn = memblock_region_memory_base_pfn(r);
>
> - if (usable_startpfn < 0x100000) {
> + if (usable_startpfn < PHYS_PFN(SZ_4G)) {
> mem_below_4gb_not_mirrored = true;
> continue;
> }
Reviewed-by: David Hildenbrand <[email protected]>
--
Thanks,
David / dhildenb
From: Ma Wupeng <[email protected]>
Now system image will perfer to be located to mirrored regions both KASLR
on and off.
Ma Wupeng (2):
arm64/boot/KASLR: Add support to relocate kernel image to mirrored
region
arm64/boot: Add support to relocate kernel image to mirrored region
without kaslr
drivers/firmware/efi/libstub/arm64-stub.c | 62 +++++++++++++++++++++-
drivers/firmware/efi/libstub/efistub.h | 7 ++-
drivers/firmware/efi/libstub/randomalloc.c | 14 ++++-
3 files changed, 79 insertions(+), 4 deletions(-)
--
2.25.1
On 4/14/22 15:43, Wupeng Ma wrote:
> From: Ma Wupeng <[email protected]>
>
> Previous 0x100000 is used to check the 4G limit in
> find_zone_movable_pfns_for_nodes(). This is right in x86 because
> the page size can only be 4K. But 16K and 64K are available in
> arm64. So replace it with PHYS_PFN(SZ_4G).
>
> Signed-off-by: Ma Wupeng <[email protected]>
> ---
> mm/page_alloc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 6e5b4488a0c5..570d0ebf98df 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
>
> usable_startpfn = memblock_region_memory_base_pfn(r);
>
> - if (usable_startpfn < 0x100000) {
> + if (usable_startpfn < PHYS_PFN(SZ_4G)) {
> mem_below_4gb_not_mirrored = true;
> continue;
> }
Regardless PFN value should never be encoded directly.
Reviewed-by: Anshuman Khandual <[email protected]>
From: Ma Wupeng <[email protected]>
Add support to relocate kernel image to mirrored regions if KASLR is
enabled.
If a suiable mirrored slot if found, iterate EFI memory map and pick the
mirrored region to process for adding candidate of randomization slot. If
no suitable mirrored region found, alloc memory from non-mirrored regions.
Signed-off-by: Ma Wupeng <[email protected]>
---
drivers/firmware/efi/libstub/arm64-stub.c | 52 +++++++++++++++++++++-
drivers/firmware/efi/libstub/efistub.h | 7 ++-
drivers/firmware/efi/libstub/randomalloc.c | 13 +++++-
3 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 9cc556013d08..39b774853b93 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -79,6 +79,51 @@ static bool check_image_region(u64 base, u64 size)
return ret;
}
+/* check if system has suitable for kernel to relocate */
+static bool check_mirror_suitable(unsigned long size,
+ unsigned long align)
+{
+ unsigned long map_size, desc_size;
+ unsigned long buff_size;
+ efi_status_t status;
+ efi_memory_desc_t *memory_map;
+ int map_offset;
+ struct efi_boot_memmap map;
+ bool found = false;
+
+ map.map = &memory_map;
+ map.map_size = &map_size;
+ map.desc_size = &desc_size;
+ map.desc_ver = NULL;
+ map.key_ptr = NULL;
+ map.buff_size = &buff_size;
+
+ status = efi_get_memory_map(&map);
+ if (status != EFI_SUCCESS)
+ return false;
+
+ if (align < EFI_ALLOC_ALIGN)
+ align = EFI_ALLOC_ALIGN;
+
+ size = round_up(size, EFI_ALLOC_ALIGN);
+
+ for (map_offset = 0; map_offset < map_size; map_offset += desc_size) {
+ efi_memory_desc_t *md = (void *)memory_map + map_offset;
+ unsigned long slots;
+
+ /* system has suiable mirrored area */
+ slots = get_entry_num_slots(md, size, ilog2(align));
+ if (slots > 0 && md->attribute & EFI_MEMORY_MORE_RELIABLE) {
+ found = true;
+ break;
+ }
+ }
+
+ efi_bs_call(free_pool, memory_map);
+
+ return found;
+}
+
efi_status_t handle_kernel_image(unsigned long *image_addr,
unsigned long *image_size,
unsigned long *reserve_addr,
@@ -88,6 +133,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
efi_status_t status;
unsigned long kernel_size, kernel_memsize = 0;
u32 phys_seed = 0;
+ bool efi_mirror_found;
/*
* Although relocatable kernels can fix up the misalignment with
@@ -127,13 +173,16 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
kernel_memsize = kernel_size + (_end - _edata);
*reserve_size = kernel_memsize;
+ efi_mirror_found = check_mirror_suitable(*reserve_size, min_kimg_align);
+
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
/*
* If KASLR is enabled, and we have some randomness available,
* locate the kernel at a randomized offset in physical memory.
*/
status = efi_random_alloc(*reserve_size, min_kimg_align,
- reserve_addr, phys_seed);
+ reserve_addr, phys_seed,
+ efi_mirror_found);
if (status != EFI_SUCCESS)
efi_warn("efi_random_alloc() failed: 0x%lx\n", status);
} else {
@@ -163,6 +212,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
}
}
+out:
*image_addr = *reserve_addr;
memcpy((void *)*image_addr, _text, kernel_size);
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index edb77b0621ea..0cf2e25cb7d0 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -790,7 +790,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
efi_status_t efi_get_random_bytes(unsigned long size, u8 *out);
efi_status_t efi_random_alloc(unsigned long size, unsigned long align,
- unsigned long *addr, unsigned long random_seed);
+ unsigned long *addr, unsigned long random_seed,
+ bool efi_has_mirror);
efi_status_t check_platform_features(void);
@@ -875,6 +876,10 @@ void efi_handle_post_ebs_state(void);
enum efi_secureboot_mode efi_get_secureboot(void);
+extern unsigned long get_entry_num_slots(efi_memory_desc_t *md,
+ unsigned long size,
+ unsigned long align_shift);
+
#ifdef CONFIG_RESET_ATTACK_MITIGATION
void efi_enable_reset_attack_mitigation(void);
#else
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
index 724155b9e10d..dd81d6c3c406 100644
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -14,7 +14,7 @@
* addresses it covers that are suitably aligned and supply enough room
* for the allocation.
*/
-static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
+unsigned long get_entry_num_slots(efi_memory_desc_t *md,
unsigned long size,
unsigned long align_shift)
{
@@ -53,7 +53,8 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
efi_status_t efi_random_alloc(unsigned long size,
unsigned long align,
unsigned long *addr,
- unsigned long random_seed)
+ unsigned long random_seed,
+ bool efi_mirror_found)
{
unsigned long map_size, desc_size, total_slots = 0, target_slot;
unsigned long buff_size;
@@ -83,6 +84,10 @@ efi_status_t efi_random_alloc(unsigned long size,
efi_memory_desc_t *md = (void *)memory_map + map_offset;
unsigned long slots;
+ if (efi_mirror_found &&
+ !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
+ continue;
+
slots = get_entry_num_slots(md, size, ilog2(align));
MD_NUM_SLOTS(md) = slots;
total_slots += slots;
@@ -112,6 +117,10 @@ efi_status_t efi_random_alloc(unsigned long size,
continue;
}
+ if (efi_mirror_found &&
+ !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
+ continue;
+
target = round_up(md->phys_addr, align) + target_slot * align;
pages = size / EFI_PAGE_SIZE;
--
2.25.1
From: Ma Wupeng <[email protected]>
Add support to relocate kernel image to mirrord regions if KASLR doesn't
work.
If a suiable mirrored slot if found, call efi_random_alloc() with
random_seed be zero to relocate kernel code and data to the first slot
available.
Signed-off-by: Ma Wupeng <[email protected]>
---
drivers/firmware/efi/libstub/arm64-stub.c | 10 ++++++++++
drivers/firmware/efi/libstub/randomalloc.c | 1 +
2 files changed, 11 insertions(+)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 39b774853b93..851a8948cafb 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -190,6 +190,16 @@ efi_status_t handle_kernel_image(unsigned long *image_addr,
}
if (status != EFI_SUCCESS) {
+ if (efi_mirror_found) {
+ status = efi_random_alloc(*reserve_size, min_kimg_align,
+ reserve_addr, 0,
+ efi_mirror_found);
+ if (status == EFI_SUCCESS)
+ goto out;
+
+ efi_err("Failed to relocate kernel to mirrored region\n");
+ }
+
if (!check_image_region((u64)_text, kernel_memsize)) {
efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n");
} else if (IS_ALIGNED((u64)_text, min_kimg_align)) {
diff --git a/drivers/firmware/efi/libstub/randomalloc.c b/drivers/firmware/efi/libstub/randomalloc.c
index dd81d6c3c406..d5f4249943a7 100644
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -50,6 +50,7 @@ unsigned long get_entry_num_slots(efi_memory_desc_t *md,
*/
#define MD_NUM_SLOTS(md) ((md)->virt_addr)
+/* random_seed == 0 means alloc mem from the first suitable slot */
efi_status_t efi_random_alloc(unsigned long size,
unsigned long align,
unsigned long *addr,
--
2.25.1
On Tue, 19 Apr 2022 at 13:13, Anshuman Khandual
<[email protected]> wrote:
>
>
>
> On 4/14/22 15:43, Wupeng Ma wrote:
> > From: Ma Wupeng <[email protected]>
> >
> > Previous 0x100000 is used to check the 4G limit in
> > find_zone_movable_pfns_for_nodes(). This is right in x86 because
> > the page size can only be 4K. But 16K and 64K are available in
> > arm64. So replace it with PHYS_PFN(SZ_4G).
> >
> > Signed-off-by: Ma Wupeng <[email protected]>
> > ---
> > mm/page_alloc.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> > index 6e5b4488a0c5..570d0ebf98df 100644
> > --- a/mm/page_alloc.c
> > +++ b/mm/page_alloc.c
> > @@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
> >
> > usable_startpfn = memblock_region_memory_base_pfn(r);
> >
> > - if (usable_startpfn < 0x100000) {
> > + if (usable_startpfn < PHYS_PFN(SZ_4G)) {
> > mem_below_4gb_not_mirrored = true;
> > continue;
> > }
>
> Regardless PFN value should never be encoded directly.
>
> Reviewed-by: Anshuman Khandual <[email protected]>
Acked-by: Ard Biesheuvel <[email protected]>
Andrew, can you please take this one through the -mm tree? The rest of
the series needs a bit more work, but is an obvious fix and there is
no point in holding it up.
Thanks,
Ard.
On Thu, 21 Apr 2022 at 00:27, Andrew Morton <[email protected]> wrote:
>
> On Tue, 19 Apr 2022 20:29:27 +0200 Ard Biesheuvel <[email protected]> wrote:
>
> > > > --- a/mm/page_alloc.c
> > > > +++ b/mm/page_alloc.c
> > > > @@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
> > > >
> > > > usable_startpfn = memblock_region_memory_base_pfn(r);
> > > >
> > > > - if (usable_startpfn < 0x100000) {
> > > > + if (usable_startpfn < PHYS_PFN(SZ_4G)) {
> > > > mem_below_4gb_not_mirrored = true;
> > > > continue;
> > > > }
> > >
> > > Regardless PFN value should never be encoded directly.
> > >
> > > Reviewed-by: Anshuman Khandual <[email protected]>
> >
> > Acked-by: Ard Biesheuvel <[email protected]>
> >
> > Andrew, can you please take this one through the -mm tree? The rest of
> > the series needs a bit more work, but is an obvious fix and there is
> > no point in holding it up.
>
> Sure.
>
> I'm not seeing any description of the runtime effects of this
> shortcoming. I tentatively queued the fix for 5.18, without a
> cc:stable for backporting. But that might not be the best decision?
>
As far as I can tell, mirrored memory is only used on x86 today, where
pages are always 4k.
However, the whole notion of memory below 4 GB being special is a
x86-ism, and so this logic does not appear to extrapolate to other
architectures anyway, and probably needs more work.
So definitely not a backportable fix, but just an incremental
improvement, so either 5.18 or 5.19 should be fine afaict (and no
cc:stable)
On Sat, 16 Apr 2022 at 03:32, mawupeng <[email protected]> wrote:
>
>
>
> 在 2022/4/14 18:22, Ard Biesheuvel 写道:
> > On Thu, 14 Apr 2022 at 11:54, Wupeng Ma <[email protected]> wrote:
> >>
> >> From: Ma Wupeng <[email protected]>
> >>
> >> Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
> >> introduced mirrored memory support for x86. This support rely on UEFI to
> >> report mirrored memory address ranges. See UEFI 2.5 spec pages 157-158:
> >>
> >> http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf
> >>
> >> Memory mirroring is a technique used to separate memory into two separate
> >> channels, usually on a memory device, like a server. In memory mirroring,
> >> one channel is copied to another to create redundancy. This method makes
> >> input/output (I/O) registers and memory appear with more than one address
> >> range because the same physical byte is accessible at more than one
> >> address. Using memory mirroring, higher memory reliability and a higher
> >> level of memory consolidation are possible.
> >>
> >> Arm64 can support this too. So mirrored memory support is added to support
> >> arm64.
> >>
> >> Efi_fake_mem is used for testing mirrored features and will not be used in
> >> production environment. This test features can fake memory's attribute
> >> values.
> >>
> >> The reason why efi_fake_mem support is put first is that memory's attribute
> >> is reported by BIOS which is hard to simulate. With this support, any arm64
> >> machines with efi support can easily test mirrored features.
> >>
> >> The main purpose of this patchset is to introduce mirrored support for
> >> arm64 and we have already fixed the problems we had which is shown in
> >> patch #5 to patch #7 and try to bring total isolation in patch #8 which
> >> will disable mirror feature if kernelcore is not specified.
> >>
> >> In order to test this support in arm64:
> >> - patch this patchset
> >> - add efi_fake_mem=8G@0:0x10000 in kernel parameter to simulate mirrored
> >> memroy between phy addr 0-8G.
> >> - add kernelcore=mirror in kernel parameter
> >> - start you kernel
> >>
> >
> > As I explained before:
> >
> > - NAK to EFI fake_mem support on arm64
>
> fake_mem support on arm64 will be removed in subsequent version.
>
> > - NAK to the whole series until you come up with a proposal on how to
> > locate the static kernel image itself into more reliable memory, as
> > there is really no point to any of this otherwise.
>
> Sorry I am not familiar with this, as you metioned before,
>
> > you have to iterate over the memory map and look for regions with
> > the desired attribute, and allocate those pages explicitly.
>
> Do you mean this is x86, commit c05cd79750fb
> ("x86/boot/KASLR: Prefer mirrored memory regions for the kernel physical address").
> I will do some research.
>
> > I'd prefer to implement this in the bootloader, and only add minimal
> > logic to the stub to respect the placement of the kernel by the loader
> > if the loader signals it to do so.
>
> Does this bootloader refer to grub and then add minimal logic to arm64-stub.c?
>
Any bootloader, yes.
> What is the loader signal?
A protocol installed onto the image handle, as I suggested before. I
even cc'ed you on a patch that implements this.
> System exists mirrored memory reported by uefi?
>
What on earth is the point of any of this if the only use case being
targeted is efi_fake_mem with arbitrary fake mirrored regions?
So yes, unless there are systems that need this, I don't see a point
in merging any of this.
在 2022/4/20 2:32, Ard Biesheuvel 写道:
> On Sat, 16 Apr 2022 at 03:32, mawupeng <[email protected]> wrote:
>>
>>
>>
>> 在 2022/4/14 18:22, Ard Biesheuvel 写道:
>>> On Thu, 14 Apr 2022 at 11:54, Wupeng Ma <[email protected]> wrote:
>>>>
>>>> From: Ma Wupeng <[email protected]>
>>>>
>>>> Commit b05b9f5f9dcf ("x86, mirror: x86 enabling - find mirrored memory ranges")
>>>> introduced mirrored memory support for x86. This support rely on UEFI to
>>>> report mirrored memory address ranges. See UEFI 2.5 spec pages 157-158:
>>>>
>>>> http://www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf
>>>>
>>>> Memory mirroring is a technique used to separate memory into two separate
>>>> channels, usually on a memory device, like a server. In memory mirroring,
>>>> one channel is copied to another to create redundancy. This method makes
>>>> input/output (I/O) registers and memory appear with more than one address
>>>> range because the same physical byte is accessible at more than one
>>>> address. Using memory mirroring, higher memory reliability and a higher
>>>> level of memory consolidation are possible.
>>>>
>>>> Arm64 can support this too. So mirrored memory support is added to support
>>>> arm64.
>>>>
>>>> Efi_fake_mem is used for testing mirrored features and will not be used in
>>>> production environment. This test features can fake memory's attribute
>>>> values.
>>>>
>>>> The reason why efi_fake_mem support is put first is that memory's attribute
>>>> is reported by BIOS which is hard to simulate. With this support, any arm64
>>>> machines with efi support can easily test mirrored features.
>>>>
>>>> The main purpose of this patchset is to introduce mirrored support for
>>>> arm64 and we have already fixed the problems we had which is shown in
>>>> patch #5 to patch #7 and try to bring total isolation in patch #8 which
>>>> will disable mirror feature if kernelcore is not specified.
>>>>
>>>> In order to test this support in arm64:
>>>> - patch this patchset
>>>> - add efi_fake_mem=8G@0:0x10000 in kernel parameter to simulate mirrored
>>>> memroy between phy addr 0-8G.
>>>> - add kernelcore=mirror in kernel parameter
>>>> - start you kernel
>>>>
>>>
>>> As I explained before:
>>>
>>> - NAK to EFI fake_mem support on arm64
>>
>> fake_mem support on arm64 will be removed in subsequent version.
>>
>>> - NAK to the whole series until you come up with a proposal on how to
>>> locate the static kernel image itself into more reliable memory, as
>>> there is really no point to any of this otherwise.
>>
>> Sorry I am not familiar with this, as you metioned before,
>>
>> > you have to iterate over the memory map and look for regions with
>> > the desired attribute, and allocate those pages explicitly.
>>
>> Do you mean this is x86, commit c05cd79750fb
>> ("x86/boot/KASLR: Prefer mirrored memory regions for the kernel physical address").
>> I will do some research.
>>
>> > I'd prefer to implement this in the bootloader, and only add minimal
>> > logic to the stub to respect the placement of the kernel by the loader
>> > if the loader signals it to do so.
>>
>> Does this bootloader refer to grub and then add minimal logic to arm64-stub.c?
>>
>
> Any bootloader, yes.
>
>> What is the loader signal?
>
> A protocol installed onto the image handle, as I suggested before. I
> even cc'ed you on a patch that implements this.
Sorry to bother you.
I didn't receive any patches.
Could you share the link?
>
>> System exists mirrored memory reported by uefi?
>>
>
> What on earth is the point of any of this if the only use case being
> targeted is efi_fake_mem with arbitrary fake mirrored regions?
>
> So yes, unless there are systems that need this, I don't see a point
> in merging any of this
We do have mirrored memory reported by uefi and efi_fake_mem is added for easy testing
with qemu/hardware without update UEFI.
> .
On Tue, 19 Apr 2022 20:29:27 +0200 Ard Biesheuvel <[email protected]> wrote:
> > > --- a/mm/page_alloc.c
> > > +++ b/mm/page_alloc.c
> > > @@ -7870,7 +7870,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
> > >
> > > usable_startpfn = memblock_region_memory_base_pfn(r);
> > >
> > > - if (usable_startpfn < 0x100000) {
> > > + if (usable_startpfn < PHYS_PFN(SZ_4G)) {
> > > mem_below_4gb_not_mirrored = true;
> > > continue;
> > > }
> >
> > Regardless PFN value should never be encoded directly.
> >
> > Reviewed-by: Anshuman Khandual <[email protected]>
>
> Acked-by: Ard Biesheuvel <[email protected]>
>
> Andrew, can you please take this one through the -mm tree? The rest of
> the series needs a bit more work, but is an obvious fix and there is
> no point in holding it up.
Sure.
I'm not seeing any description of the runtime effects of this
shortcoming. I tentatively queued the fix for 5.18, without a
cc:stable for backporting. But that might not be the best decision?
On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
>
> From: Ma Wupeng <[email protected]>
>
> Now system image will perfer to be located to mirrored regions both KASLR
> on and off.
>
Hello Ma Wupeng,
I wonder if we could simplify this as follows:
- ignore the non-KASLR case for now, and rely on the bootloader to
load the image into mirrored memory if it exists;
- simplify the KASLR case to the below.
I think this is reasonable, because it means we take mirrored memory
into account when we decide to move the image anyway, but expect the
boot chain to take care of this if there is no need to move the image.
-------------8<------------------
--- a/drivers/firmware/efi/libstub/randomalloc.c
+++ b/drivers/firmware/efi/libstub/randomalloc.c
@@ -56,6 +56,7 @@ efi_status_t efi_random_alloc(unsigned long size,
unsigned long random_seed)
{
unsigned long map_size, desc_size, total_slots = 0, target_slot;
+ unsigned long total_mirrored_slots = 0;
unsigned long buff_size;
efi_status_t status;
efi_memory_desc_t *memory_map;
@@ -86,8 +87,14 @@ efi_status_t efi_random_alloc(unsigned long size,
slots = get_entry_num_slots(md, size, ilog2(align));
MD_NUM_SLOTS(md) = slots;
total_slots += slots;
+ if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
+ total_mirrored_slots += slots;
}
+ /* only consider mirrored slots for randomization if any exist */
+ if (total_mirrored_slots > 0)
+ total_slots = total_mirrored_slots;
+
/* find a random number between 0 and total_slots */
target_slot = (total_slots * (u64)(random_seed & U32_MAX)) >> 32;
@@ -107,6 +114,10 @@ efi_status_t efi_random_alloc(unsigned long size,
efi_physical_addr_t target;
unsigned long pages;
+ if (total_mirrored_slots > 0 &&
+ !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
+ continue;
+
if (target_slot >= MD_NUM_SLOTS(md)) {
target_slot -= MD_NUM_SLOTS(md);
continue;
在 2022/5/3 17:58, Ard Biesheuvel 写道:
> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
>>
>> From: Ma Wupeng <[email protected]>
>>
>> Now system image will perfer to be located to mirrored regions both KASLR
>> on and off.
>>
>
> Hello Ma Wupeng,
>
> I wonder if we could simplify this as follows:
> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
In grub, memory for static image is allocated via the following path:
grub_cmd_linux
kernel = grub_malloc(filelen)
kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
Can we get memory from mirrored region by the following steps:
1. get memory map by calling grub_efi_get_memory_map()
2. iter all memory map to find a suitable mirrored memory area
3. locate kernel image to this area
So, if kaslr is not enabled
- grub will load kernel into mirrored region
else
- arm64-stub.c will relocate kernel image to mirrored region
Is this feasible?
> - simplify the KASLR case to the below.
Yes, we can certainly do this. I will remove my code and use yours.
>
> I think this is reasonable, because it means we take mirrored memory
> into account when we decide to move the image anyway, but expect the
> boot chain to take care of this if there is no need to move the image.
>
> -------------8<------------------
> --- a/drivers/firmware/efi/libstub/randomalloc.c
> +++ b/drivers/firmware/efi/libstub/randomalloc.c
> @@ -56,6 +56,7 @@ efi_status_t efi_random_alloc(unsigned long size,
> unsigned long random_seed)
> {
> unsigned long map_size, desc_size, total_slots = 0, target_slot;
> + unsigned long total_mirrored_slots = 0;
> unsigned long buff_size;
> efi_status_t status;
> efi_memory_desc_t *memory_map;
> @@ -86,8 +87,14 @@ efi_status_t efi_random_alloc(unsigned long size,
> slots = get_entry_num_slots(md, size, ilog2(align));
> MD_NUM_SLOTS(md) = slots;
> total_slots += slots;
> + if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
> + total_mirrored_slots += slots;
> }
>
> + /* only consider mirrored slots for randomization if any exist */
> + if (total_mirrored_slots > 0)
> + total_slots = total_mirrored_slots;
> +
> /* find a random number between 0 and total_slots */
> target_slot = (total_slots * (u64)(random_seed & U32_MAX)) >> 32;
>
> @@ -107,6 +114,10 @@ efi_status_t efi_random_alloc(unsigned long size,
> efi_physical_addr_t target;
> unsigned long pages;
>
> + if (total_mirrored_slots > 0 &&
> + !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
> + continue;
> +
> if (target_slot >= MD_NUM_SLOTS(md)) {
> target_slot -= MD_NUM_SLOTS(md);
> continue;
> .
在 2022/5/7 17:28, mawupeng 写道:
>
>
> 在 2022/5/3 17:58, Ard Biesheuvel 写道:
>> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
>>>
>>> From: Ma Wupeng <[email protected]>
>>>
>>> Now system image will perfer to be located to mirrored regions both KASLR
>>> on and off.
>>>
>>
>> Hello Ma Wupeng,
>>
>> I wonder if we could simplify this as follows:
>> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
>
> In grub, memory for static image is allocated via the following path:
>
> grub_cmd_linux
> kernel = grub_malloc(filelen)
> kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
> grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
> grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
>
> Can we get memory from mirrored region by the following steps:
> 1. get memory map by calling grub_efi_get_memory_map()
> 2. iter all memory map to find a suitable mirrored memory area
> 3. locate kernel image to this area
>
> So, if kaslr is not enabled
> - grub will load kernel into mirrored region
> else
> - arm64-stub.c will relocate kernel image to mirrored region
>
> Is this feasible?
Is this a feasible proposal to relocate the static kernel image itself
into more reliable memory?
>
>> - simplify the KASLR case to the below.
>
> Yes, we can certainly do this. I will remove my code and use yours.
>
>>
>> I think this is reasonable, because it means we take mirrored memory
>> into account when we decide to move the image anyway, but expect the
>> boot chain to take care of this if there is no need to move the image.
>>
>> -------------8<------------------
>> --- a/drivers/firmware/efi/libstub/randomalloc.c
>> +++ b/drivers/firmware/efi/libstub/randomalloc.c
>> @@ -56,6 +56,7 @@ efi_status_t efi_random_alloc(unsigned long size,
>> unsigned long random_seed)
>> {
>> unsigned long map_size, desc_size, total_slots = 0, target_slot;
>> + unsigned long total_mirrored_slots = 0;
>> unsigned long buff_size;
>> efi_status_t status;
>> efi_memory_desc_t *memory_map;
>> @@ -86,8 +87,14 @@ efi_status_t efi_random_alloc(unsigned long size,
>> slots = get_entry_num_slots(md, size, ilog2(align));
>> MD_NUM_SLOTS(md) = slots;
>> total_slots += slots;
>> + if (md->attribute & EFI_MEMORY_MORE_RELIABLE)
>> + total_mirrored_slots += slots;
>> }
>>
>> + /* only consider mirrored slots for randomization if any exist */
>> + if (total_mirrored_slots > 0)
>> + total_slots = total_mirrored_slots;
>> +
>> /* find a random number between 0 and total_slots */
>> target_slot = (total_slots * (u64)(random_seed & U32_MAX)) >> 32;
>>
>> @@ -107,6 +114,10 @@ efi_status_t efi_random_alloc(unsigned long size,
>> efi_physical_addr_t target;
>> unsigned long pages;
>>
>> + if (total_mirrored_slots > 0 &&
>> + !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
>> + continue;
>> +
>> if (target_slot >= MD_NUM_SLOTS(md)) {
>> target_slot -= MD_NUM_SLOTS(md);
>> continue;
>> .
On Fri, 20 May 2022 at 08:52, Ard Biesheuvel <[email protected]> wrote:
>
> On Thu, 19 May 2022 at 13:09, mawupeng <[email protected]> wrote:
> >
> >
> >
> > 在 2022/5/7 17:28, mawupeng 写道:
> > >
> > >
> > > 在 2022/5/3 17:58, Ard Biesheuvel 写道:
> > >> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
> > >>>
> > >>> From: Ma Wupeng <[email protected]>
> > >>>
> > >>> Now system image will perfer to be located to mirrored regions both KASLR
> > >>> on and off.
> > >>>
> > >>
> > >> Hello Ma Wupeng,
> > >>
> > >> I wonder if we could simplify this as follows:
> > >> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
> > >
> > > In grub, memory for static image is allocated via the following path:
> > >
> > > grub_cmd_linux
> > > kernel = grub_malloc(filelen)
> > > kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
> > > grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
> > > grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
> > >
> > > Can we get memory from mirrored region by the following steps:
> > > 1. get memory map by calling grub_efi_get_memory_map()
> > > 2. iter all memory map to find a suitable mirrored memory area
> > > 3. locate kernel image to this area
> > >
> > > So, if kaslr is not enabled
> > > - grub will load kernel into mirrored region
> > > else
> > > - arm64-stub.c will relocate kernel image to mirrored region
> > >
> > > Is this feasible?
> >
> > Is this a feasible proposal to relocate the static kernel image itself
> > into more reliable memory?
> >
>
> I'm not sure, it all depends on the firmware.
>
> When GRUB calls LoadImage(), the firmware will reallocate the image
> and unpack it there. So it is really the firmware's job to ensure that
> the image is loaded into a suitable location.
>
> I have some code here that implements a EFI based decompressor, and
> which loads the kernel image into mirrored memory if it exists,
> without the need to move it again. It could trivially be modified to
> deal with non-randomized loads as well.
>
Code is here
https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=efi-decompressor-v2
在 2022/5/20 14:52, Ard Biesheuvel 写道:
> On Thu, 19 May 2022 at 13:09, mawupeng <[email protected]> wrote:
>>
>>
>>
>> 在 2022/5/7 17:28, mawupeng 写道:
>>>
>>>
>>> 在 2022/5/3 17:58, Ard Biesheuvel 写道:
>>>> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
>>>>>
>>>>> From: Ma Wupeng <[email protected]>
>>>>>
>>>>> Now system image will perfer to be located to mirrored regions both KASLR
>>>>> on and off.
>>>>>
>>>>
>>>> Hello Ma Wupeng,
>>>>
>>>> I wonder if we could simplify this as follows:
>>>> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
>>>
>>> In grub, memory for static image is allocated via the following path:
>>>
>>> grub_cmd_linux
>>> kernel = grub_malloc(filelen)
>>> kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
>>> grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
>>> grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
>>>
>>> Can we get memory from mirrored region by the following steps:
>>> 1. get memory map by calling grub_efi_get_memory_map()
>>> 2. iter all memory map to find a suitable mirrored memory area
>>> 3. locate kernel image to this area
>>>
>>> So, if kaslr is not enabled
>>> - grub will load kernel into mirrored region
>>> else
>>> - arm64-stub.c will relocate kernel image to mirrored region
>>>
>>> Is this feasible?
>>
>> Is this a feasible proposal to relocate the static kernel image itself
>> into more reliable memory?
>>
>
> I'm not sure, it all depends on the firmware.
>
> When GRUB calls LoadImage(), the firmware will reallocate the image
> and unpack it there. So it is really the firmware's job to ensure that
> the image is loaded into a suitable location.
>
> I have some code here that implements a EFI based decompressor, and
> which loads the kernel image into mirrored memory if it exists,
> without the need to move it again. It could trivially be modified to
> deal with non-randomized loads as well.
>
> But the bottom line is that UEFI should expose the ability to target
> mirrored memory, hacking around it like this is not a sustainable
> approach.
Since firmware is responsible for put kernel static image into mirrored
region and kernel is responsible for relocate this image into mirrored
region if kaslr is enabled. There is no conflict between these two.
Can we integrate the kernel part(introduce mirrored support to arm64) first?
> .
On Thu, 19 May 2022 at 13:09, mawupeng <[email protected]> wrote:
>
>
>
> 在 2022/5/7 17:28, mawupeng 写道:
> >
> >
> > 在 2022/5/3 17:58, Ard Biesheuvel 写道:
> >> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
> >>>
> >>> From: Ma Wupeng <[email protected]>
> >>>
> >>> Now system image will perfer to be located to mirrored regions both KASLR
> >>> on and off.
> >>>
> >>
> >> Hello Ma Wupeng,
> >>
> >> I wonder if we could simplify this as follows:
> >> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
> >
> > In grub, memory for static image is allocated via the following path:
> >
> > grub_cmd_linux
> > kernel = grub_malloc(filelen)
> > kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
> > grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
> > grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
> >
> > Can we get memory from mirrored region by the following steps:
> > 1. get memory map by calling grub_efi_get_memory_map()
> > 2. iter all memory map to find a suitable mirrored memory area
> > 3. locate kernel image to this area
> >
> > So, if kaslr is not enabled
> > - grub will load kernel into mirrored region
> > else
> > - arm64-stub.c will relocate kernel image to mirrored region
> >
> > Is this feasible?
>
> Is this a feasible proposal to relocate the static kernel image itself
> into more reliable memory?
>
I'm not sure, it all depends on the firmware.
When GRUB calls LoadImage(), the firmware will reallocate the image
and unpack it there. So it is really the firmware's job to ensure that
the image is loaded into a suitable location.
I have some code here that implements a EFI based decompressor, and
which loads the kernel image into mirrored memory if it exists,
without the need to move it again. It could trivially be modified to
deal with non-randomized loads as well.
But the bottom line is that UEFI should expose the ability to target
mirrored memory, hacking around it like this is not a sustainable
approach.
On Mon, 23 May 2022 at 03:18, mawupeng <[email protected]> wrote:
>
>
>
> 在 2022/5/20 14:52, Ard Biesheuvel 写道:
> > On Thu, 19 May 2022 at 13:09, mawupeng <[email protected]> wrote:
> >>
> >>
> >>
> >> 在 2022/5/7 17:28, mawupeng 写道:
> >>>
> >>>
> >>> 在 2022/5/3 17:58, Ard Biesheuvel 写道:
> >>>> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
> >>>>>
> >>>>> From: Ma Wupeng <[email protected]>
> >>>>>
> >>>>> Now system image will perfer to be located to mirrored regions both KASLR
> >>>>> on and off.
> >>>>>
> >>>>
> >>>> Hello Ma Wupeng,
> >>>>
> >>>> I wonder if we could simplify this as follows:
> >>>> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
> >>>
> >>> In grub, memory for static image is allocated via the following path:
> >>>
> >>> grub_cmd_linux
> >>> kernel = grub_malloc(filelen)
> >>> kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
> >>> grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
> >>> grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
> >>>
> >>> Can we get memory from mirrored region by the following steps:
> >>> 1. get memory map by calling grub_efi_get_memory_map()
> >>> 2. iter all memory map to find a suitable mirrored memory area
> >>> 3. locate kernel image to this area
> >>>
> >>> So, if kaslr is not enabled
> >>> - grub will load kernel into mirrored region
> >>> else
> >>> - arm64-stub.c will relocate kernel image to mirrored region
> >>>
> >>> Is this feasible?
> >>
> >> Is this a feasible proposal to relocate the static kernel image itself
> >> into more reliable memory?
> >>
> >
> > I'm not sure, it all depends on the firmware.
> >
> > When GRUB calls LoadImage(), the firmware will reallocate the image
> > and unpack it there. So it is really the firmware's job to ensure that
> > the image is loaded into a suitable location.
> >
> > I have some code here that implements a EFI based decompressor, and
> > which loads the kernel image into mirrored memory if it exists,
> > without the need to move it again. It could trivially be modified to
> > deal with non-randomized loads as well.
> >
> > But the bottom line is that UEFI should expose the ability to target
> > mirrored memory, hacking around it like this is not a sustainable
> > approach.
>
> Since firmware is responsible for put kernel static image into mirrored
> region and kernel is responsible for relocate this image into mirrored
> region if kaslr is enabled. There is no conflict between these two.
>
> Can we integrate the kernel part(introduce mirrored support to arm64) first?
>
Yes. If you drop the changes related to fake memmap and rebase, please
resend them after -rc1 is released.
在 2022/5/23 22:41, Ard Biesheuvel 写道:
> On Mon, 23 May 2022 at 03:18, mawupeng <[email protected]> wrote:
>>
>>
>>
>> 在 2022/5/20 14:52, Ard Biesheuvel 写道:
>>> On Thu, 19 May 2022 at 13:09, mawupeng <[email protected]> wrote:
>>>>
>>>>
>>>>
>>>> 在 2022/5/7 17:28, mawupeng 写道:
>>>>>
>>>>>
>>>>> 在 2022/5/3 17:58, Ard Biesheuvel 写道:
>>>>>> On Tue, 19 Apr 2022 at 08:43, Wupeng Ma <[email protected]> wrote:
>>>>>>>
>>>>>>> From: Ma Wupeng <[email protected]>
>>>>>>>
>>>>>>> Now system image will perfer to be located to mirrored regions both KASLR
>>>>>>> on and off.
>>>>>>>
>>>>>>
>>>>>> Hello Ma Wupeng,
>>>>>>
>>>>>> I wonder if we could simplify this as follows:
>>>>>> - ignore the non-KASLR case for now, and rely on the bootloader > load the image into mirrored memory if it exists;
>>>>>
>>>>> In grub, memory for static image is allocated via the following path:
>>>>>
>>>>> grub_cmd_linux
>>>>> kernel = grub_malloc(filelen)
>>>>> kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages)
>>>>> grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size))
>>>>> grub_loader_set (grub_linux_boot, grub_linux_unload, 0)
>>>>>
>>>>> Can we get memory from mirrored region by the following steps:
>>>>> 1. get memory map by calling grub_efi_get_memory_map()
>>>>> 2. iter all memory map to find a suitable mirrored memory area
>>>>> 3. locate kernel image to this area
>>>>>
>>>>> So, if kaslr is not enabled
>>>>> - grub will load kernel into mirrored region
>>>>> else
>>>>> - arm64-stub.c will relocate kernel image to mirrored region
>>>>>
>>>>> Is this feasible?
>>>>
>>>> Is this a feasible proposal to relocate the static kernel image itself
>>>> into more reliable memory?
>>>>
>>>
>>> I'm not sure, it all depends on the firmware.
>>>
>>> When GRUB calls LoadImage(), the firmware will reallocate the image
>>> and unpack it there. So it is really the firmware's job to ensure that
>>> the image is loaded into a suitable location.
>>>
>>> I have some code here that implements a EFI based decompressor, and
>>> which loads the kernel image into mirrored memory if it exists,
>>> without the need to move it again. It could trivially be modified to
>>> deal with non-randomized loads as well.
>>>
>>> But the bottom line is that UEFI should expose the ability to target
>>> mirrored memory, hacking around it like this is not a sustainable
>>> approach.
>>
>> Since firmware is responsible for put kernel static image into mirrored
>> region and kernel is responsible for relocate this image into mirrored
>> region if kaslr is enabled. There is no conflict between these two.
>>
>> Can we integrate the kernel part(introduce mirrored support to arm64) first?
>>
>
> Yes. If you drop the changes related to fake memmap and rebase, please
> resend them after -rc1 is released.
Ok, I will drop the changes related to fake memmap and rebase and then
resend them after -rc1 is released.
Thanks for reviewing.
> .