arch/s390/mm/pfault.c

Source file repositories/reference/linux-study-clean/arch/s390/mm/pfault.c

File Facts

System
Linux kernel
Corpus path
arch/s390/mm/pfault.c
Extension
.c
Size
6567 bytes
Lines
249
Domain
Architecture Layer
Bucket
arch/s390
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct pfault_refbk {
	u16 refdiagc;
	u16 reffcode;
	u16 refdwlen;
	u16 refversn;
	u64 refgaddr;
	u64 refselmk;
	u64 refcmpmk;
	u64 reserved;
};

static struct pfault_refbk pfault_init_refbk = {
	.refdiagc = 0x258,
	.reffcode = 0,
	.refdwlen = 5,
	.refversn = 2,
	.refgaddr = __LC_LPP,
	.refselmk = 1UL << 48,
	.refcmpmk = 1UL << 48,
	.reserved = __PF_RES_FIELD
};

int __pfault_init(void)
{
	int rc = -EOPNOTSUPP;

	if (pfault_disable)
		return rc;
	diag_stat_inc(DIAG_STAT_X258);
	asm_inline volatile(
		"	diag	%[refbk],%[rc],0x258\n"
		"0:	nopr	%%r7\n"
		EX_TABLE(0b, 0b)
		: [rc] "+d" (rc)
		: [refbk] "a" (virt_to_phys(&pfault_init_refbk)), "m" (pfault_init_refbk)
		: "cc");
	return rc;
}

static struct pfault_refbk pfault_fini_refbk = {
	.refdiagc = 0x258,
	.reffcode = 1,
	.refdwlen = 5,
	.refversn = 2,
};

void __pfault_fini(void)
{
	if (pfault_disable)
		return;
	diag_stat_inc(DIAG_STAT_X258);
	asm_inline volatile(
		"	diag	%[refbk],0,0x258\n"
		"0:	nopr	%%r7\n"
		EX_TABLE(0b, 0b)
		:
		: [refbk] "a" (virt_to_phys(&pfault_fini_refbk)), "m" (pfault_fini_refbk)
		: "cc");
}

static DEFINE_SPINLOCK(pfault_lock);
static LIST_HEAD(pfault_list);

#define PF_COMPLETE	0x0080

/*
 * The mechanism of our pfault code: if Linux is running as guest, runs a user
 * space process and the user space process accesses a page that the host has
 * paged out we get a pfault interrupt.
 *
 * This allows us, within the guest, to schedule a different process. Without
 * this mechanism the host would have to suspend the whole virtual cpu until
 * the page has been paged in.
 *
 * So when we get such an interrupt then we set the state of the current task
 * to uninterruptible and also set the need_resched flag. Both happens within
 * interrupt context(!). If we later on want to return to user space we
 * recognize the need_resched flag and then call schedule().  It's not very
 * obvious how this works...
 *
 * Of course we have a lot of additional fun with the completion interrupt (->
 * host signals that a page of a process has been paged in and the process can
 * continue to run). This interrupt can arrive on any cpu and, since we have
 * virtual cpus, actually appear before the interrupt that signals that a page
 * is missing.
 */
static void pfault_interrupt(struct ext_code ext_code,
			     unsigned int param32, unsigned long param64)
{
	struct task_struct *tsk;

Annotation

Implementation Notes