[PATCH RFC V2 1/2] arm64: Add enable/disable d-cache support for purgatory
Pratyush Anand
panand at redhat.com
Tue Jan 12 01:53:42 PST 2016
Hi Akashi,
Thanks for your review.
On 12/01/2016:05:34:41 PM, AKASHI Takahiro wrote:
> >+ default:
> >+ return 32;
>
> AA64MMFR0_PRANGE_32, instead of 'default', should explicitly be used here
> as it is defined as 0x0 in ARM ARM.
OK.
>
> >+static void init_page_table(void)
> >+{
> >+ inval_cache_range((uint64_t)page_table,
> >+ (uint64_t)page_table + PAGE_TABLE_SIZE);
> >+ memset(page_table, 0, PAGE_TABLE_SIZE);
>
> why invalidate first?
Humm..may be you are right. It was copied from arch/arm64/kernel/head.S.
http://lxr.free-electrons.com/source/arch/arm64/kernel/head.S#L322
>
> >+ */
> >+static void create_identity_mapping(uint64_t start, uint64_t end,
> >+ uint64_t flags)
> >+{
> >+ uint32_t sec_shift, pgdir_shift, sec_mask;
> >+ uint64_t desc, s1, e1, s2, e2;
> >+ uint64_t *table2;
> >+
> >+ s1 = start;
> >+ e1 = end;
> >+
> >+ sec_shift = get_section_shift();
> >+ if (pgtable_level == 1) {
> >+ s1 >>= sec_shift;
> >+ e1 >>= sec_shift;
> >+ do {
> >+ desc = s1 << sec_shift;
> >+ desc |= flags;
> >+ page_table[s1] = desc;
> >+ s1++;
> >+ } while (s1 <= e1);
>
> To be precise, this loop creates an unnecessary entry
> if 'end' is exclusive. Pls think about the case that end is
> on sector boundary. Maybe,
> e1 = (e1 - 1) >> sec_shift
Correct.
>
> >+ } else {
> >+ pgdir_shift = get_pgdir_shift();
> >+ sec_mask = get_section_mask();
> >+ s1 >>= pgdir_shift;
> >+ e1 >>= pgdir_shift;
> >+ do {
> >+ /*
> >+ * If there is no table entry then write a new
> >+ * entry else, use old entry
> >+ */
> >+ if (!page_table[s1]) {
>
> s1 can be larger than 0, 1 or 2 if ram is located at much higher address
> than the first (three) sector(s).
Yes, that can most likely be, but code will take care.
>From page_table[0] to page_table[MAX_PAGE_SIZE / sizeof(uint64_t)] will have entries
for 1st table.
we can have at max three tables.
table1 points to &page_table[0]
table2 points to &page_table[ MAX_PAGE_SIZE / sizeof(uint64_t)]
table3 points to &page_table[ 2 * MAX_PAGE_SIZE / sizeof(uint64_t)]
each table can contain number of entries = MAX_PAGE_SIZE / sizeof(uint64_t), so
if s1 > 3, it should work fine.
>
> >+static void enable_mmu_dcache(void)
> >+{
> >+ uint64_t tcr_flags = TCR_FLAGS | TCR_T0SZ(va_bits);
> >+
> >+ switch(page_shift) {
> >+ case 16:
> >+ tcr_flags |= TCR_TG0_64K;
> >+ break;
> >+ case 12:
> >+ tcr_flags |= TCR_TG0_4K;
> >+ break;
> >+ default:
> >+ printf("page shift not supported\n");
> >+ return;
> >+ }
> >+ /*
> >+ * Since the page tables have been populated with non-cacheable
> >+ * accesses (MMU disabled), invalidate the idmap page
> >+ * tables again to remove any speculatively loaded cache lines.
> >+ */
> >+ inval_cache_range((uint64_t)page_table,
> >+ (uint64_t)page_table + PAGE_TABLE_SIZE);
> >+
> >+ switch(get_current_el()) {
> >+ case 3:
>
> Linux kernel should be started only in EL2 or non-secure EL1.
> why should we take care of el3?
I was not sure about it, so kept it. OK.. Will remove in next version.
>
> >+void disable_dcache(uint64_t ram_start, uint64_t ram_end)
> >+{
> >+ switch(get_current_el()) {
> >+ case 3:
> >+ reset_sctlr_el3();
> >+ break;
>
> ditto
OK.
>
> >+#define ID_AA64MMFR0_PARANGE_40 0x2
> >+#define ID_AA64MMFR0_PARANGE_36 0x1
> >+#define ID_AA64MMFR0_PARANGE_32 0x0
> >+
> >+#define TCR_TG0_64K (1UL << 14)
> >+#define TCR_TG0_4K (0UL << 14)
> >+#define TCR_SHARED_NONE (0UL << 12)
> >+#define TCR_ORGN_WBWA (1UL << 10)
> >+#define TCR_IRGN_WBWA (1UL << 8)
> >+#define TCR_IPS_EL1_SHIFT 32
> >+#define TCR_IPS_EL2_SHIFT 16
> >+#define TCR_IPS_EL3_SHIFT 16
>
> TCR_PS_EL[23]_SHIFT?
OK :-) , Did not noticed it earlier.
~Pratyush
More information about the kexec
mailing list