From: Xu Zhang <xzhang@cs.uic.edu>
To: Samuel Thibault <samuel.thibault@ens-lyon.org>,
"xen-devel@lists.xen.org" <xen-devel@lists.xen.org>,
gm281@cam.ac.uk
Subject: Re: Nested events in 64bit mini-OS
Date: Mon, 05 Nov 2012 23:56:04 -0600 [thread overview]
Message-ID: <5098A674.5090203@cs.uic.edu> (raw)
In-Reply-To: <20121025205653.GW5925@type.chello.at>
[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]
Dear all,
I haven't seen any updates on this matter, so I try to come up with a
fix. Generally speaking, I want to mimic 32-bit mini-OS behaviour, adding:
1) a fixup table: for each byte offset in the critical region, it
provides the number of bytes which have already been popped from the
interrupted stack frame.
2) a fixup routine: obtain number of restored registers by quickly
looking up the fixup table and coalesce the current stack frame with the
just-interrupted one.
3) checks against re-entrance in hypervisor_callback
The "git diff" output is attached to this email. I only did some naive
"tests" by running it inside gdb. I am wondering is there a test suite
for mini-OS? A follow-up question is that given this fix, do you still
need hypercall iret?
Thank you very much.
Regards,
Xu Zhang
On 10/25/2012 03:56 PM, Samuel Thibault wrote:
> Xu Zhang, le Tue 23 Oct 2012 17:43:28 -0500, a écrit :
>> 64-bit mini-OS seems to adopt a mixed use of both (in HYPERVISOR_IRET).
>> mini-OS doesn't have an userspace, so unless an NMI happened, it always
>> perform interrupt/exception return with machine instruction iret, without
>> checking against nested events. This is wrong to me. Am I missing something
>> here?
> I don't think you are missing anything. Cc-ing Grzegorz, who actually
> wrote the code.
>
> Samuel
[-- Attachment #2: fixup.diff --]
[-- Type: text/x-patch, Size: 5515 bytes --]
diff --git a/extras/mini-os/arch/x86/x86_64.S b/extras/mini-os/arch/x86/x86_64.S
index a65e5d5..b4f351c 100644
--- a/extras/mini-os/arch/x86/x86_64.S
+++ b/extras/mini-os/arch/x86/x86_64.S
@@ -42,8 +42,10 @@ hypercall_page:
NMI_MASK = 0x80000000
+#define RBX 40
#define RDI 112
#define ORIG_RAX 120 /* + error_code */
+#define RIP 128
#define EFLAGS 144
.macro RESTORE_ALL
@@ -147,7 +149,43 @@ error_call_handler:
ENTRY(hypervisor_callback)
- zeroentry hypervisor_callback2
+ movq (%rsp),%rcx
+ movq 8(%rsp),%r11
+ addq $0x10,%rsp /* skip rcx and r11 */
+ pushq $0 /* push error code/oldrax */
+ pushq %rax /* push real oldrax to the rdi slot */
+ leaq hypervisor_callback2(%rip), %rax
+
+ /* rdi slot contains rax, oldrax contains error code */
+ cld
+ subq $14*8,%rsp
+ movq %rsi,13*8(%rsp)
+ movq 14*8(%rsp),%rsi /* load rax from rdi slot */
+ movq %rdx,12*8(%rsp)
+ movq %rcx,11*8(%rsp)
+ movq %rsi,10*8(%rsp) /* store rax */
+ movq %r8, 9*8(%rsp)
+ movq %r9, 8*8(%rsp)
+ movq %r10,7*8(%rsp)
+ movq %r11,6*8(%rsp)
+ movq %rbx,5*8(%rsp)
+ movq %rbp,4*8(%rsp)
+ movq %r12,3*8(%rsp)
+ movq %r13,2*8(%rsp)
+ movq %r14,1*8(%rsp)
+ movq %r15,(%rsp)
+ movq %rdi, RDI(%rsp)
+
+ # check against re-entrance
+ movq RIP(%rsp),%rbx
+ cmpq $scrit,%rbx
+ jb 10f
+ cmpq $ecrit,%rbx
+ jb critical_region_fixup
+
+10: movq RBX(%rsp),%rbx # restore rbx
+ movq %rsp,%rdi
+ call *%rax
ENTRY(hypervisor_callback2)
movq %rdi, %rsp
@@ -172,17 +210,40 @@ scrit: /**** START OF CRITICAL REGION ****/
14: XEN_LOCKED_BLOCK_EVENTS(%rsi)
XEN_PUT_VCPU_INFO(%rsi)
- subq $6*8,%rsp
- movq %rbx,5*8(%rsp)
- movq %rbp,4*8(%rsp)
- movq %r12,3*8(%rsp)
- movq %r13,2*8(%rsp)
- movq %r14,1*8(%rsp)
- movq %r15,(%rsp)
- movq %rsp,%rdi # set the argument again
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ movq %rsp,%rdi # set the argument again
jmp 11b
ecrit: /**** END OF CRITICAL REGION ****/
+# [How we do the fixup]. We want to merge the current stack frame with the
+# just-interrupted frame. How we do this depends on where in the critical
+# region the interrupted handler was executing, and so how many saved
+# registers are in each frame. We do this quickly using the lookup table
+# 'critical_fixup_table'. For each byte offset in the critical region, it
+# provides the number of bytes which have already been popped from the
+# interrupted stack frame.
+critical_region_fixup:
+ addq $critical_fixup_table - scrit, %rbx
+ movzbq (%rbx),%rbx # %rbx contains num bytes popped
+ mov %rsp,%rsi
+ add %rbx,%rsi # %esi points at end of src region
+ mov %rsp,%rdi
+ add $0xa8,%rdi # %edi points at end of dst region
+ mov %rbx,%rcx
+ shr $3,%rcx # convert bytes into count of 64-bit entities
+ je 16f # skip loop if nothing to copy
+15: subq $8,%rsi # pre-decrementing copy loop
+ subq $8,%rdi
+ movq (%rsi),%rbx
+ movq %rbx,(%rdi)
+ loop 15b
+16: movq %rdi,%rsp # final %rdi is top of merged stack
+ jmp 10b
retint_kernel:
retint_restore_args:
@@ -210,6 +271,42 @@ error_exit:
jmp retint_kernel
+critical_fixup_table:
+ .byte 0x30,0x30,0x30 # testb $0xff,(%rsi)
+ .byte 0x30,0x30 # jne 14f
+ .byte 0x30,0x30,0x30,0x30 # mov (%rsp),%r11
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x8(%rsp),%r10
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x10(%rsp),%r9
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x18(%rsp),%r8
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x20(%rsp),%rax
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x28(%rsp),%rcx
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x30(%rsp),%rdx
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x38(%rsp),%rsi
+ .byte 0x30,0x30,0x30,0x30,0x30 # mov 0x40(%rsp),%rdi
+ .byte 0x30,0x30,0x30,0x30 # add $0x50,%rsp
+ .byte 0x80,0x80,0x80,0x80 # testl $NMI_MASK,2*8(%rsp)
+ .byte 0x80,0x80,0x80,0x80
+ .byte 0x80,0x80 # jne 2f
+ .byte 0x80,0x80,0x80,0x80 # testb $1,(xen_features+XENFEAT_supervisor_mode_kernel)
+ .byte 0x80,0x80,0x80,0x80
+ .byte 0x80,0x80 # jne 1f
+ .byte 0x80,0x80,0x80,0x80,0x80 # orb $0x3,0x8(%rsp)
+ .byte 0x80,0x80,0x80,0x80,0x80 # orb $0x3,0x20(%rsp)
+ .byte 0x80,0x80 # iretq
+ .byte 0x80,0x80,0x80,0x80 # andl $~NMI_MASK,0x10(%rsp)
+ .byte 0x80,0x80,0x80,0x80
+ .byte 0x80,0x80 # pushq $0x0
+ .byte 0x78,0x78,0x78,0x78,0x78 # jmp hypercall_page + (__HYPERVISOR_iret * 32)
+ .byte 0x30,0x30,0x30,0x30 # movb $0x1,0x1(%rsi)
+ .byte 0x30 # push %rbx
+ .byte 0x28 # push %rbp
+ .byte 0x20,0x20 # push %r12
+ .byte 0x18,0x18 # push %r13
+ .byte 0x10,0x10 # push %r14
+ .byte 0x08,0x08 # push %r15
+ .byte 0x00,0x00,0x00 # mov %rsp,%rdi
+ .byte 0x00,0x00,0x00,0x00,0x00 # jmpq 11b
+
ENTRY(failsafe_callback)
popq %rcx
[-- Attachment #3: Type: text/plain, Size: 126 bytes --]
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
next prev parent reply other threads:[~2012-11-06 5:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-23 22:43 Nested events in 64bit mini-OS Xu Zhang
2012-10-25 20:56 ` Samuel Thibault
2012-11-06 5:56 ` Xu Zhang [this message]
2012-11-10 13:52 ` Samuel Thibault
2012-11-11 15:36 ` Xu Zhang
2012-11-14 1:49 ` Xu Zhang
2012-11-18 17:43 ` Samuel Thibault
2012-11-19 10:22 ` Ian Campbell
2012-11-19 10:21 ` Ian Campbell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5098A674.5090203@cs.uic.edu \
--to=xzhang@cs.uic.edu \
--cc=gm281@cam.ac.uk \
--cc=samuel.thibault@ens-lyon.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).