Commit c1f7ab21 authored by Cyrill Gorcunov's avatar Cyrill Gorcunov Committed by Pavel Emelyanov

checkpoint: Add dumping of FPU state

The dumping of FPU state is done with help of ptrace
facility. There are two cases which we need to handle
depending on which features are available on host machine

1) The dump via ptrace(PTRACE_GETFPREGS ...)

   In this case the kernel will use fxsave approach
   inside the kenrel and provides us back the data
   encoded in i387_fxsave_struct format.

2) The dump via ptrace(PTRACE_GETREGSET ...)

   In this case the kernel will use xsave approach
   inside the kernel and provides us back the data
   encoded in xsave_struct format.

In any case we decode data and save it in protobuf format.
This is why core.proto file has been extended to keep new
entries.
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 8b93676d
...@@ -61,6 +61,8 @@ ...@@ -61,6 +61,8 @@
#include "net.h" #include "net.h"
#include "sk-packet.h" #include "sk-packet.h"
#include "cpu.h" #include "cpu.h"
#include "fpu.h"
#include "elf.h"
#ifndef CONFIG_X86_64 #ifndef CONFIG_X86_64
# error No x86-32 support yet # error No x86-32 support yet
...@@ -649,9 +651,10 @@ err: ...@@ -649,9 +651,10 @@ err:
static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl) static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *ctl)
{ {
user_fpregs_struct_t fpregs = {-1}; struct xsave_struct xsave = { };
user_regs_struct_t regs = {-1}; user_regs_struct_t regs = {-1};
struct iovec iov;
int ret = -1; int ret = -1;
pr_info("Dumping GP/FPU registers ... "); pr_info("Dumping GP/FPU registers ... ");
...@@ -665,11 +668,6 @@ static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl * ...@@ -665,11 +668,6 @@ static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *
} }
} }
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs)) {
pr_err("Can't obtain FPU registers for %d\n", pid);
goto err;
}
/* Did we come from a system call? */ /* Did we come from a system call? */
if ((int)regs.orig_ax >= 0) { if ((int)regs.orig_ax >= 0) {
/* Restart the system call */ /* Restart the system call */
...@@ -718,25 +716,60 @@ static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl * ...@@ -718,25 +716,60 @@ static int get_task_regs(pid_t pid, CoreEntry *core, const struct parasite_ctl *
assign_reg(core->thread_info->gpregs, regs, fs); assign_reg(core->thread_info->gpregs, regs, fs);
assign_reg(core->thread_info->gpregs, regs, gs); assign_reg(core->thread_info->gpregs, regs, gs);
assign_reg(core->thread_info->fpregs, fpregs, cwd); #ifndef PTRACE_GETREGSET
assign_reg(core->thread_info->fpregs, fpregs, swd); # define PTRACE_GETREGSET 0x4204
assign_reg(core->thread_info->fpregs, fpregs, twd); #endif
assign_reg(core->thread_info->fpregs, fpregs, fop);
assign_reg(core->thread_info->fpregs, fpregs, rip); if (!cpu_has_feature(X86_FEATURE_FPU))
assign_reg(core->thread_info->fpregs, fpregs, rdp); goto out;
assign_reg(core->thread_info->fpregs, fpregs, mxcsr);
assign_reg(core->thread_info->fpregs, fpregs, mxcsr_mask); /*
* FPU fetched either via fxsave or via xsave,
* thus decode it accrodingly.
*/
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
iov.iov_base = &xsave;
iov.iov_len = sizeof(xsave);
if (ptrace(PTRACE_GETREGSET, pid, (unsigned int)NT_X86_XSTATE, &iov) < 0) {
pr_err("Can't obtain FPU registers for %d\n", pid);
goto err;
}
} else {
if (ptrace(PTRACE_GETFPREGS, pid, NULL, &xsave)) {
pr_err("Can't obtain FPU registers for %d\n", pid);
goto err;
}
}
assign_reg(core->thread_info->fpregs, xsave.i387, cwd);
assign_reg(core->thread_info->fpregs, xsave.i387, swd);
assign_reg(core->thread_info->fpregs, xsave.i387, twd);
assign_reg(core->thread_info->fpregs, xsave.i387, fop);
assign_reg(core->thread_info->fpregs, xsave.i387, rip);
assign_reg(core->thread_info->fpregs, xsave.i387, rdp);
assign_reg(core->thread_info->fpregs, xsave.i387, mxcsr);
assign_reg(core->thread_info->fpregs, xsave.i387, mxcsr_mask);
/* Make sure we have enough space */ /* Make sure we have enough space */
BUG_ON(core->thread_info->fpregs->n_st_space != ARRAY_SIZE(fpregs.st_space)); BUG_ON(core->thread_info->fpregs->n_st_space != ARRAY_SIZE(xsave.i387.st_space));
BUG_ON(core->thread_info->fpregs->n_xmm_space != ARRAY_SIZE(fpregs.xmm_space)); BUG_ON(core->thread_info->fpregs->n_xmm_space != ARRAY_SIZE(xsave.i387.xmm_space));
assign_array(core->thread_info->fpregs, xsave.i387, st_space);
assign_array(core->thread_info->fpregs, xsave.i387, xmm_space);
assign_array(core->thread_info->fpregs, fpregs, st_space); if (cpu_has_feature(X86_FEATURE_XSAVE)) {
assign_array(core->thread_info->fpregs, fpregs, xmm_space); BUG_ON(core->thread_info->fpregs->xsave->n_ymmh_space != ARRAY_SIZE(xsave.ymmh.ymmh_space));
assign_reg(core->thread_info->fpregs->xsave, xsave.xsave_hdr, xstate_bv);
assign_array(core->thread_info->fpregs->xsave, xsave.ymmh, ymmh_space);
}
#undef assign_reg #undef assign_reg
#undef assign_array #undef assign_array
out:
ret = 0; ret = 0;
err: err:
...@@ -793,6 +826,9 @@ static void core_entry_free(CoreEntry *core) ...@@ -793,6 +826,9 @@ static void core_entry_free(CoreEntry *core)
if (core) { if (core) {
if (core->thread_info) { if (core->thread_info) {
if (core->thread_info->fpregs) { if (core->thread_info->fpregs) {
if (core->thread_info->fpregs->xsave)
xfree(core->thread_info->fpregs->xsave->ymmh_space);
xfree(core->thread_info->fpregs->xsave);
xfree(core->thread_info->fpregs->st_space); xfree(core->thread_info->fpregs->st_space);
xfree(core->thread_info->fpregs->xmm_space); xfree(core->thread_info->fpregs->xmm_space);
xfree(core->thread_info->fpregs->padding); xfree(core->thread_info->fpregs->padding);
...@@ -845,22 +881,37 @@ static CoreEntry *core_entry_alloc(int alloc_thread_info, ...@@ -845,22 +881,37 @@ static CoreEntry *core_entry_alloc(int alloc_thread_info,
user_x86_regs_entry__init(gpregs); user_x86_regs_entry__init(gpregs);
thread_info->gpregs = gpregs; thread_info->gpregs = gpregs;
fpregs = xmalloc(sizeof(*fpregs)); if (cpu_has_feature(X86_FEATURE_FPU)) {
if (!fpregs) fpregs = xmalloc(sizeof(*fpregs));
goto err; if (!fpregs)
user_x86_fpregs_entry__init(fpregs); goto err;
thread_info->fpregs = fpregs; user_x86_fpregs_entry__init(fpregs);
thread_info->fpregs = fpregs;
/* These are numbers from kernel */ /* These are numbers from kernel */
fpregs->n_st_space = 32; fpregs->n_st_space = 32;
fpregs->n_xmm_space = 64; fpregs->n_xmm_space = 64;
fpregs->st_space = xzalloc(pb_repeated_size(fpregs, st_space)); fpregs->st_space = xzalloc(pb_repeated_size(fpregs, st_space));
fpregs->xmm_space = xzalloc(pb_repeated_size(fpregs, xmm_space)); fpregs->xmm_space = xzalloc(pb_repeated_size(fpregs, xmm_space));
if (!fpregs->st_space || !fpregs->xmm_space) if (!fpregs->st_space || !fpregs->xmm_space)
goto err; goto err;
if (cpu_has_feature(X86_FEATURE_XSAVE)) {
UserX86XsaveEntry *xsave;
xsave = xmalloc(sizeof(*xsave));
if (!xsave)
goto err;
user_x86_xsave_entry__init(xsave);
thread_info->fpregs->xsave = xsave;
xsave->n_ymmh_space = 64;
xsave->ymmh_space = xzalloc(pb_repeated_size(xsave, ymmh_space));
if (!xsave->ymmh_space)
goto err;
}
}
} }
if (alloc_tc) { if (alloc_tc) {
......
...@@ -28,7 +28,14 @@ message user_x86_regs_entry { ...@@ -28,7 +28,14 @@ message user_x86_regs_entry {
required uint64 gs = 27; required uint64 gs = 27;
} }
message user_x86_xsave_entry {
required uint64 xstate_bv = 1;
repeated uint32 ymmh_space = 2;
}
message user_x86_fpregs_entry { message user_x86_fpregs_entry {
/* fxsave data */
required uint32 cwd = 1; required uint32 cwd = 1;
required uint32 swd = 2; required uint32 swd = 2;
required uint32 twd = 3; required uint32 twd = 3;
...@@ -42,6 +49,9 @@ message user_x86_fpregs_entry { ...@@ -42,6 +49,9 @@ message user_x86_fpregs_entry {
/* Unused, but present for backward compatibility */ /* Unused, but present for backward compatibility */
repeated uint32 padding = 11; repeated uint32 padding = 11;
/* xsave extension */
optional user_x86_xsave_entry xsave = 13;
} }
message task_core_entry { message task_core_entry {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment