// -*- C++ -*- (c) 2016 Jan Mrázek #pragma once #include #include #include // Syscall argument types #include #include #include #include #include #include #include #include namespace __dios { extern SysProxy *syscall_proxy; struct SetupBase { MemoryPool *pool; const _VM_Env *env; SysOpts opts; }; template< typename Context_ > struct Setup : SetupBase { using Context = Context_; typename Context::Process *proc1; Setup( const SetupBase &s ) : SetupBase( s ) {} }; struct Trap { enum RM { CONTINUE, RESCHEDULE, TRAMPOLINE } retmode; uint64_t keepflags; static const uint64_t kern = _VM_CF_KernelMode | _VM_CF_IgnoreLoop | _VM_CF_IgnoreCrit; __inline Trap( RM rm ) : retmode( rm ) { __sync_synchronize(); // for the sake of weakmem keepflags = __vm_ctl_flag( 0, kern ) & kern; if ( retmode == CONTINUE ) return; __dios_sync_this_frame(); } __inline ~Trap() { __vm_ctl_flag( kern & ~keepflags, 0 ); if ( retmode == RESCHEDULE ) __dios_reschedule(); if ( retmode == TRAMPOLINE ) { /* our parent is the __invoke of the sysenter lambda */ auto frame = __dios_this_frame(); auto parent = frame->parent; auto target = parent->parent; /* free the in-between frame */ __dios_unwind( frame, parent, target ); __dios_set_frame( target ); } } }; struct BaseContext : KObject { struct Process : KObject { SysProxy *syscall_proxy = nullptr; virtual ~Process() { if ( syscall_proxy ) __vm_obj_free( syscall_proxy ); } }; template< typename Ctx > struct SysEnter : SysProxy, KObject { #include #define SYSCALL( name, schedule, ret, arg ) \ \ __trapfn ret name arg noexcept override \ { \ Trap _trap( Trap::schedule ); \ auto ctx = reinterpret_cast< Ctx * >( __vm_ctl_get( _VM_CR_State ) ); \ return unpad( ctx, &Ctx::name, _1, _2, _3, _4, _5, _6 ); \ }; #include #undef SYSCALL #include }; template< typename Setup > void setup( Setup s ) { traceAlias< BaseContext >( "{BaseContext}" ); using Ctx = typename Setup::Context; /* FIXME use metadata and proc1->globals to fix this up */ s.proc1->syscall_proxy = syscall_proxy = new SysEnter< Ctx >(); if ( s.opts.empty() ) return; for ( const auto& opt : s.opts ) __dios_trace_f( "ERROR: Unused option %.*s:%.*s", int( opt.first.size() ), opt.first.begin(), int( opt.second.size() ), opt.second.begin() ); __dios_fault( _DiOS_F_Config, "Unused options" ); } virtual void reschedule() = 0; virtual Process *make_process( Process * ) = 0; void finalize() {} Process *findProcess( pid_t ) { return nullptr; } void getHelp( ArrayMap< std::string_view, HelpOption >& ) {} #include #define SYSCALL( name, schedule, ret, arg ) ret name arg; #include #undef SYSCALL #include }; }