arch/x86/um/os-Linux/mcontext.c

Source file repositories/reference/linux-study-clean/arch/x86/um/os-Linux/mcontext.c

File Facts

System
Linux kernel
Corpus path
arch/x86/um/os-Linux/mcontext.c
Extension
.c
Size
7638 bytes
Lines
267
Domain
Architecture Layer
Bucket
arch/x86
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 _xstate_64 {
	struct _fpstate_64		fpstate;
	struct _header			xstate_hdr;
	struct _ymmh_state		ymmh;
	/* New processor state extensions go here: */
};

/* Not quite the right structures as these contain more information */
int um_i387_from_fxsr(struct _fpstate_32 *i387,
		      const struct _fpstate_64 *fxsave);
int um_fxsr_from_i387(struct _fpstate_64 *fxsave,
		      const struct _fpstate_32 *from);
#else
#define _xstate_64 _xstate
#endif

static struct _fpstate *get_fpstate(struct stub_data *data,
				    mcontext_t *mcontext,
				    int *fp_size)
{
	struct _fpstate *res;

	/* Assume floating point registers are on the same page */
	res = (void *)(((unsigned long)mcontext->fpregs &
			(UM_KERN_PAGE_SIZE - 1)) +
		       (unsigned long)&data->sigstack[0]);

	if ((void *)res + sizeof(struct _fpstate) >
	    (void *)data->sigstack + sizeof(data->sigstack))
		return NULL;

	if (res->sw_reserved.magic1 != FP_XSTATE_MAGIC1) {
		*fp_size = sizeof(struct _fpstate);
	} else {
		char *magic2_addr;

		magic2_addr = (void *)res;
		magic2_addr += res->sw_reserved.extended_size;
		magic2_addr -= FP_XSTATE_MAGIC2_SIZE;

		/* We still need to be within our stack */
		if ((void *)magic2_addr >
		    (void *)data->sigstack + sizeof(data->sigstack))
			return NULL;

		/* If we do not read MAGIC2, then we did something wrong */
		if (*(__u32 *)magic2_addr != FP_XSTATE_MAGIC2)
			return NULL;

		/* Remove MAGIC2 from the size, we do not save/restore it */
		*fp_size = res->sw_reserved.extended_size -
			   FP_XSTATE_MAGIC2_SIZE;
	}

	return res;
}

int get_stub_state(struct uml_pt_regs *regs, struct stub_data *data,
		   unsigned long *fp_size_out)
{
	mcontext_t *mcontext;
	struct _fpstate *fpstate_stub;
	struct _xstate_64 *xstate_stub;
	int fp_size, xstate_size;

	/* mctx_offset is verified by wait_stub_done_seccomp */
	mcontext = (void *)&data->sigstack[data->mctx_offset];

	get_regs_from_mc(regs, mcontext);

	fpstate_stub = get_fpstate(data, mcontext, &fp_size);
	if (!fpstate_stub)
		return -EINVAL;

#ifdef CONFIG_X86_32
	xstate_stub = (void *)&fpstate_stub->_fxsr_env;
	xstate_size = fp_size - offsetof(struct _fpstate_32, _fxsr_env);
#else
	xstate_stub = (void *)fpstate_stub;
	xstate_size = fp_size;
#endif

	if (fp_size_out)
		*fp_size_out = xstate_size;

	if (xstate_size > host_fp_size)
		return -ENOSPC;

	memcpy(&regs->fp, xstate_stub, xstate_size);

Annotation

Implementation Notes