Commit e0e0a87b authored by Alexander Gordeev's avatar Alexander Gordeev Committed by Heiko Carstens

s390/boot: allow setup of different virtual address types

Currently the decompressor sets up only identity mapping.
Allow adding more address range types as a prerequisite
for allocation of kernel fixed mappings.
Signed-off-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 07493a9c
...@@ -17,6 +17,10 @@ unsigned long __bootdata(pgalloc_pos); ...@@ -17,6 +17,10 @@ unsigned long __bootdata(pgalloc_pos);
unsigned long __bootdata(pgalloc_end); unsigned long __bootdata(pgalloc_end);
unsigned long __bootdata(pgalloc_low); unsigned long __bootdata(pgalloc_low);
enum populate_mode {
POPULATE_ONE2ONE,
};
static void boot_check_oom(void) static void boot_check_oom(void)
{ {
if (pgalloc_pos < pgalloc_low) if (pgalloc_pos < pgalloc_low)
...@@ -81,6 +85,16 @@ static pte_t *boot_pte_alloc(void) ...@@ -81,6 +85,16 @@ static pte_t *boot_pte_alloc(void)
return pte; return pte;
} }
static unsigned long _pa(unsigned long addr, enum populate_mode mode)
{
switch (mode) {
case POPULATE_ONE2ONE:
return addr;
default:
return -1;
}
}
static bool can_large_pud(pud_t *pu_dir, unsigned long addr, unsigned long end) static bool can_large_pud(pud_t *pu_dir, unsigned long addr, unsigned long end)
{ {
return machine.has_edat2 && return machine.has_edat2 &&
...@@ -93,7 +107,8 @@ static bool can_large_pmd(pmd_t *pm_dir, unsigned long addr, unsigned long end) ...@@ -93,7 +107,8 @@ static bool can_large_pmd(pmd_t *pm_dir, unsigned long addr, unsigned long end)
IS_ALIGNED(addr, PMD_SIZE) && (end - addr) >= PMD_SIZE; IS_ALIGNED(addr, PMD_SIZE) && (end - addr) >= PMD_SIZE;
} }
static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end) static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long end,
enum populate_mode mode)
{ {
unsigned long next; unsigned long next;
pte_t *pte, entry; pte_t *pte, entry;
...@@ -101,14 +116,15 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e ...@@ -101,14 +116,15 @@ static void pgtable_pte_populate(pmd_t *pmd, unsigned long addr, unsigned long e
pte = pte_offset_kernel(pmd, addr); pte = pte_offset_kernel(pmd, addr);
for (; addr < end; addr += PAGE_SIZE, pte++) { for (; addr < end; addr += PAGE_SIZE, pte++) {
if (pte_none(*pte)) { if (pte_none(*pte)) {
entry = __pte(__pa(addr)); entry = __pte(_pa(addr, mode));
entry = set_pte_bit(entry, PAGE_KERNEL_EXEC); entry = set_pte_bit(entry, PAGE_KERNEL_EXEC);
set_pte(pte, entry); set_pte(pte, entry);
} }
} }
} }
static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long end) static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long end,
enum populate_mode mode)
{ {
unsigned long next; unsigned long next;
pmd_t *pmd, entry; pmd_t *pmd, entry;
...@@ -119,7 +135,7 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e ...@@ -119,7 +135,7 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e
next = pmd_addr_end(addr, end); next = pmd_addr_end(addr, end);
if (pmd_none(*pmd)) { if (pmd_none(*pmd)) {
if (can_large_pmd(pmd, addr, next)) { if (can_large_pmd(pmd, addr, next)) {
entry = __pmd(__pa(addr)); entry = __pmd(_pa(addr, mode));
entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC); entry = set_pmd_bit(entry, SEGMENT_KERNEL_EXEC);
set_pmd(pmd, entry); set_pmd(pmd, entry);
continue; continue;
...@@ -129,11 +145,12 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e ...@@ -129,11 +145,12 @@ static void pgtable_pmd_populate(pud_t *pud, unsigned long addr, unsigned long e
} else if (pmd_large(*pmd)) { } else if (pmd_large(*pmd)) {
continue; continue;
} }
pgtable_pte_populate(pmd, addr, next); pgtable_pte_populate(pmd, addr, next, mode);
} }
} }
static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long end) static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long end,
enum populate_mode mode)
{ {
unsigned long next; unsigned long next;
pud_t *pud, entry; pud_t *pud, entry;
...@@ -144,7 +161,7 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e ...@@ -144,7 +161,7 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e
next = pud_addr_end(addr, end); next = pud_addr_end(addr, end);
if (pud_none(*pud)) { if (pud_none(*pud)) {
if (can_large_pud(pud, addr, next)) { if (can_large_pud(pud, addr, next)) {
entry = __pud(__pa(addr)); entry = __pud(_pa(addr, mode));
entry = set_pud_bit(entry, REGION3_KERNEL_EXEC); entry = set_pud_bit(entry, REGION3_KERNEL_EXEC);
set_pud(pud, entry); set_pud(pud, entry);
continue; continue;
...@@ -154,11 +171,12 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e ...@@ -154,11 +171,12 @@ static void pgtable_pud_populate(p4d_t *p4d, unsigned long addr, unsigned long e
} else if (pud_large(*pud)) { } else if (pud_large(*pud)) {
continue; continue;
} }
pgtable_pmd_populate(pud, addr, next); pgtable_pmd_populate(pud, addr, next, mode);
} }
} }
static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long end) static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long end,
enum populate_mode mode)
{ {
unsigned long next; unsigned long next;
p4d_t *p4d; p4d_t *p4d;
...@@ -171,11 +189,11 @@ static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long e ...@@ -171,11 +189,11 @@ static void pgtable_p4d_populate(pgd_t *pgd, unsigned long addr, unsigned long e
pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY); pud = boot_crst_alloc(_REGION3_ENTRY_EMPTY);
p4d_populate(&init_mm, p4d, pud); p4d_populate(&init_mm, p4d, pud);
} }
pgtable_pud_populate(p4d, addr, next); pgtable_pud_populate(p4d, addr, next, mode);
} }
} }
static void pgtable_populate(unsigned long addr, unsigned long end) static void pgtable_populate(unsigned long addr, unsigned long end, enum populate_mode mode)
{ {
unsigned long next; unsigned long next;
pgd_t *pgd; pgd_t *pgd;
...@@ -188,7 +206,7 @@ static void pgtable_populate(unsigned long addr, unsigned long end) ...@@ -188,7 +206,7 @@ static void pgtable_populate(unsigned long addr, unsigned long end)
p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY); p4d = boot_crst_alloc(_REGION2_ENTRY_EMPTY);
pgd_populate(&init_mm, pgd, p4d); pgd_populate(&init_mm, pgd, p4d);
} }
pgtable_p4d_populate(pgd, addr, next); pgtable_p4d_populate(pgd, addr, next, mode);
} }
} }
...@@ -208,7 +226,7 @@ static void pgtable_populate_end(void) ...@@ -208,7 +226,7 @@ static void pgtable_populate_end(void)
do { do {
pgalloc_pos_prev = pgalloc_pos; pgalloc_pos_prev = pgalloc_pos;
pgtable_populate(pgalloc_pos, pgalloc_end_curr); pgtable_populate(pgalloc_pos, pgalloc_end_curr, POPULATE_ONE2ONE);
pgalloc_end_curr = pgalloc_pos_prev; pgalloc_end_curr = pgalloc_pos_prev;
} while (pgalloc_pos < pgalloc_pos_prev); } while (pgalloc_pos < pgalloc_pos_prev);
} }
...@@ -239,8 +257,8 @@ void setup_vmem(unsigned long online_end, unsigned long asce_limit) ...@@ -239,8 +257,8 @@ void setup_vmem(unsigned long online_end, unsigned long asce_limit)
* of pgalloc_pos finalized with a call to pgtable_populate_end(). * of pgalloc_pos finalized with a call to pgtable_populate_end().
*/ */
pgtable_populate_begin(online_end); pgtable_populate_begin(online_end);
pgtable_populate(0, sizeof(struct lowcore)); pgtable_populate(0, sizeof(struct lowcore), POPULATE_ONE2ONE);
pgtable_populate(0, online_end); pgtable_populate(0, online_end, POPULATE_ONE2ONE);
pgtable_populate_end(); pgtable_populate_end();
S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits; S390_lowcore.kernel_asce = swapper_pg_dir | asce_bits;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment