Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9b5ad54 authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

s390/mm: tag normal pages vs pages used in page tables



The ESSA instruction has a new option that allows to tag pages that
are not used as a page table. Without the tag the hypervisor has to
assume that any guest page could be used in a page table inside the
guest. This forces the hypervisor to flush all guest TLB entries
whenever a host page table entry is invalidated. With the tag
the host can skip the TLB flush if the page is tagged as normal page.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 520eccdf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#define ESSA_SET_POT_VOLATILE		4
#define ESSA_SET_STABLE_RESIDENT	5
#define ESSA_SET_STABLE_IF_RESIDENT	6
#define ESSA_SET_STABLE_NODAT		7

#define ESSA_MAX	ESSA_SET_STABLE_IF_RESIDENT

+3 −0
Original line number Diff line number Diff line
@@ -133,6 +133,9 @@ static inline int page_reset_referenced(unsigned long addr)
struct page;
void arch_free_page(struct page *page, int order);
void arch_alloc_page(struct page *page, int order);
void arch_set_page_dat(struct page *page, int order);
void arch_set_page_nodat(struct page *page, int order);
int arch_test_page_nodat(struct page *page);
void arch_set_page_states(int make_stable);

static inline int devmem_is_allowed(unsigned long pfn)
+2 −1
Original line number Diff line number Diff line
@@ -106,7 +106,8 @@ extern void pfault_fini(void);

void report_user_fault(struct pt_regs *regs, long signr, int is_mm_fault);

extern void cmma_init(void);
void cmma_init(void);
void cmma_init_nodat(void);

extern void (*_machine_restart)(char *command);
extern void (*_machine_halt)(void);
+19 −5
Original line number Diff line number Diff line
@@ -98,10 +98,16 @@ int page_key_alloc(unsigned long pages)
 */
void page_key_read(unsigned long *pfn)
{
	struct page *page;
	unsigned long addr;
	unsigned char key;

	addr = (unsigned long) page_address(pfn_to_page(*pfn));
	*(unsigned char *) pfn = (unsigned char) page_get_storage_key(addr);
	page = pfn_to_page(*pfn);
	addr = (unsigned long) page_address(page);
	key = (unsigned char) page_get_storage_key(addr) & 0x7f;
	if (arch_test_page_nodat(page))
		key |= 0x80;
	*(unsigned char *) pfn = key;
}

/*
@@ -126,8 +132,16 @@ void page_key_memorize(unsigned long *pfn)
 */
void page_key_write(void *address)
{
	page_set_storage_key((unsigned long) address,
			     page_key_rp->data[page_key_rx], 0);
	struct page *page;
	unsigned char key;

	key = page_key_rp->data[page_key_rx];
	page_set_storage_key((unsigned long) address, key & 0x7f, 0);
	page = virt_to_page(address);
	if (key & 0x80)
		arch_set_page_nodat(page, 0);
	else
		arch_set_page_dat(page, 0);
	if (++page_key_rx >= PAGE_KEY_DATA_SIZE)
		return;
	page_key_rp = page_key_rp->next;
+2 −0
Original line number Diff line number Diff line
@@ -157,6 +157,8 @@ int vdso_alloc_per_cpu(struct lowcore *lowcore)
	page_frame = get_zeroed_page(GFP_KERNEL);
	if (!segment_table || !page_table || !page_frame)
		goto out;
	arch_set_page_dat(virt_to_page(segment_table), SEGMENT_ORDER);
	arch_set_page_dat(virt_to_page(page_table), 0);

	/* Initialize per-cpu vdso data page */
	vd = (struct vdso_per_cpu_data *) page_frame;
Loading