[PATCH V3 3/3] arm64: Extend early page table code to allow for larger kernels
Steve Capper
steve.capper at arm.com
Wed Jan 3 09:11:11 PST 2018
On Wed, Jan 03, 2018 at 04:38:47PM +0000, Ard Biesheuvel wrote:
> On 3 January 2018 at 16:20, Steve Capper <steve.capper at arm.com> wrote:
> > On Tue, Jan 02, 2018 at 10:01:29PM +0000, Ard Biesheuvel wrote:
> >> Hi Steve,
> >
> > Hi Ard,
> >
> >>
> >> On 2 January 2018 at 15:12, Steve Capper <steve.capper at arm.com> wrote:
> >> > Currently the early assembler page table code assumes that precisely
> >> > 1xpgd, 1xpud, 1xpmd are sufficient to represent the early kernel text
> >> > mappings.
> >> >
> >> > Unfortunately this is rarely the case when running with a 16KB granule,
> >> > and we also run into limits with 4KB granule when building much larger
> >> > kernels.
> >> >
> >> > This patch re-writes the early page table logic to compute indices of
> >> > mappings for each level of page table, and if multiple indices are
> >> > required, the next-level page table is scaled up accordingly.
> >> >
> >> > Also the required size of the swapper_pg_dir is computed at link time
> >> > to cover the mapping [KIMAGE_ADDR + VOFFSET, _end]. When KASLR is
> >> > enabled, an extra page is set aside for each level that may require extra
> >> > entries at runtime.
> >> >
> >> > Signed-off-by: Steve Capper <steve.capper at arm.com>
> >> >
> >> > ---
> >> > Changed in V3:
> >> > Corrected KASLR computation
> >> > Rebased against arm64/for-next/core, particularly Kristina's 52-bit
> >> > PA series.
> >> > ---
> >> > arch/arm64/include/asm/kernel-pgtable.h | 47 ++++++++++-
> >> > arch/arm64/include/asm/pgtable.h | 1 +
> >> > arch/arm64/kernel/head.S | 145 +++++++++++++++++++++++---------
> >> > arch/arm64/kernel/vmlinux.lds.S | 1 +
> >> > arch/arm64/mm/mmu.c | 3 +-
> >> > 5 files changed, 157 insertions(+), 40 deletions(-)
> >> >
> >> > diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
> >> > index 77a27af01371..82386e860dd2 100644
> >> > --- a/arch/arm64/include/asm/kernel-pgtable.h
> >> > +++ b/arch/arm64/include/asm/kernel-pgtable.h
[...]
> >> > - * Preserves: tbl, flags
> >> > - * Corrupts: phys, start, end, tmp, pstate
> >> > + * Preserves: vstart, vend, shift, ptrs
> >> > + * Returns: istart, iend, count
> >> > */
> >> > - .macro create_block_map, tbl, flags, phys, start, end, tmp
> >> > - lsr \start, \start, #SWAPPER_BLOCK_SHIFT
> >> > - and \start, \start, #PTRS_PER_PTE - 1 // table index
> >> > - bic \phys, \phys, #SWAPPER_BLOCK_SIZE - 1
> >> > - lsr \end, \end, #SWAPPER_BLOCK_SHIFT
> >> > - and \end, \end, #PTRS_PER_PTE - 1 // table end index
> >> > -9999: phys_to_pte \phys, \tmp
> >> > - orr \tmp, \tmp, \flags // table entry
> >> > - str \tmp, [\tbl, \start, lsl #3] // store the entry
> >> > - add \start, \start, #1 // next entry
> >> > - add \phys, \phys, #SWAPPER_BLOCK_SIZE // next block
> >> > - cmp \start, \end
> >> > - b.ls 9999b
> >> > + .macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count
> >> > + lsr \iend, \vend, \shift
> >> > + mov \istart, \ptrs
> >> > + sub \istart, \istart, #1
> >> > + and \iend, \iend, \istart // iend = (vend >> shift) & (ptrs - 1)
> >> > + mov \istart, \ptrs
> >> > + sub \count, \count, #1
> >> > + mul \istart, \istart, \count
> >> > + add \iend, \iend, \istart // iend += (count - 1) * ptrs
> >> > + // our entries span multiple tables
> >> > +
> >> > + lsr \istart, \vstart, \shift
> >> > + mov \count, \ptrs
> >> > + sub \count, \count, #1
> >> > + and \istart, \istart, \count
> >> > +
> >> > + sub \count, \iend, \istart
> >> > + add \count, \count, #1
> >> > + .endm
> >> > +
> >>
> >> You can simplify this macro by using an immediate for \ptrs. Please
> >> see the diff below [whitespace mangling courtesy of Gmail]
> >
> > Thanks, I like the simplification a lot. For 52-bit kernel VAs though, I
> > will need a variable PTRS_PER_PGD at compile time.
> >
> > For 52-bit kernel PAs one can just use the maximum number of ptrs available.
> > For a 48-bit PA the leading address bits will always be zero, thus we
> > will derive the same PGD indices from both 48 and 52 bit PTRS_PER_PGD.
> >
> > For kernel VAs, because the leading address bits are one, we need to use a
> > PTRS_PER_PGD corresponding to the VA size.
> >
>
> OK, so you are saying you shouldn't mask off too many bits, right? In
> any case, I suppose you can just use the same trick as I used for
> .Lidmap_ptrs_per_pgd, i.e., use .set to assign the correct value and
> pass that into the macro.
>
Yeah, that's right, one needs to mask off the correct number of bits.
If I've understood correctly, we choose which .set to use at compile
time rather than runtime though?
The problem I have is the number of PGDs is only known precisely at boot
time when one has a kernel that switches between 48/52 bit VAs. That's
why I had the number of PGDs in a register.
Cheers,
--
Steve
More information about the linux-arm-kernel
mailing list