#include <arch/thread.h>
#include <string.h>
#include <arch_cpu.h>
#include <cpu.h>
#include <kernel.h>
#include <ksignal.h>
#include <interrupts.h>
#include <team.h>
#include <thread.h>
#include <vm/vm_types.h>
#include <vm/VMAddressSpace.h>
#include "paging/X86PagingStructures.h"
#include "paging/X86VMTranslationMap.h"
#include "x86_syscalls.h"
extern "C" void x86_return_to_userland(iframe* frame);
#ifndef __x86_64__
extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
#endif
static struct iframe*
find_previous_iframe(Thread* thread, addr_t frame)
{
while (frame >= thread->kernel_stack_base
&& frame < thread->kernel_stack_top) {
addr_t previousFrame = *(addr_t*)frame;
if ((previousFrame & ~(addr_t)IFRAME_TYPE_MASK) == 0) {
if (previousFrame == 0)
return NULL;
return (struct iframe*)frame;
}
frame = previousFrame;
}
return NULL;
}
static struct iframe*
get_previous_iframe(struct iframe* frame)
{
if (frame == NULL)
return NULL;
return find_previous_iframe(thread_get_current_thread(), frame->bp);
}
static struct iframe*
get_current_iframe(void)
{
return find_previous_iframe(thread_get_current_thread(),
x86_get_stack_frame());
}
struct iframe*
x86_get_user_iframe(void)
{
struct iframe* frame = get_current_iframe();
while (frame != NULL) {
if (IFRAME_IS_USER(frame))
return frame;
frame = get_previous_iframe(frame);
}
return NULL;
}
struct iframe*
x86_get_thread_user_iframe(Thread *thread)
{
if (thread->state == B_THREAD_RUNNING)
return NULL;
struct iframe* frame = find_previous_iframe(thread,
thread->arch_info.GetFramePointer());
while (frame != NULL) {
if (IFRAME_IS_USER(frame))
return frame;
frame = get_previous_iframe(frame);
}
return NULL;
}
struct iframe*
x86_get_current_iframe(void)
{
return get_current_iframe();
}
phys_addr_t
x86_next_page_directory(Thread* from, Thread* to)
{
VMAddressSpace* toAddressSpace = to->team->address_space;
if (from->team->address_space == toAddressSpace) {
return 0;
}
if (toAddressSpace == NULL)
toAddressSpace = VMAddressSpace::Kernel();
return static_cast<X86VMTranslationMap*>(toAddressSpace->TranslationMap())
->PagingStructures()->pgdir_phys;
}
void
x86_initial_return_to_userland(Thread* thread, iframe* frame)
{
disable_interrupts();
get_cpu_struct()->arch.tss.sp0 = thread->kernel_stack_top;
x86_set_tls_context(thread);
x86_set_syscall_stack(thread->kernel_stack_top);
x86_return_to_userland(frame);
}
status_t
arch_team_init_team_struct(Team* p, bool kernel)
{
return B_OK;
}
status_t
arch_thread_init_tls(Thread *thread)
{
thread->user_local_storage =
thread->user_stack_base + thread->user_stack_size;
return B_OK;
}
void
arch_thread_context_switch(Thread* from, Thread* to)
{
cpu_ent* cpuData = to->cpu;
cpuData->arch.tss.sp0 = to->kernel_stack_top;
x86_set_syscall_stack(to->kernel_stack_top);
if (to->user_local_storage != 0)
x86_set_tls_context(to);
X86PagingStructures* activePagingStructures
= cpuData->arch.active_paging_structures;
VMAddressSpace* toAddressSpace = to->team->address_space;
X86PagingStructures* toPagingStructures;
if (toAddressSpace != NULL
&& (toPagingStructures = static_cast<X86VMTranslationMap*>(
toAddressSpace->TranslationMap())->PagingStructures())
!= activePagingStructures) {
int cpu = cpuData->cpu_num;
activePagingStructures->active_on_cpus.ClearBitAtomic(cpu);
toPagingStructures->active_on_cpus.SetBitAtomic(cpu);
toPagingStructures->AddReference();
cpuData->arch.active_paging_structures = toPagingStructures;
addr_t newPageDirectory = toPagingStructures->pgdir_phys;
if (newPageDirectory != activePagingStructures->pgdir_phys)
x86_swap_pgdir(newPageDirectory);
activePagingStructures->RemoveReference();
}
#ifndef __x86_64__
gX86SwapFPUFunc(from->arch_info.fpu_state, to->arch_info.fpu_state);
#endif
x86_context_switch(&from->arch_info, &to->arch_info);
}
bool
arch_on_signal_stack(Thread *thread)
{
struct iframe* frame = get_current_iframe();
return frame->user_sp >= thread->signal_stack_base
&& frame->user_sp < thread->signal_stack_base
+ thread->signal_stack_size;
}
void
arch_store_fork_frame(struct arch_fork_arg* arg)
{
struct iframe* frame = x86_get_current_iframe();
arg->iframe = *frame;
arg->iframe.ax = 0;
}
void
arch_restore_fork_frame(struct arch_fork_arg* arg)
{
x86_initial_return_to_userland(thread_get_current_thread(), &arg->iframe);
}