Commit 4f36934b authored by kaf24's avatar kaf24

Fix x86/64 version of Mini-OS. It encompasses the following:

a) 64-bit switch_to scheduler macro (by Aravindh Puthiyaparambil)
b) implements 64-bit hypervisor_callback
c) fixes thread creation issues (thread_starter used to perform 
initialisation)
Signed-off-by: default avatarGrzegorz Milos <gm281@cam.ac.uk>
parent f143b49c
......@@ -128,7 +128,7 @@ void printk(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
print(0, fmt, args);
print(1, fmt, args);
va_end(args);
}
......
......@@ -106,6 +106,17 @@ void unbind_virq( u32 port )
unbind_evtchn(port);
}
#if defined(__x86_64__)
/* Allocate 4 pages for the irqstack */
#define STACK_PAGES 4
char irqstack[1024 * 4 * STACK_PAGES];
static struct pda
{
int irqcount; /* offset 0 (used in x86_64.S) */
char *irqstackptr; /* 8 */
} cpu0_pda;
#endif
/*
* Initially all events are without a handler and disabled
......@@ -113,7 +124,12 @@ void unbind_virq( u32 port )
void init_events(void)
{
int i;
#if defined(__x86_64__)
asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
wrmsrl(0xc0000101, &cpu0_pda); /* 0xc0000101 is MSR_GS_BASE */
cpu0_pda.irqcount = -1;
cpu0_pda.irqstackptr = irqstack + 1024 * 4 * STACK_PAGES;
#endif
/* inintialise event handler */
for ( i = 0; i < NR_EVS; i++ )
{
......
......@@ -41,8 +41,8 @@ void do_hypervisor_callback(struct pt_regs *regs)
shared_info_t *s = HYPERVISOR_shared_info;
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
vcpu_info->evtchn_upcall_pending = 0;
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
while ( l1 != 0 )
......
......@@ -148,7 +148,7 @@ static __inline__ unsigned long machine_to_phys(unsigned long machine)
}
#if defined(__x86_64__)
#define VIRT_START 0xFFFFFFFF00000000UL
#define VIRT_START 0xFFFFFFFF80000000UL
#elif defined(__i386__)
#define VIRT_START 0xC0000000UL
#endif
......
......@@ -434,6 +434,13 @@ static __inline__ unsigned long __ffs(unsigned long word)
(val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
} while(0)
#define wrmsr(msr,val1,val2) \
__asm__ __volatile__("wrmsr" \
: /* no outputs */ \
: "c" (msr), "a" (val1), "d" (val2))
#define wrmsrl(msr,val) wrmsr(msr,(u32)((u64)(val)),((u64)(val))>>32)
#else /* ifdef __x86_64__ */
#error "Unsupported architecture"
......
......@@ -7,8 +7,8 @@ struct thread
{
char *name;
char *stack;
unsigned long eps;
unsigned long eip;
unsigned long sp; /* Stack pointer */
unsigned long ip; /* Instruction pointer */
struct list_head thread_list;
u32 flags;
};
......@@ -25,7 +25,9 @@ static inline struct thread* get_current(void)
struct thread **current;
#ifdef __i386__
__asm__("andl %%esp,%0; ":"=r" (current) : "r" (~8191UL));
#endif
#else
__asm__("andq %%rsp,%0; ":"=r" (current) : "r" (~8191UL));
#endif
return *current;
}
......
......@@ -35,6 +35,8 @@
#include <lib.h>
#include <sched.h>
#include <xenbus.h>
#include <xen/features.h>
#include <xen/version.h>
/*
* Shared page for communicating with the hypervisor.
......@@ -85,6 +87,26 @@ static void init_xs(void *ign)
test_xenbus();
}
u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
void setup_xen_features(void)
{
xen_feature_info_t fi;
int i, j;
for (i = 0; i < XENFEAT_NR_SUBMAPS; i++)
{
fi.submap_idx = i;
if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
break;
for (j=0; j<32; j++)
xen_features[i*32+j] = !!(fi.submap & 1<<j);
}
}
/*
* INITIAL C ENTRY POINT.
*/
......@@ -127,7 +149,9 @@ void start_kernel(start_info_t *si)
printk(" flags: 0x%x\n", (unsigned int)si->flags);
printk(" cmd_line: %s\n",
si->cmd_line ? (const char *)si->cmd_line : "NULL");
printk(" stack: %p-%p\n", stack, stack + 8192);
setup_xen_features();
/* Init memory management. */
init_mm();
......@@ -146,7 +170,7 @@ void start_kernel(start_info_t *si)
/* Init XenBus from a separate thread */
create_thread("init_xs", init_xs, NULL);
/* Everything initialised, start idle thread */
run_idle_thread();
}
......
......@@ -3,7 +3,7 @@ OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
. = 0xFFFFFFFF00000000;
. = 0xFFFFFFFF80000000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
......
......@@ -69,17 +69,27 @@ void idle_thread_fn(void *unused);
void dump_stack(struct thread *thread)
{
unsigned long *bottom = (unsigned long *)thread->stack + 2048;
unsigned long *pointer = (unsigned long *)thread->eps;
unsigned long *bottom = (unsigned long *)(thread->stack + 2*4*1024);
unsigned long *pointer = (unsigned long *)thread->sp;
int count;
if(thread == current)
{
#ifdef __i386__
asm("movl %%esp,%0"
: "=r"(pointer));
#else
asm("movq %%rsp,%0"
: "=r"(pointer));
#endif
}
printk("The stack for \"%s\"\n", thread->name);
for(count = 0; count < 15 && pointer < bottom; count ++)
for(count = 0; count < 25 && pointer < bottom; count ++)
{
printk("[0x%lx] 0x%lx\n", pointer, *pointer);
pointer++;
}
if(pointer < bottom) printk("Not the whole stack printed\n");
if(pointer < bottom) printk(" ... continues.\n");
}
#ifdef __i386__
......@@ -95,13 +105,29 @@ void dump_stack(struct thread *thread)
"1:\t" \
"popl %%ebp\n\t" \
"popfl" \
:"=m" (prev->eps),"=m" (prev->eip), \
:"=m" (prev->sp),"=m" (prev->ip), \
"=S" (esi),"=D" (edi) \
:"m" (next->eps),"m" (next->eip), \
:"m" (next->sp),"m" (next->ip), \
"2" (prev), "d" (next)); \
} while (0)
#elif __x86_64__
/* FIXME */
#define switch_threads(prev, next) do { \
unsigned long rsi,rdi; \
__asm__ __volatile__("pushfq\n\t" \
"pushq %%rbp\n\t" \
"movq %%rsp,%0\n\t" /* save RSP */ \
"movq %4,%%rsp\n\t" /* restore RSP */ \
"movq $1f,%1\n\t" /* save RIP */ \
"pushq %5\n\t" /* restore RIP */ \
"ret\n\t" \
"1:\t" \
"popq %%rbp\n\t" \
"popfq" \
:"=m" (prev->sp),"=m" (prev->ip), \
"=S" (rsi),"=D" (rdi) \
:"m" (next->sp),"m" (next->ip), \
"2" (prev), "d" (next)); \
} while (0)
#endif
void inline print_runqueue(void)
......@@ -151,17 +177,19 @@ void schedule(void)
local_irq_restore(flags);
/* Interrupting the switch is equivalent to having the next thread
inturrupted at the return instruction. And therefore at safe point. */
/* The thread switching only works for i386 at the moment */
#ifdef __i386__
if(prev != next) switch_threads(prev, next);
#endif
}
/* Gets run when a new thread is scheduled the first time ever,
defined in x86_[32/64].S */
extern void thread_starter(void);
void exit_thread(struct thread *thread)
void exit_thread(void)
{
unsigned long flags;
struct thread *thread = current;
printk("Thread \"%s\" exited.\n", thread->name);
local_irq_save(flags);
/* Remove from the thread list */
......@@ -174,6 +202,12 @@ void exit_thread(struct thread *thread)
schedule();
}
/* Pushes the specified value onto the stack of the specified thread */
static void stack_push(struct thread *thread, unsigned long value)
{
thread->sp -= sizeof(unsigned long);
*((unsigned long *)thread->sp) = value;
}
struct thread* create_thread(char *name, void (*function)(void *), void *data)
{
......@@ -187,23 +221,17 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data)
printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
thread->stack);
thread->eps = (unsigned long)thread->stack + 4096 * 2 - 4;
thread->sp = (unsigned long)thread->stack + 4096 * 2;
/* Save pointer to the thread on the stack, used by current macro */
*((unsigned long *)thread->stack) = (unsigned long)thread;
*((unsigned long *)thread->eps) = (unsigned long)thread;
thread->eps -= 4;
*((unsigned long *)thread->eps) = (unsigned long)data;
/* No return address */
thread->eps -= 4;
*((unsigned long *)thread->eps) = (unsigned long)exit_thread;
thread->eip = (unsigned long)function;
stack_push(thread, (unsigned long) function);
stack_push(thread, (unsigned long) data);
thread->ip = (unsigned long) thread_starter;
/* Not runable, not exited */
thread->flags = 0;
set_runnable(thread);
local_irq_save(flags);
if(idle_thread != NULL) {
list_add_tail(&thread->thread_list, &idle_thread->thread_list);
......@@ -213,7 +241,6 @@ struct thread* create_thread(char *name, void (*function)(void *), void *data)
BUG();
}
local_irq_restore(flags);
return thread;
}
......@@ -240,11 +267,19 @@ void idle_thread_fn(void *unused)
void run_idle_thread(void)
{
/* Switch stacks and run the thread */
#if defined(__i386__)
__asm__ __volatile__("mov %0,%%esp\n\t"
"push %1\n\t"
"ret"
:"=m" (idle_thread->eps)
:"m" (idle_thread->eip));
:"=m" (idle_thread->sp)
:"m" (idle_thread->ip));
#elif defined(__x86_64__)
__asm__ __volatile__("mov %0,%%rsp\n\t"
"push %1\n\t"
"ret"
:"=m" (idle_thread->sp)
:"m" (idle_thread->ip));
#endif
}
......
......@@ -286,3 +286,11 @@ ENTRY(spurious_interrupt_bug)
pushl $0
pushl $do_spurious_interrupt_bug
jmp do_exception
ENTRY(thread_starter)
popl %eax
popl %ebx
pushl %eax
call *%ebx
call exit_thread
#include <os.h>
#include <xen/features.h>
.section __xen_guest
.ascii "GUEST_OS=Mini-OS"
......@@ -65,10 +66,253 @@ shared_info:
hypercall_page:
.org 0x3000
/* Offsets into shared_info_t. */
#define evtchn_upcall_pending /* 0 */
#define evtchn_upcall_mask 1
NMI_MASK = 0x80000000
#define RDI 112
#define ORIG_RAX 120 /* + error_code */
#define EFLAGS 144
#define REST_SKIP 6*8
.macro SAVE_REST
subq $REST_SKIP,%rsp
# CFI_ADJUST_CFA_OFFSET REST_SKIP
movq %rbx,5*8(%rsp)
# CFI_REL_OFFSET rbx,5*8
movq %rbp,4*8(%rsp)
# CFI_REL_OFFSET rbp,4*8
movq %r12,3*8(%rsp)
# CFI_REL_OFFSET r12,3*8
movq %r13,2*8(%rsp)
# CFI_REL_OFFSET r13,2*8
movq %r14,1*8(%rsp)
# CFI_REL_OFFSET r14,1*8
movq %r15,(%rsp)
# CFI_REL_OFFSET r15,0*8
.endm
.macro RESTORE_REST
movq (%rsp),%r15
# CFI_RESTORE r15
movq 1*8(%rsp),%r14
# CFI_RESTORE r14
movq 2*8(%rsp),%r13
# CFI_RESTORE r13
movq 3*8(%rsp),%r12
# CFI_RESTORE r12
movq 4*8(%rsp),%rbp
# CFI_RESTORE rbp
movq 5*8(%rsp),%rbx
# CFI_RESTORE rbx
addq $REST_SKIP,%rsp
# CFI_ADJUST_CFA_OFFSET -(REST_SKIP)
.endm
#define ARG_SKIP 9*8
.macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0,skipr8910=0,skiprdx=0
.if \skipr11
.else
movq (%rsp),%r11
# CFI_RESTORE r11
.endif
.if \skipr8910
.else
movq 1*8(%rsp),%r10
# CFI_RESTORE r10
movq 2*8(%rsp),%r9
# CFI_RESTORE r9
movq 3*8(%rsp),%r8
# CFI_RESTORE r8
.endif
.if \skiprax
.else
movq 4*8(%rsp),%rax
# CFI_RESTORE rax
.endif
.if \skiprcx
.else
movq 5*8(%rsp),%rcx
# CFI_RESTORE rcx
.endif
.if \skiprdx
.else
movq 6*8(%rsp),%rdx
# CFI_RESTORE rdx
.endif
movq 7*8(%rsp),%rsi
# CFI_RESTORE rsi
movq 8*8(%rsp),%rdi
# CFI_RESTORE rdi
.if ARG_SKIP+\addskip > 0
addq $ARG_SKIP+\addskip,%rsp
# CFI_ADJUST_CFA_OFFSET -(ARG_SKIP+\addskip)
.endif
.endm
.macro HYPERVISOR_IRET flag
# testb $3,1*8(%rsp) /* Don't need to do that in Mini-os, as */
# jnz 2f /* there is no userspace? */
testl $NMI_MASK,2*8(%rsp)
jnz 2f
testb $1,(xen_features+XENFEAT_supervisor_mode_kernel)
jnz 1f
/* Direct iret to kernel space. Correct CS and SS. */
orb $3,1*8(%rsp)
orb $3,4*8(%rsp)
1: iretq
2: /* Slow iret via hypervisor. */
andl $~NMI_MASK, 16(%rsp)
pushq $\flag
jmp hypercall_page + (__HYPERVISOR_iret * 32)
.endm
/*
* Exception entry point. This expects an error code/orig_rax on the stack
* and the exception handler in %rax.
*/
ENTRY(error_entry)
# _frame RDI
/* rdi slot contains rax, oldrax contains error code */
cld
subq $14*8,%rsp
# CFI_ADJUST_CFA_OFFSET (14*8)
movq %rsi,13*8(%rsp)
# CFI_REL_OFFSET rsi,RSI
movq 14*8(%rsp),%rsi /* load rax from rdi slot */
movq %rdx,12*8(%rsp)
# CFI_REL_OFFSET rdx,RDX
movq %rcx,11*8(%rsp)
# CFI_REL_OFFSET rcx,RCX
movq %rsi,10*8(%rsp) /* store rax */
# CFI_REL_OFFSET rax,RAX
movq %r8, 9*8(%rsp)
# CFI_REL_OFFSET r8,R8
movq %r9, 8*8(%rsp)
# CFI_REL_OFFSET r9,R9
movq %r10,7*8(%rsp)
# CFI_REL_OFFSET r10,R10
movq %r11,6*8(%rsp)
# CFI_REL_OFFSET r11,R11
movq %rbx,5*8(%rsp)
# CFI_REL_OFFSET rbx,RBX
movq %rbp,4*8(%rsp)
# CFI_REL_OFFSET rbp,RBP
movq %r12,3*8(%rsp)
# CFI_REL_OFFSET r12,R12
movq %r13,2*8(%rsp)
# CFI_REL_OFFSET r13,R13
movq %r14,1*8(%rsp)
# CFI_REL_OFFSET r14,R14
movq %r15,(%rsp)
# CFI_REL_OFFSET r15,R15
#if 0
cmpl $__KERNEL_CS,CS(%rsp)
je error_kernelspace
#endif
error_call_handler:
movq %rdi, RDI(%rsp)
movq %rsp,%rdi
movq ORIG_RAX(%rsp),%rsi # get error code
movq $-1,ORIG_RAX(%rsp)
call *%rax
.macro zeroentry sym
# INTR_FRAME
movq (%rsp),%rcx
movq 8(%rsp),%r11
addq $0x10,%rsp /* skip rcx and r11 */
pushq $0 /* push error code/oldrax */
# CFI_ADJUST_CFA_OFFSET 8
pushq %rax /* push real oldrax to the rdi slot */
# CFI_ADJUST_CFA_OFFSET 8
leaq \sym(%rip),%rax
jmp error_entry
# CFI_ENDPROC
.endm
#define XEN_GET_VCPU_INFO(reg) movq HYPERVISOR_shared_info,reg
#define XEN_PUT_VCPU_INFO(reg)
#define XEN_PUT_VCPU_INFO_fixup
#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg)
#define XEN_LOCKED_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg)
#define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg)
#define XEN_BLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \
XEN_LOCKED_BLOCK_EVENTS(reg) ; \
XEN_PUT_VCPU_INFO(reg)
#define XEN_UNBLOCK_EVENTS(reg) XEN_GET_VCPU_INFO(reg) ; \
XEN_LOCKED_UNBLOCK_EVENTS(reg) ; \
XEN_PUT_VCPU_INFO(reg)
ENTRY(hypervisor_callback)
popq %rcx
popq %r11
iretq
zeroentry hypervisor_callback2
ENTRY(hypervisor_callback2)
movq %rdi, %rsp
11: movq %gs:8,%rax
incl %gs:0
cmovzq %rax,%rsp
pushq %rdi
call do_hypervisor_callback
popq %rsp
decl %gs:0
jmp error_exit
# ALIGN
restore_all_enable_events:
XEN_UNBLOCK_EVENTS(%rsi) # %rsi is already set up...
scrit: /**** START OF CRITICAL REGION ****/
XEN_TEST_PENDING(%rsi)
jnz 14f # process more events if necessary...
XEN_PUT_VCPU_INFO(%rsi)
RESTORE_ARGS 0,8,0
HYPERVISOR_IRET 0
14: XEN_LOCKED_BLOCK_EVENTS(%rsi)
XEN_PUT_VCPU_INFO(%rsi)
SAVE_REST
movq %rsp,%rdi # set the argument again
jmp 11b
ecrit: /**** END OF CRITICAL REGION ****/
retint_kernel:
retint_restore_args:
movl EFLAGS-REST_SKIP(%rsp), %eax
shr $9, %eax # EAX[0] == IRET_EFLAGS.IF
XEN_GET_VCPU_INFO(%rsi)
andb evtchn_upcall_mask(%rsi),%al
andb $1,%al # EAX[0] == IRET_EFLAGS.IF & event_mask
jnz restore_all_enable_events # != 0 => enable event delivery
XEN_PUT_VCPU_INFO(%rsi)
RESTORE_ARGS 0,8,0
HYPERVISOR_IRET 0
error_exit:
RESTORE_REST
/* cli */
XEN_BLOCK_EVENTS(%rsi)
jmp retint_kernel
ENTRY(failsafe_callback)
popq %rcx
......@@ -228,3 +472,12 @@ ENTRY(exception_table)
.quad do_alignment_check
.quad do_machine_check
.quad do_simd_coprocessor_error
ENTRY(thread_starter)
popq %rdi
popq %rbx
call *%rbx
call exit_thread
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