x86: Add support for SW-switched segment-based protection domains

This patch extends the protection domain framework with a third plugin
that is a hybrid of the previous two.  The hardware task switching
mechanism has a strictly-defined format for TSS data structures that
causes more space to be consumed than would otherwise be required.
This patch defines a smaller data structure that is allocated for each
protection domain, only requiring 32 bytes instead of 128 bytes.  It
uses the same multi-segment memory layout as the TSS-based plugin and
leaves paging disabled.  However, it uses a similar mechanism as the
paging plugin to perform system call dispatches and returns.

For additional information, please refer to cpu/x86/mm/README.md.
This commit is contained in:
Michael LeMay 2015-08-07 11:51:04 -07:00
parent 4cdb7ba9b6
commit e0aefd11d9
13 changed files with 335 additions and 38 deletions

View file

@ -33,6 +33,10 @@
#include "gdt-layout.h"
#include "stacks.h"
/* Must match definitions (plus the trailing 's') in multi-segment.h */
#define SEG_MMIO fs
#define SEG_KERN fs
.text
/* Invoke the system call return dispatcher from the default privilege
@ -42,21 +46,57 @@
prot_domains_sysret_stub:
int $PROT_DOMAINS_SYSRET_DISPATCH_INT
.macro save_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
/* Save (and restore, in restore_segs) MMIO segment register into
* callee-saved register in case a system call was invoked from a region in
* which MMIO is enabled.
*/
push %SEG_MMIO
#endif
.endm
.macro restore_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
pop %SEG_MMIO
#endif
.endm
/* Refresh most of the segment registers in case they were corrupted by
* userspace code to prevent that from corrupting the operation of the
* privileged code.
*/
.macro load_kern_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
mov $GDT_SEL_DATA, %eax
mov %eax, %ds
mov %eax, %es
mov $GDT_SEL_DATA_KERN_EXC, %eax
mov %eax, %SEG_KERN
#endif
.endm
/* Invoke the system call dispatcher C routine */
.global prot_domains_syscall_dispatcher
prot_domains_syscall_dispatcher:
mov %esp, %ecx /*< interrupt_stack_t *intr_stk */
/* EDX already set to "dom_client_data_t to_dcd" by syscall stub */
push %eax /*< syscalls_id_t syscall_id */
save_segs
push %eax /*< syscalls_entrypoint_t *syscall */
load_kern_segs
call prot_domains_syscall_dispatcher_impl
/* fastcall convention, so callee pops arguments */
restore_segs
iret
/* Invoke the system call return dispatcher C routine */
.global prot_domains_sysret_dispatcher
prot_domains_sysret_dispatcher:
mov %esp, %ecx /*< interrupt_stack_t *intr_stk */
save_segs
load_kern_segs
call prot_domains_sysret_dispatcher_impl
restore_segs
/* Zero caller-saved registers in case they contain secrets. The system call
* handlers and dispatchers need to preserve the callee-saved registers.
*/
@ -67,11 +107,17 @@ prot_domains_sysret_dispatcher:
.global prot_domains_launch_kernel
prot_domains_launch_kernel:
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
mov $GDT_SEL_DATA, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov %eax, %gs
#else
mov $GDT_SEL_LDT(DOM_ID_kern), %eax
lldt %ax
call multi_segment_launch_kernel
#endif
/* init interrupt return stack: */
pushl $GDT_SEL_STK
lea stacks_main, %eax