Skip to content

Commit

Permalink
test fxsave
Browse files Browse the repository at this point in the history
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
  • Loading branch information
thehajime committed Dec 9, 2024
1 parent 173030d commit d85cc24
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 0 deletions.
3 changes: 3 additions & 0 deletions arch/x86/um/nommu/do_syscall_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <asm/prctl.h>
#include <kern_util.h>
#include <sysdep/syscalls.h>
#include <shared/registers.h>
#include <os.h>

/*
Expand Down Expand Up @@ -52,6 +53,8 @@ static int os_x86_arch_prctl(int pid, int option, unsigned long *arg2)
return 0;
}

char fpstate_buf[2696];

__visible void do_syscall_64(struct pt_regs *regs)
{
int syscall;
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/um/nommu/entry_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ ENTRY(__kernel_vsyscall)

movq %rsp, %r11

/* save fpregs */
fxsave fpstate_buf

/* Point rsp to the top of the ptregs array, so we can
just fill it with a bunch of push'es. */
movq current_ptregs, %rsp
Expand Down Expand Up @@ -106,6 +109,10 @@ ENTRY(userspace)
addq $8, %rsp /* skip flags */
popq %rsp


/* restore fpregs */
fxrstor fpstate_buf

jmp *%r11

END(userspace)
98 changes: 98 additions & 0 deletions arch/x86/um/os-Linux/mcontext.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
COPY2(UESP, ESP); /* sic */
COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
#undef COPY2
#undef COPY
#undef COPY_SEG
#undef COPY_SEG_CPL3
#else
#define COPY2(X,Y) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##Y]
#define COPY(X) regs->gp[X/sizeof(unsigned long)] = mc->gregs[REG_##X]
Expand All @@ -29,5 +33,99 @@ void get_regs_from_mc(struct uml_pt_regs *regs, mcontext_t *mc)
COPY2(CS, CSGSFS);
regs->gp[CS / sizeof(unsigned long)] &= 0xffff;
regs->gp[CS / sizeof(unsigned long)] |= 3;
#undef COPY2
#undef COPY
#endif
}

/* Same thing, but the copy macros are turned around. */
void get_mc_from_regs(struct uml_pt_regs *regs, mcontext_t *mc, int single_stepping)
{
#ifdef __i386__
#define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X]
#define COPY(X) mc->gregs[REG_##X] = regs->gp[X]
#define COPY_SEG(X) mc->gregs[REG_##X] = regs->gp[X] & 0xffff;
#define COPY_SEG_CPL3(X) mc->gregs[REG_##X] = (regs->gp[X] & 0xffff) | 3;
COPY_SEG(GS); COPY_SEG(FS); COPY_SEG(ES); COPY_SEG(DS);
COPY(EDI); COPY(ESI); COPY(EBP);
COPY2(UESP, ESP); /* sic */
COPY(EBX); COPY(EDX); COPY(ECX); COPY(EAX);
COPY(EIP); COPY_SEG_CPL3(CS); COPY(EFL); COPY_SEG_CPL3(SS);
#else
#define COPY2(X,Y) mc->gregs[REG_##Y] = regs->gp[X/sizeof(unsigned long)]
#define COPY(X) mc->gregs[REG_##X] = regs->gp[X/sizeof(unsigned long)]
COPY(R8); COPY(R9); COPY(R10); COPY(R11);
COPY(R12); COPY(R13); COPY(R14); COPY(R15);
COPY(RDI); COPY(RSI); COPY(RBP); COPY(RBX);
COPY(RDX); COPY(RAX); COPY(RCX); COPY(RSP);
COPY(RIP);
COPY2(EFLAGS, EFL);
mc->gregs[REG_CSGSFS] = mc->gregs[REG_CSGSFS] & 0xffffffffffffl;
mc->gregs[REG_CSGSFS] |= (regs->gp[SS / sizeof(unsigned long)] & 0xffff) << 48;
#endif

if (single_stepping)
mc->gregs[REG_EFL] |= X86_EFLAGS_TF;
else
mc->gregs[REG_EFL] &= ~X86_EFLAGS_TF;
}
#if 0

#ifdef CONFIG_X86_32
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

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;
}
#endif
2 changes: 2 additions & 0 deletions arch/x86/um/shared/sysdep/mcontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#define __SYS_SIGCONTEXT_X86_H

extern void get_regs_from_mc(struct uml_pt_regs *, mcontext_t *);
extern void get_mc_from_regs(struct uml_pt_regs *regs, mcontext_t *mc,
int single_stepping);
#ifndef CONFIG_MMU
extern void mc_set_sigsys_hook(mcontext_t *mc);
extern void mc_set_regs_ip_relay(mcontext_t *mc);
Expand Down

0 comments on commit d85cc24

Please sign in to comment.