aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Rapoport <rppt@linux.ibm.com>2022-02-15 09:03:15 +0200
committerMike Rapoport <rppt@linux.ibm.com>2022-02-15 09:04:46 +0200
commitb7a4baac6a2866224710f92d96fdf2ed5227e392 (patch)
treedf0784424871b1d39d36a89cb4845a2cfd23b85d
parent0688376261c29bf8452c5c77f8bc6fa9a4252bf5 (diff)
downloadlinux-x86/e820-update-range.tar.gz
x86/e820: implement e820__range_remove() using __e820__ranage_update()x86/e820-update-range
Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
-rw-r--r--arch/x86/include/asm/e820/types.h6
-rw-r--r--arch/x86/kernel/e820.c73
2 files changed, 21 insertions, 58 deletions
diff --git a/arch/x86/include/asm/e820/types.h b/arch/x86/include/asm/e820/types.h
index 314f75d886d08a..85c4b3276c90e3 100644
--- a/arch/x86/include/asm/e820/types.h
+++ b/arch/x86/include/asm/e820/types.h
@@ -8,6 +8,12 @@
* These are the E820 types known to the kernel:
*/
enum e820_type {
+ /*
+ * Special value that indicates that a range must be removed during
+ * updates of e820 table
+ */
+ E820_TYPE_NONE = 0,
+
E820_TYPE_RAM = 1,
E820_TYPE_RESERVED = 2,
E820_TYPE_ACPI = 3,
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index e3594690466b59..f431d7bbd737ac 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -187,6 +187,7 @@ void __init e820__range_add(u64 start, u64 size, enum e820_type type)
static void __init e820_print_type(enum e820_type type)
{
switch (type) {
+ case E820_TYPE_NONE: pr_cont("none"); break;
case E820_TYPE_RAM: /* Fall through: */
case E820_TYPE_RESERVED_KERN: pr_cont("usable"); break;
case E820_TYPE_RESERVED: pr_cont("reserved"); break;
@@ -462,6 +463,7 @@ static int __init append_e820_table(struct boot_e820_entry *entries, u32 nr_entr
struct e820_update_params {
enum e820_type old_type;
enum e820_type new_type;
+ int check_type;
};
static u64 __init
@@ -469,6 +471,7 @@ __e820__range_update(struct e820_table *table, u64 start, u64 size, struct e820_
{
enum e820_type old_type = params->old_type;
enum e820_type new_type = params->new_type;
+ int check_type = params->check_type;
u64 end;
unsigned int i;
@@ -481,6 +484,7 @@ __e820__range_update(struct e820_table *table, u64 start, u64 size, struct e820_
end = start + size;
printk(KERN_DEBUG "e820: update [mem %#010Lx-%#010Lx] ", start, end - 1);
+
e820_print_type(old_type);
pr_cont(" ==> ");
e820_print_type(new_type);
@@ -491,7 +495,7 @@ __e820__range_update(struct e820_table *table, u64 start, u64 size, struct e820_
u64 final_start, final_end;
u64 entry_end;
- if (entry->type != old_type)
+ if (check_type && entry->type != old_type)
continue;
entry_end = entry->addr + entry->size;
@@ -500,12 +504,15 @@ __e820__range_update(struct e820_table *table, u64 start, u64 size, struct e820_
if (entry->addr >= start && entry_end <= end) {
entry->type = new_type;
real_updated_size += entry->size;
+ if (new_type == E820_TYPE_NONE)
+ memset(entry, 0, sizeof(*entry));
continue;
}
/* New range is completely covered? */
if (entry->addr < start && entry_end > end) {
- __e820__range_add(table, start, size, new_type);
+ if (new_type != E820_TYPE_NONE)
+ __e820__range_add(table, start, size, new_type);
__e820__range_add(table, end, entry_end - end, entry->type);
entry->size = start - entry->addr;
real_updated_size += size;
@@ -558,63 +565,13 @@ static u64 __init e820__range_update_kexec(u64 start, u64 size, enum e820_type o
/* Remove a range of memory from the E820 table: */
u64 __init e820__range_remove(u64 start, u64 size, enum e820_type old_type, bool check_type)
{
- int i;
- u64 end;
- u64 real_removed_size = 0;
-
- if (size > (ULLONG_MAX - start))
- size = ULLONG_MAX - start;
-
- end = start + size;
- printk(KERN_DEBUG "e820: remove [mem %#010Lx-%#010Lx] ", start, end - 1);
- if (check_type)
- e820_print_type(old_type);
- pr_cont("\n");
-
- for (i = 0; i < e820_table->nr_entries; i++) {
- struct e820_entry *entry = &e820_table->entries[i];
- u64 final_start, final_end;
- u64 entry_end;
-
- if (check_type && entry->type != old_type)
- continue;
-
- entry_end = entry->addr + entry->size;
-
- /* Completely covered? */
- if (entry->addr >= start && entry_end <= end) {
- real_removed_size += entry->size;
- memset(entry, 0, sizeof(*entry));
- continue;
- }
-
- /* Is the new range completely covered? */
- if (entry->addr < start && entry_end > end) {
- e820__range_add(end, entry_end - end, entry->type);
- entry->size = start - entry->addr;
- real_removed_size += size;
- continue;
- }
-
- /* Partially covered: */
- final_start = max(start, entry->addr);
- final_end = min(end, entry_end);
- if (final_start >= final_end)
- continue;
-
- real_removed_size += final_end - final_start;
-
- /*
- * Left range could be head or tail, so need to update
- * the size first:
- */
- entry->size -= final_end - final_start;
- if (entry->addr < final_start)
- continue;
+ struct e820_update_params params = {
+ .old_type = old_type,
+ .new_type = E820_TYPE_NONE,
+ .check_type = check_type,
+ };
- entry->addr = final_end;
- }
- return real_removed_size;
+ return __e820__range_update(e820_table, start, size, &params);
}
void __init e820__update_table_print(void)