x86: implement user mode on 64-bit

- In early boot, enable the syscall instruction and set up
  necessary MSRs
- Add a hook to update page tables on context switch
- Properly initialize thread based on whether it will
  start in user or supervisor mode
- Add landing function for system calls to execute the
  desired handler
- Implement arch_user_string_nlen()
- Implement logic for dropping a thread down to user mode
- Reserve per-CPU storage space for user and privilege
  elevation stack pointers, necessary for handling syscalls
  when no free registers are available
- Proper handling of gs register considerations when
  transitioning privilege levels

Kernel page table isolation (KPTI) is not yet implemented.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2019-12-18 14:30:41 -08:00 committed by Anas Nashif
commit 3d80208025
10 changed files with 406 additions and 15 deletions

View file

@ -59,6 +59,19 @@ struct x86_esf {
typedef struct x86_esf z_arch_esf_t;
struct x86_ssf {
unsigned long rip;
unsigned long rflags;
unsigned long r10;
unsigned long r9;
unsigned long r8;
unsigned long rdx;
unsigned long rsi;
char fxsave[X86_FXSAVE_SIZE];
unsigned long rdi;
unsigned long rsp;
};
#define ARCH_EXCEPT(reason_p) do { \
__asm__ volatile( \
"movq %[reason], %%rax\n\t" \

View file

@ -20,6 +20,11 @@
#define X86_USER_DS 0x30 /* 64-bit user mode data */
#define X86_USER_CS 0x38 /* 64-bit user mode code */
/* Value programmed into bits 63:32 of STAR MSR with proper segment
* descriptors for implementing user mode with syscall/sysret
*/
#define X86_STAR_UPPER ((X86_USER_CS_32 << 16) | X86_KERNEL_CS)
#define X86_KERNEL_CPU0_TR 0x40 /* 64-bit task state segment */
#define X86_KERNEL_CPU1_TR 0x50 /* 64-bit task state segment */
#define X86_KERNEL_CPU2_TR 0x60 /* 64-bit task state segment */
@ -73,6 +78,13 @@ struct x86_tss64 {
*/
struct _cpu *cpu;
#ifdef CONFIG_USERSPACE
/* Privilege mode stack pointer value when doing a system call */
char *psp;
/* Storage area for user mode stack pointer when doing a syscall */
char *usp;
#endif
} __packed __aligned(8);
typedef struct x86_tss64 x86_tss64_t;
@ -101,6 +113,23 @@ typedef struct _callee_saved _callee_saved_t;
struct _thread_arch {
u8_t flags;
#ifdef CONFIG_USERSPACE
/* Pointer to page tables used by this thread. Supervisor threads
* always use the kernel's page table, user thread use per-thread
* tables stored in the stack object
*/
struct x86_page_tables *ptables;
/* Initial privilege mode stack pointer when doing a system call.
* Un-set for supervisor threads.
*/
char *psp;
/* SS and CS selectors for this thread when restoring context */
u64_t ss;
u64_t cs;
#endif
u64_t rax;
u64_t rcx;
u64_t rdx;