This gets a simple checkpoint/restart working on an s390x. Signed-off-by: Serge E. Hallyn <serue@xxxxxxxxxx> --- arch/s390/include/asm/checkpoint_hdr.h | 35 +++++++++- arch/s390/mm/checkpoint.c | 110 +++++++++++++++++++++++++++++--- 2 files changed, 132 insertions(+), 13 deletions(-) diff --git a/arch/s390/include/asm/checkpoint_hdr.h b/arch/s390/include/asm/checkpoint_hdr.h index 81ca76f..2be5ced 100644 --- a/arch/s390/include/asm/checkpoint_hdr.h +++ b/arch/s390/include/asm/checkpoint_hdr.h @@ -34,19 +34,46 @@ #endif struct cr_hdr_head_arch { - __u16 unimplemented; + __u64 unimplemented; }; struct cr_hdr_thread { - __s16 unimplemented; + /* restart blocks */ + __u64 unimplemented; }; +/* + * Notes + * NUM_GPRS defined in <asm/ptrace.h> to be 16 + * NUM_FPRS defined in <asm/ptrace.h> to be 16 + * NUM_APRS defined in <asm/ptrace.h> to be 16 + */ struct cr_hdr_cpu { - __u64 unimplemented; + psw_t psw; + unsigned long args[1]; + s390_fp_regs fp_regs; + unsigned long gprs[NUM_GPRS]; + unsigned long orig_gpr2; + unsigned short svcnr; + unsigned short ilc; + unsigned int acrs[NUM_ACRS]; + unsigned long ksp; + unsigned long prot_addr; + unsigned int trap_no; + per_struct per_info; + unsigned long ieee_instruction_pointer; + unsigned long pfault_wait; }; struct cr_hdr_mm_context { - __s16 unimplemented; +#if 0 + unsigned long asce_bits; + unsigned long asce_limit; + int noexec; + int has_pgste; + int alloc_pgste; +#endif + unsigned long vdso_base; }; #endif /* __ASM_S390_CKPT_HDR__H */ diff --git a/arch/s390/mm/checkpoint.c b/arch/s390/mm/checkpoint.c index 7f7e0b1..b2d7841 100644 --- a/arch/s390/mm/checkpoint.c +++ b/arch/s390/mm/checkpoint.c @@ -35,6 +35,29 @@ int cr_write_thread(struct cr_ctx *ctx, struct task_struct *t) return ret; } +static void cr_save_cpu_regs(struct cr_hdr_cpu *hh, struct task_struct *t) +{ + struct thread_struct *thread = &t->thread; + struct pt_regs *regs = task_pt_regs(t); + + memcpy(&hh->psw, ®s->psw, sizeof(psw_t)); + hh->args[0] = regs->args[0]; + hh->svcnr = regs->svcnr; + hh->ilc = regs->ilc; + memcpy(hh->gprs, regs->gprs, NUM_GPRS*sizeof(unsigned long)); + hh->orig_gpr2 = regs->orig_gpr2; + + memcpy(&hh->fp_regs, &thread->fp_regs, sizeof(s390_fp_regs)); + memcpy(hh->acrs, thread->acrs, NUM_ACRS * sizeof(unsigned int)); + hh->ksp = thread->ksp; + printk(KERN_NOTICE "%s: saving ksp as %lx\n", __func__, hh->ksp); + hh->prot_addr = thread->prot_addr; + hh->trap_no = thread->trap_no; + memcpy(&hh->per_info, &thread->per_info, sizeof(per_struct)); + hh->ieee_instruction_pointer = thread->ieee_instruction_pointer; + hh->pfault_wait = thread->pfault_wait; +} + /* dump the cpu state and registers of a given task */ int cr_write_cpu(struct cr_ctx *ctx, struct task_struct *t) { @@ -46,7 +69,7 @@ int cr_write_cpu(struct cr_ctx *ctx, struct task_struct *t) h.len = sizeof(*hh); h.parent = task_pid_vnr(t); - hh->unimplemented = 0xdeadbeef; + cr_save_cpu_regs(hh, t); ret = cr_write_obj(ctx, &h, hh); cr_hbuf_put(ctx, sizeof(*hh)); @@ -87,16 +110,22 @@ int cr_write_mm_context(struct cr_ctx *ctx, struct mm_struct *mm, int parent) h.len = sizeof(*hh); h.parent = parent; - hh->unimplemented = 0xbeef; +#if 1 + hh->vdso_base = mm->context.vdso_base; +#else + hh->asce_bits = mm->context.asce_bits; + hh->asce_limit = mm->context.asce_limit; + hh->noexec = mm->context.noexec; + hh->has_pgste = mm->context.has_pgste; + hh->alloc_pgste = mm->context.alloc_pgste; +#endif ret = cr_write_obj(ctx, &h, hh); cr_hbuf_put(ctx, sizeof(*hh)); - WARN_ON_ONCE(ret < 0); if (ret < 0) goto out; - /* FIXME: NFI. */ ret = 0; out: return ret; @@ -107,14 +136,64 @@ out: /* read the thread_struct into the current task */ int cr_read_thread(struct cr_ctx *ctx) { - WARN_ON_ONCE(true); - return -ENOSYS; + struct cr_hdr_thread *hh = cr_hbuf_get(ctx, sizeof(*hh)); + int parent, ret; + + parent = cr_read_obj_type(ctx, hh, sizeof(*hh), CR_HDR_THREAD); + if (parent < 0) { + ret = parent; + goto out; + } + + if (hh->unimplemented != 0xbeef) { + printk(KERN_NOTICE "Error: cr file corrupted\n"); + ret = -EINVAL; + goto out; + } + ret = 0; + +out: + cr_hbuf_put(ctx, sizeof(*hh)); + return 0; } int cr_read_cpu(struct cr_ctx *ctx) { - WARN_ON_ONCE(true); - return -ENOSYS; + struct cr_hdr_cpu *hh = cr_hbuf_get(ctx, sizeof(*hh)); + struct thread_struct *thread = ¤t->thread; + struct pt_regs *regs = task_pt_regs(current); + int parent, ret; + + parent = cr_read_obj_type(ctx, hh, sizeof(*hh), CR_HDR_CPU); + if (parent < 0) { + ret = parent; + goto out; + } + ret = 0; + + //memcpy(®s->psw, &hh->psw, sizeof(psw_t)); + regs->psw.addr &= ~PSW_ADDR_INSN; + regs->psw.addr |= hh->psw.addr & PSW_ADDR_INSN; + regs->args[0] = hh->args[0]; + regs->svcnr = hh->svcnr; + regs->ilc = hh->ilc; + memcpy(regs->gprs, hh->gprs, NUM_GPRS*sizeof(unsigned long)); + regs->orig_gpr2 = hh->orig_gpr2; + + memcpy(&thread->fp_regs, &hh->fp_regs, sizeof(s390_fp_regs)); + memcpy(thread->acrs, hh->acrs, NUM_ACRS * sizeof(unsigned int)); + printk(KERN_NOTICE "%s: orig task's ksp was %lx\n", __func__, thread->ksp); + thread->ksp = hh->ksp; + printk(KERN_NOTICE "%s: restoring ksp as %lx\n", __func__, hh->ksp); + thread->prot_addr = hh->prot_addr; + thread->trap_no = hh->trap_no; + memcpy(&thread->per_info, &hh->per_info, sizeof(per_struct)); + thread->ieee_instruction_pointer = hh->ieee_instruction_pointer; + thread->pfault_wait = hh->pfault_wait; + +out: + cr_hbuf_put(ctx, sizeof(*hh)); + return ret; } int cr_read_head_arch(struct cr_ctx *ctx) @@ -128,6 +207,11 @@ int cr_read_head_arch(struct cr_ctx *ctx) goto out; } else if (parent != 0) goto out; + + if (hh->unimplemented != 0xbeef) { + printk(KERN_NOTICE "%s: checkpoint file corrupt\n", __func__); + ret = -EINVAL; + } out: cr_hbuf_put(ctx, sizeof(*hh)); return ret; @@ -146,7 +230,15 @@ int cr_read_mm_context(struct cr_ctx *ctx, struct mm_struct *mm, int rparent) if (parent != rparent) goto out; - WARN_ON_ONCE(hh->unimplemented != (__s16)0xbeef); +#if 0 + mm->context.asce_bits = hh->asce_bits; + mm->context.asce_limit = hh->asce_limit; + mm->context.noexec = hh->noexec; + mm->context.has_pgste = hh->has_pgste; + mm->context.alloc_pgste = hh->alloc_pgste; +#endif + mm->context.vdso_base = hh->vdso_base; + ret = 0; out: cr_hbuf_put(ctx, sizeof(*hh)); return ret; -- 1.6.1 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers