diff --git a/minix/include/minix/sef.h b/minix/include/minix/sef.h index 8da2bd8a7..28a63b903 100644 --- a/minix/include/minix/sef.h +++ b/minix/include/minix/sef.h @@ -11,6 +11,8 @@ int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr); endpoint_t sef_self(void); void sef_cancel(void); void __dead sef_exit(int status); +int sef_getrndseed (void); +int sef_munmap(void *addrstart, vir_bytes len, int type); #define sef_receive(src, m_ptr) sef_receive_status(src, m_ptr, NULL) /* SEF global definitions. */ @@ -46,6 +48,7 @@ typedef struct { void* init_buff_start; void* init_buff_cleanup_start; size_t init_buff_len; + int copy_flags; } sef_init_info_t; /* Callback type definitions. */ @@ -65,6 +68,10 @@ int sef_cb_init_response_null(message *m_ptr); int sef_cb_init_fail(int type, sef_init_info_t *info); int sef_cb_init_reset(int type, sef_init_info_t *info); int sef_cb_init_crash(int type, sef_init_info_t *info); +int sef_cb_init_timeout(int type, sef_init_info_t *info); +int sef_cb_init_identity_state_transfer(int type, sef_init_info_t *info); +int sef_cb_init_lu_identity_as_restart(int type, sef_init_info_t *info); +int sef_cb_init_lu_generic(int type, sef_init_info_t *info); int sef_cb_init_response_rs_reply(message *m_ptr); /* Macros for predefined callback implementations. */ @@ -175,10 +182,12 @@ int sef_cb_lu_response_null(message *m_ptr); int sef_cb_lu_prepare_always_ready(int state); int sef_cb_lu_prepare_never_ready(int state); int sef_cb_lu_prepare_crash(int state); +int sef_cb_lu_prepare_eval(int state); int sef_cb_lu_state_isvalid_standard(int state, int flags); int sef_cb_lu_state_isvalid_workfree(int state, int flags); int sef_cb_lu_state_isvalid_workfree_self(int state, int flags); int sef_cb_lu_state_isvalid_generic(int state, int flags); +void sef_cb_lu_state_dump_eval(int state); int sef_cb_lu_response_rs_reply(message *m_ptr); /* Macros for predefined callback implementations. */ @@ -316,6 +325,49 @@ void sef_setcb_gcov(sef_cb_gcov_t cb); /* Fault injection tool support. */ #define SEF_FI_ALLOW_EDFI 1 +/*===========================================================================* + * SEF State Transfer * + *===========================================================================*/ +#define SEF_LU_STATE_EVAL_MAX_LEN 512 + +/* State transfer helpers. */ +int sef_copy_state_region_ctl(sef_init_info_t *info, + vir_bytes *src_address, vir_bytes *dst_address); +int sef_copy_state_region(sef_init_info_t *info, + vir_bytes address, size_t size, vir_bytes dst_address); +int sef_st_state_transfer(sef_init_info_t *info); + +/* Callback prototypes to be passed to the State Transfer framwork. */ +int sef_old_state_table_lookup(sef_init_info_t *info, void *addr); +int sef_old_state_table_lookup_opaque(void *info_opaque, void *addr); +int sef_copy_state_region_opaque(void *info_opaque, uint32_t address, + size_t size, uint32_t dst_address); + +/* Debug. */ +#define SEF_ST_DEBUG_DEFAULT 0 + +#ifndef SEF_ST_DEBUG +#define SEF_ST_DEBUG SEF_ST_DEBUG_DEFAULT +#endif + +/*===========================================================================* + * SEF LLVM * + *===========================================================================*/ +/* LLVM helpers. */ +int sef_llvm_magic_enabled(void); +int sef_llvm_real_brk(char *newbrk); +int sef_llvm_state_cleanup(void); +void sef_llvm_dump_eval(char *expr); +int sef_llvm_eval_bool(char *expr, char *result); +void *sef_llvm_state_table_addr(void); +size_t sef_llvm_state_table_size(void); +void sef_llvm_stack_refs_save(char *stack_buff); +void sef_llvm_stack_refs_restore(char *stack_buff); +int sef_llvm_state_transfer(sef_init_info_t *info); + +int sef_llvm_ltckpt_enabled(void); +int sef_llvm_get_ltckpt_offset(void); + #if !defined(USE_LIVEUPDATE) #undef INTERCEPT_SEF_LU_REQUESTS #undef SEF_LU_DEBUG diff --git a/minix/lib/libsys/Makefile b/minix/lib/libsys/Makefile index a73c58c89..cb6874f5b 100644 --- a/minix/lib/libsys/Makefile +++ b/minix/lib/libsys/Makefile @@ -43,8 +43,10 @@ SRCS+= \ sef_fi.c \ sef_init.c \ sef_liveupdate.c \ + sef_llvm.c \ sef_ping.c \ sef_signal.c \ + sef_st.c \ sqrt_approx.c \ srv_fork.c \ srv_kill.c \ @@ -139,5 +141,6 @@ CPPFLAGS+= -DUSE_SYSDEBUG .endif CPPFLAGS.sched_start.c+= -I${NETBSDSRCDIR}/minix +CPPFLAGS.sef_st.c+= -I${NETBSDSRCDIR}/minix .include diff --git a/minix/lib/libsys/sef.c b/minix/lib/libsys/sef.c index d61639dd0..9d385f9ca 100644 --- a/minix/lib/libsys/sef.c +++ b/minix/lib/libsys/sef.c @@ -1,6 +1,9 @@ #include "syslib.h" #include #include +#include +#include +#include #include #include #include @@ -10,13 +13,18 @@ #define SEF_SELF_NAME_MAXLEN 20 char sef_self_name[SEF_SELF_NAME_MAXLEN]; endpoint_t sef_self_endpoint = NONE; +endpoint_t sef_self_proc_nr; int sef_self_priv_flags; -int sef_self_first_receive_done; +int sef_self_init_flags; int sef_self_receiving; +/* Extern variables. */ +EXTERN int sef_lu_state; +EXTERN int __sef_st_before_receive_enabled; + /* Debug. */ #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG -#define SEF_DEBUG_HEADER_MAXLEN 32 +#define SEF_DEBUG_HEADER_MAXLEN 50 static int sef_debug_init = 0; static time_t sef_debug_boottime = 0; static u32_t sef_debug_system_hz = 0; @@ -41,6 +49,9 @@ EXTERN int do_sef_lu_request(message *m_ptr); /* SEF Signal prototypes. */ EXTERN int do_sef_signal_request(message *m_ptr); +/* State transfer prototypes. */ +EXTERN void do_sef_st_before_receive(void); + /* SEF GCOV prototypes. */ #ifdef USE_COVERAGE EXTERN int do_sef_gcov_request(message *m_ptr); @@ -67,8 +78,15 @@ void sef_startup() if ( r != OK) { panic("sef_startup: sys_whoami failed: %d\n", r); } + + sef_self_proc_nr = _ENDPOINT_P(sef_self_endpoint); sef_self_priv_flags = priv_flags; + sef_self_init_flags = init_flags; + sef_lu_state = SEF_LU_STATE_NULL; old_endpoint = NONE; + if(init_flags & SEF_LU_NOMMAP) { + sys_upd_flags |= SF_VM_NOMMAP; + } #if USE_LIVEUPDATE /* RS may wake up with the wrong endpoint, perfom the update in that case. */ @@ -117,8 +135,9 @@ void sef_startup() #endif /* (Re)initialize SEF variables. */ - sef_self_first_receive_done = FALSE; sef_self_priv_flags = priv_flags; + sef_self_init_flags = init_flags; + sef_lu_state = SEF_LU_STATE_NULL; } /*===========================================================================* @@ -140,13 +159,19 @@ int sef_receive_status(endpoint_t src, message *m_ptr, int *status_ptr) #if INTERCEPT_SEF_LU_REQUESTS /* Handle SEF Live update before receive events. */ - do_sef_lu_before_receive(); + if(sef_lu_state != SEF_LU_STATE_NULL) { + do_sef_lu_before_receive(); + } + + /* Handle State transfer before receive events. */ + if(__sef_st_before_receive_enabled) { + do_sef_st_before_receive(); + } #endif /* Receive and return in case of error. */ r = ipc_receive(src, m_ptr, &status); if(status_ptr) *status_ptr = status; - if(!sef_self_first_receive_done) sef_self_first_receive_done = TRUE; if(r != OK) { return r; } @@ -271,6 +296,16 @@ void sef_cancel(void) sef_self_receiving = FALSE; } +/*===========================================================================* + * sef_getrndseed * + *===========================================================================*/ +int sef_getrndseed(void) +{ + clock_t uptime; + sys_times(SELF, NULL, NULL, &uptime, NULL); + return (int) uptime; +} + /*===========================================================================* * sef_exit * *===========================================================================*/ @@ -293,6 +328,24 @@ __weak_alias(_exit, sef_exit); __weak_alias(__exit, sef_exit); #endif +/*===========================================================================* + * sef_munmap * + *===========================================================================*/ +int sef_munmap(void *addrstart, vir_bytes len, int type) +{ +/* System services use a special version of munmap() to control implicit + * munmaps as startup and allow for asynchronous mnmap for VM. + */ + message m; + m.m_type = type; + m.VMUM_ADDR = addrstart; + m.VMUM_LEN = len; + if(sef_self_endpoint == VM_PROC_NR) { + return asynsend3(SELF, &m, AMF_NOREPLY); + } + return _syscall(VM_PROC_NR, type, &m); +} + #if SEF_INIT_DEBUG || SEF_LU_DEBUG || SEF_PING_DEBUG || SEF_SIGNAL_DEBUG /*===========================================================================* * sef_debug_refresh_params * diff --git a/minix/lib/libsys/sef_init.c b/minix/lib/libsys/sef_init.c index 23cf5cf7d..876e35f45 100644 --- a/minix/lib/libsys/sef_init.c +++ b/minix/lib/libsys/sef_init.c @@ -27,6 +27,11 @@ EXTERN char* sef_debug_header(void); /* Information about SELF. */ EXTERN endpoint_t sef_self_endpoint; EXTERN endpoint_t sef_self_priv_flags; +EXTERN endpoint_t sef_self_init_flags; + +#ifndef ST_STACK_REFS_BUFF_SIZE +#define ST_STACK_REFS_BUFF_SIZE 1024 +#endif /*===========================================================================* * process_init * @@ -34,33 +39,71 @@ EXTERN endpoint_t sef_self_priv_flags; static int process_init(int type, sef_init_info_t *info) { /* Process initialization. */ - int r, result; + int r, result, debug_result_found, is_def_cb; + cp_grant_id_t gid; message m; /* Debug. */ #if SEF_INIT_DEBUG sef_init_debug_begin(); - sef_init_dprint("%s. Got a SEF Init request of type: %d. About to init.\n", - sef_debug_header(), type); + sef_init_dprint("%s. Got a SEF Init request of type %d, flags 0x%08x, rproctab_gid %d, ep %d, old ep %d, restarts %d. About to init.\n", + sef_debug_header(), type, info->flags, info->rproctab_gid, info->endpoint, info->old_endpoint, info->restarts); sef_init_debug_end(); #endif - /* Let the callback code handle the specific initialization type. */ - switch(type) { - case SEF_INIT_FRESH: - result = sef_init_cbs.sef_cb_init_fresh(type, info); - break; - case SEF_INIT_LU: - result = sef_init_cbs.sef_cb_init_lu(type, info); - break; - case SEF_INIT_RESTART: - result = sef_init_cbs.sef_cb_init_restart(type, info); - break; + /* Clear any IPC filter. */ + r = sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0); + assert(r == OK); - default: - /* Not a valid SEF init type. */ - result = EINVAL; - break; + /* Create grant for state transfer. */ + gid = cpf_grant_direct(sef_self_endpoint, 0, ULONG_MAX, CPF_READ); + if(!GRANT_VALID(gid)) { + panic("unable to create grant for state transfer"); + } + if(gid != SEF_STATE_TRANSFER_GID) { + panic("bad state transfer gid"); + } + + /* If debug init flags are allowed, process them first. */ + debug_result_found = 0; + if(SEF_INIT_ALLOW_DEBUG_INIT_FLAGS) { + int flags = info->flags; + if(flags & SEF_INIT_CRASH) { + result = sef_cb_init_crash(type, info); + debug_result_found = 1; + } + else if(flags & SEF_INIT_FAIL) { + result = sef_cb_init_fail(type, info); + debug_result_found = 1; + } + else if(flags & SEF_INIT_TIMEOUT) { + result = sef_cb_init_timeout(type, info); + debug_result_found = 1; + } + } + + if(!debug_result_found) { + /* Let the callback code handle the specific initialization type. */ + is_def_cb = info->flags & SEF_INIT_DEFCB; + switch(type) { + case SEF_INIT_FRESH: + result = is_def_cb ? SEF_CB_INIT_FRESH_DEFAULT(type, info) + : sef_init_cbs.sef_cb_init_fresh(type, info); + break; + case SEF_INIT_LU: + result = is_def_cb ? SEF_CB_INIT_LU_DEFAULT(type, info) + : sef_init_cbs.sef_cb_init_lu(type, info); + break; + case SEF_INIT_RESTART: + result = is_def_cb ? SEF_CB_INIT_RESTART_DEFAULT(type, info) + : sef_init_cbs.sef_cb_init_restart(type, info); + break; + + default: + /* Not a valid SEF init type. */ + result = EINVAL; + break; + } } memset(&m, 0, sizeof(m)); @@ -68,6 +111,31 @@ static int process_init(int type, sef_init_info_t *info) m.m_type = RS_INIT; m.m_rs_init.result = result; r = sef_init_cbs.sef_cb_init_response(&m); + if (r != OK) { + return r; + } + + /* See if we need to unmap the initialization buffer. */ + if(info->init_buff_cleanup_start) { + void *addrstart = info->init_buff_cleanup_start; + size_t len = info->init_buff_len - (size_t)((char*)info->init_buff_cleanup_start - (char*)info->init_buff_start); + r = sef_munmap(addrstart, len, VM_MUNMAP); + if(r != OK) { + printf("process_init: warning: munmap failed for init buffer\n"); + } + } + + /* Tell the kernel about the grant table. */ + cpf_reload(); + + /* Tell the kernel about the senda table. */ + r = senda_reload(); + if(r != OK) { + printf("process_init: warning: senda_reload failed\n"); + } + + /* Tell the kernel about the state table. */ + sys_statectl(SYS_STATE_SET_STATE_TABLE, sef_llvm_state_table_addr(), 0); return r; } @@ -81,6 +149,7 @@ int do_sef_rs_init(endpoint_t old_endpoint) int r; int type; sef_init_info_t info; + memset(&info, 0, sizeof(info)); /* Get init parameters from SEF. */ type = SEF_INIT_FRESH; @@ -90,9 +159,23 @@ int do_sef_rs_init(endpoint_t old_endpoint) else if(sef_self_priv_flags & RST_SYS_PROC) { type = SEF_INIT_RESTART; } - info.rproctab_gid = -1; + info.flags = sef_self_init_flags; + info.rproctab_gid = GRANT_INVALID; info.endpoint = sef_self_endpoint; info.old_endpoint = old_endpoint; + info.restarts = 0; + + /* Get init buffer details from VM. */ + info.init_buff_start = NULL; + info.init_buff_len = 0; + if(type != SEF_INIT_FRESH) { + r = vm_memctl(RS_PROC_NR, VM_RS_MEM_GET_PREALLOC_MAP, + &info.init_buff_start, &info.init_buff_len); + if(r != OK) { + printf("do_sef_rs_init: vm_memctl failed\n"); + } + } + info.init_buff_cleanup_start = info.init_buff_start; /* Peform initialization. */ r = process_init(type, &info); @@ -109,12 +192,18 @@ int do_sef_init_request(message *m_ptr) int r; int type; sef_init_info_t info; + memset(&info, 0, sizeof(info)); /* Get init parameters from message. */ type = m_ptr->m_rs_init.type; + info.flags = m_ptr->m_rs_init.flags; info.rproctab_gid = m_ptr->m_rs_init.rproctab_gid; info.endpoint = sef_self_endpoint; info.old_endpoint = m_ptr->m_rs_init.old_endpoint; + info.restarts = m_ptr->m_rs_init.restarts; + info.init_buff_start = (void*) m_ptr->m_rs_init.buff_addr; + info.init_buff_cleanup_start = info.init_buff_start; + info.init_buff_len = m_ptr->m_rs_init.buff_len; /* Peform initialization. */ r = process_init(type, &info); @@ -202,6 +291,136 @@ int sef_cb_init_crash(int UNUSED(type), sef_init_info_t *UNUSED(info)) return OK; } +/*===========================================================================* + * sef_cb_init_timeout * + *===========================================================================*/ +int sef_cb_init_timeout(int UNUSED(type), sef_init_info_t *UNUSED(info)) +{ + message m; + int status; + + printf("Simulating a timeout at initialization time...\n"); + + ipc_receive(IDLE, &m, &status); + + return EBADCALL; +} + +/*===========================================================================* + * sef_cb_init_identity_state_transfer * + *===========================================================================*/ +int sef_cb_init_identity_state_transfer(int type, sef_init_info_t *info) +{ + extern char *_brksize; + extern char *_etext; + int r; + char *old_brksize, *new_brksize; + char stack_buff[ST_STACK_REFS_BUFF_SIZE]; + vir_bytes data_start; + size_t size; + + /* Identity state transfer is for crash recovery and self update only. */ + if(type != SEF_INIT_RESTART && (type != SEF_INIT_LU || !(info->flags & SEF_LU_SELF))) { + printf("sef_cb_init_identity_state_transfer: state transfer failed\n"); + return ENOSYS; + } + + /* Save stack refs. */ + sef_llvm_stack_refs_save(stack_buff); + + old_brksize = _brksize; + data_start = (vir_bytes)&_etext; +#if SEF_ST_DEBUG + printf("sef_cb_init_identity_state_transfer: _brksize = 0x%08x, _etext = 0x%08x, data_start = 0x%08x\n", + _brksize, &_etext, data_start); +#endif + + /* Transfer data. */ + size = (size_t)(_brksize - data_start); + r = sef_copy_state_region(info, data_start, size, data_start); + if(r != OK) { + printf("sef_cb_init_identity_state_transfer: data transfer failed\n"); + return r; + } + + new_brksize = _brksize; + + /* Transfer heap if necessary. */ + if(old_brksize != new_brksize) { + +#if SEF_ST_DEBUG + printf("sef_cb_init_identity_state_transfer: brk() for new_brksize = 0x%08x\n", + new_brksize); +#endif + + /* Extend heap first. */ + _brksize = old_brksize; + r = sef_llvm_real_brk(new_brksize); + if(r != OK) { + printf("sef_cb_init_identity_state_transfer: brk failed\n"); + return EFAULT; + } + + /* Transfer state on the heap. */ + assert(_brksize == new_brksize); + size = (size_t)(_brksize - old_brksize); + r = sef_copy_state_region(info, (vir_bytes) old_brksize, size, + (vir_bytes) old_brksize); + if(r != OK) { + printf("sef_cb_init_identity_state_transfer: extended heap transfer failed\n"); + return r; + } + } + + /* Restore stack refs. */ + sef_llvm_stack_refs_restore(stack_buff); + + return OK; +} + +/*===========================================================================* + * sef_cb_init_lu_identity_as_restart * + *===========================================================================*/ +int sef_cb_init_lu_identity_as_restart(int type, sef_init_info_t *info) +{ + /* Can only handle live update. */ + if(type != SEF_INIT_LU) { + printf("sef_cb_init_lu_identity_as_restart: init failed\n"); + return ENOSYS; + } + + /* Resort to restart callback only for identity updates, ignore other cases. */ + if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { + if(info->flags & (SEF_INIT_DEFCB|SEF_INIT_SCRIPT_RESTART)) { + /* Use default callback when requested or when using a script.*/ + return SEF_CB_INIT_RESTART_DEFAULT(type, info); + } + return sef_init_cbs.sef_cb_init_restart(type, info); + } + + return ENOSYS; +} + +/*===========================================================================* + * sef_cb_init_lu_generic * + *===========================================================================*/ +int sef_cb_init_lu_generic(int type, sef_init_info_t *info) +{ + /* Can only handle live update. */ + if(type != SEF_INIT_LU) { + printf("sef_cb_init_lu_generic: init failed\n"); + return ENOSYS; + } + + /* Resort to restart callback for identity updates. */ + if(SEF_LU_IS_IDENTITY_UPDATE(info->flags)) { + return sef_cb_init_lu_identity_as_restart(type, info); + } + + /* Perform state transfer updates in all the other cases. */ + return sef_st_state_transfer(info); +} + /*===========================================================================* * sef_cb_init_response_rs_reply * *===========================================================================*/ diff --git a/minix/lib/libsys/sef_liveupdate.c b/minix/lib/libsys/sef_liveupdate.c index 537f9a98c..5becf0c2a 100644 --- a/minix/lib/libsys/sef_liveupdate.c +++ b/minix/lib/libsys/sef_liveupdate.c @@ -1,13 +1,14 @@ #include "syslib.h" #include #include +#include /* SEF Live update variables. */ -static int sef_lu_state; +int sef_lu_state; +int __sef_st_before_receive_enabled; +char sef_lu_state_eval[SEF_LU_STATE_EVAL_MAX_LEN]; static int sef_lu_flags; -extern __attribute__((weak)) int st_do_state_cleanup(void); - /* SEF Live update callbacks. */ static struct sef_lu_cbs { sef_cb_lu_prepare_t sef_cb_lu_prepare; @@ -31,6 +32,9 @@ int do_sef_lu_request(message *m_ptr); /* SEF Live update helpers. */ static void sef_lu_ready(int result); +static void sef_lu_state_change(int state, int flags); +int sef_lu_handle_state_data(endpoint_t src_e, int state, + cp_grant_id_t state_data_gid); /* Debug. */ EXTERN char* sef_debug_header(void); @@ -38,7 +42,6 @@ static int sef_lu_debug_cycle = 0; /* Information about SELF. */ EXTERN endpoint_t sef_self_endpoint; -EXTERN int sef_self_first_receive_done; /*===========================================================================* * do_sef_lu_before_receive * @@ -48,15 +51,7 @@ void do_sef_lu_before_receive(void) /* Handle SEF Live update before receive events. */ int r; - /* Initialize on first receive. */ - if(!sef_self_first_receive_done) { - sef_lu_state = SEF_LU_STATE_NULL; - } - - /* Nothing to do if we are not preparing for a live update. */ - if(sef_lu_state == SEF_LU_STATE_NULL) { - return; - } + assert(sef_lu_state != SEF_LU_STATE_NULL); /* Debug. */ #if SEF_LU_DEBUG @@ -68,15 +63,29 @@ void do_sef_lu_before_receive(void) sef_lu_debug_end(); #endif - /* Let the callback code handle the event. - * For SEF_LU_STATE_WORK_FREE, we're always ready, tell immediately. + /* Check the state. For SEF_LU_STATE_WORK_FREE/SEF_LU_STATE_UNREACHABLE, + * we are always/never ready. For SEF_LU_STATE_EVAL, evaluate the expression. + * For other states, let the callback code handle the event. */ - r = OK; - if(sef_lu_state != SEF_LU_STATE_WORK_FREE) { - r = sef_lu_cbs.sef_cb_lu_prepare(sef_lu_state); + switch(sef_lu_state) { + case SEF_LU_STATE_WORK_FREE: + r = OK; + break; + case SEF_LU_STATE_UNREACHABLE: + r = sef_cb_lu_prepare_never_ready(sef_lu_state); + break; + case SEF_LU_STATE_PREPARE_CRASH: + r = sef_cb_lu_prepare_crash(sef_lu_state); + break; + case SEF_LU_STATE_EVAL: + r = sef_cb_lu_prepare_eval(sef_lu_state); + break; + default: + r = sef_lu_cbs.sef_cb_lu_prepare(sef_lu_state); + break; } - if(r == OK) { - sef_lu_ready(OK); + if(r == OK || r != ENOTREADY) { + sef_lu_ready(r); } } @@ -86,15 +95,25 @@ void do_sef_lu_before_receive(void) int do_sef_lu_request(message *m_ptr) { /* Handle a SEF Live update request. */ - int state, old_state, flags, is_valid_state; + int r, state, flags, is_valid_state; + cp_grant_id_t rs_state_data_gid; sef_lu_debug_cycle = 0; - old_state = sef_lu_state; state = m_ptr->m_rs_update.state; flags = m_ptr->m_rs_update.flags; + rs_state_data_gid = m_ptr->m_rs_update.state_data_gid; - /* Deal with prepare cancel requests first. */ - is_valid_state = (state == SEF_LU_STATE_NULL); + /* Deal with prepare cancel requests first, where no reply is requested. */ + if(state == SEF_LU_STATE_NULL) { + sef_lu_state_change(SEF_LU_STATE_NULL, 0); + return OK; + } + + /* Check if we are already busy. */ + if(sef_lu_state != SEF_LU_STATE_NULL) { + sef_lu_ready(EBUSY); + return OK; + } /* Otherwise only accept live update requests with a valid state. */ is_valid_state = SEF_LU_ALWAYS_ALLOW_DEBUG_STATES && SEF_LU_STATE_IS_DEBUG(state); @@ -106,19 +125,20 @@ int do_sef_lu_request(message *m_ptr) else { sef_lu_ready(EINVAL); } + return OK; } - else { - /* Set the new live update state. */ - sef_lu_state = state; - /* If the live update state changed, let the callback code - * handle the rest. - */ - if(old_state != sef_lu_state) { - sef_lu_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state); - } + /* Handle additional state data (if any). */ + r = sef_lu_handle_state_data(m_ptr->m_source, state, rs_state_data_gid); + if(r != OK) { + sef_lu_ready(r); + return OK; } + /* Set the new live update state. */ + sef_lu_state_change(state, flags); + + /* Return OK not to let anybody else intercept the request. */ return(OK); } @@ -129,7 +149,7 @@ int do_sef_lu_request(message *m_ptr) static void sef_lu_ready(int result) { message m; - int old_state, r=EINVAL; + int r=EINVAL; #if SEF_LU_DEBUG sef_lu_debug_begin(); @@ -143,10 +163,7 @@ static void sef_lu_ready(int result) * any state that must be carried over to the new version. */ if(result == OK) { - /* st_do_state_cleanup is a weak symbol. It is only defined if - * we are linked against magic */ - if (st_do_state_cleanup) - r = st_do_state_cleanup(); + r = sef_llvm_state_cleanup(); if(r == OK) { r = sef_lu_cbs.sef_cb_lu_state_save(sef_lu_state, sef_lu_flags); } @@ -178,13 +195,126 @@ static void sef_lu_ready(int result) /* Something went wrong. Update was aborted and we didn't get updated. * Restore things back to normal and continue executing. */ + sef_lu_state_change(SEF_LU_STATE_NULL, 0); +} + +/*===========================================================================* + * sef_lu_state_change * + *===========================================================================*/ +static void sef_lu_state_change(int state, int flags) +{ + int r, old_state; + old_state = sef_lu_state; - sef_lu_state = SEF_LU_STATE_NULL; + sef_lu_state = state; + sef_lu_flags = flags; + if(sef_lu_state == SEF_LU_STATE_NULL) { + r = sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0); + assert(r == OK); + } if(old_state != sef_lu_state) { sef_lu_cbs.sef_cb_lu_state_changed(old_state, sef_lu_state); } } +/*===========================================================================* + * sef_lu_handle_state_data * + *===========================================================================*/ +int sef_lu_handle_state_data(endpoint_t src_e, + int state, cp_grant_id_t state_data_gid) +{ + int r; + struct rs_state_data rs_state_data; + + if(state_data_gid == GRANT_INVALID) { + /* SEF_LU_STATE_EVAL requires an eval expression. */ + return state == SEF_LU_STATE_EVAL ? EINVAL : OK; + } + + r = sys_safecopyfrom(src_e, state_data_gid, 0, + (vir_bytes) &rs_state_data, sizeof(rs_state_data)); + if(r != OK) { + return r; + } + if(rs_state_data.size != sizeof(rs_state_data)) { + return E2BIG; + } + if(state == SEF_LU_STATE_EVAL) { + if(rs_state_data.eval_addr && rs_state_data.eval_len) { + if(rs_state_data.eval_len >= SEF_LU_STATE_EVAL_MAX_LEN) { + return E2BIG; + } + r = sys_safecopyfrom(src_e, rs_state_data.eval_gid, 0, + (vir_bytes) sef_lu_state_eval, rs_state_data.eval_len); + if(r != OK) { + return r; + } + sef_lu_state_eval[rs_state_data.eval_len] = '\0'; + r = sef_cb_lu_prepare_eval(SEF_LU_STATE_EVAL); + if(r != OK && r != ENOTREADY) { + /* State expression could not be evaluated correctly. */ + return EINVAL; + } + } + else { + /* SEF_LU_STATE_EVAL requires a valid eval expression. */ + return EINVAL; + } + } + if(rs_state_data.ipcf_els && rs_state_data.ipcf_els_size) { + ipc_filter_el_t ipc_filter[IPCF_MAX_ELEMENTS]; + size_t ipc_filter_size = sizeof(ipc_filter); + int num_ipc_filters = rs_state_data.ipcf_els_size / ipc_filter_size; + int i; + if(rs_state_data.ipcf_els_size % ipc_filter_size) { + return E2BIG; + } + r = OK; + for(i=0;i +#include +#include + +/* Stack refs definitions. */ +extern char **environ; +extern char **env_argv; +extern int env_argc; + +#define sef_llvm_stack_refs_save_one(P, T, R) { *((T*)P) = R; P += sizeof(T); } +#define sef_llvm_stack_refs_restore_one(P, T, R) { R = *((T*)P); P += sizeof(T); } + +/*===========================================================================* + * sef_llvm_magic_enabled * + *===========================================================================*/ +int sef_llvm_magic_enabled() +{ + extern void __attribute__((weak)) magic_init(); + if (!magic_init) + return 0; + return 1; +} + +/*===========================================================================* + * sef_llvm_real_brk * + *===========================================================================*/ +int sef_llvm_real_brk(char *newbrk) +{ + extern int __attribute__((weak)) _magic_real_brk(char*); + if (!_magic_real_brk) + return brk(newbrk); + return _magic_real_brk(newbrk); +} + +/*===========================================================================* + * sef_llvm_state_cleanup * + *===========================================================================*/ +int sef_llvm_state_cleanup() +{ + return OK; +} + +/*===========================================================================* + * sef_llvm_dump_eval * + *===========================================================================*/ +void sef_llvm_dump_eval(char *expr) +{ + extern void __attribute__((weak)) _magic_dump_eval_bool(char*); + if (!_magic_dump_eval_bool) + return; + return _magic_dump_eval_bool(expr); +} + +/*===========================================================================* + * sef_llvm_eval_bool * + *===========================================================================*/ +int sef_llvm_eval_bool(char *expr, char *result) +{ + extern int __attribute__((weak)) magic_eval_bool(char*, char*); + if (!magic_eval_bool) + return 0; + return magic_eval_bool(expr, result); +} + +/*===========================================================================* + * sef_llvm_state_table_addr * + *===========================================================================*/ +void *sef_llvm_state_table_addr() +{ + extern void* __attribute__((weak)) _magic_vars_addr(void); + if (!_magic_vars_addr) + return NULL; + return _magic_vars_addr(); +} + +/*===========================================================================* + * sef_llvm_state_table_size * + *===========================================================================*/ +size_t sef_llvm_state_table_size() +{ + extern size_t __attribute__((weak)) _magic_vars_size(void); + if (!_magic_vars_size) + return 0; + return _magic_vars_size(); +} + +/*===========================================================================* + * sef_llvm_stack_refs_save * + *===========================================================================*/ +void sef_llvm_stack_refs_save(char *stack_buff) +{ + extern void __attribute__((weak)) st_stack_refs_save_restore(char*, int); + char *p = stack_buff; + + sef_llvm_stack_refs_save_one(p, char**, environ); + sef_llvm_stack_refs_save_one(p, char**, env_argv); + sef_llvm_stack_refs_save_one(p, int, env_argc); + + if (st_stack_refs_save_restore) + st_stack_refs_save_restore(p, 1); +} + +/*===========================================================================* + * sef_llvm_stack_refs_restore * + *===========================================================================*/ +void sef_llvm_stack_refs_restore(char *stack_buff) +{ + extern void __attribute__((weak)) st_stack_refs_save_restore(char*, int); + char *p = stack_buff; + + sef_llvm_stack_refs_restore_one(p, char**, environ); + sef_llvm_stack_refs_restore_one(p, char**, env_argv); + sef_llvm_stack_refs_restore_one(p, int, env_argc); + + if (st_stack_refs_save_restore) + st_stack_refs_save_restore(p, 0); +} + +/*===========================================================================* + * sef_llvm_state_transfer * + *===========================================================================*/ +int sef_llvm_state_transfer(sef_init_info_t *info) +{ + extern int __attribute__((weak)) _magic_state_transfer(sef_init_info_t *info); + if (!_magic_state_transfer) + return ENOSYS; + return _magic_state_transfer(info); +} + +/*===========================================================================* + * sef_llvm_ltckpt_enabled * + *===========================================================================*/ +int sef_llvm_ltckpt_enabled() +{ + extern int __attribute__((weak)) ltckpt_get_offset(); + if (!ltckpt_get_offset) + return 0; + return 1; +} + +/*===========================================================================* + * sef_llvm_ltckpt_get_offset * + *===========================================================================*/ +int sef_llvm_get_ltckpt_offset() +{ + extern int __attribute__((weak)) ltckpt_get_offset(); + if (!ltckpt_get_offset) + return 0; + return ltckpt_get_offset(); +} + diff --git a/minix/lib/libsys/sef_st.c b/minix/lib/libsys/sef_st.c new file mode 100644 index 000000000..3189d9a22 --- /dev/null +++ b/minix/lib/libsys/sef_st.c @@ -0,0 +1,124 @@ +#include "syslib.h" +#include +#include +#include +#include +#include + +#include "kernel/config.h" +#include "kernel/const.h" +#include "kernel/type.h" +#include "kernel/proc.h" + +/* SEF Live update prototypes for sef_receive(). */ +void do_sef_st_before_receive(void); + +/*===========================================================================* + * do_sef_st_before_receive * + *===========================================================================*/ +void do_sef_st_before_receive(void) +{ +} + +/*===========================================================================* + * sef_copy_state_region_ctl * + *===========================================================================*/ +int sef_copy_state_region_ctl(sef_init_info_t *info, vir_bytes *src_address, vir_bytes *dst_address) { + if(info->copy_flags & SEF_COPY_DEST_OFFSET) { + *dst_address += sef_llvm_get_ltckpt_offset(); + } + if(info->copy_flags & SEF_COPY_SRC_OFFSET) { + *src_address += sef_llvm_get_ltckpt_offset(); + } +#if STATE_TRANS_DEBUG + printf("sef_copy_state_region_ctl. copy_flags:\nSEF_COPY_DEST_OFFSET\t%d\nSEF_COPY_SRC_OFFSET\t%d\nSEF_COPY_NEW_TO_NEW\t%d\nSEF_COPY_OLD_TO_NEW\t%d\n", info->copy_flags & SEF_COPY_DEST_OFFSET ? 1 : 0, + info->copy_flags & SEF_COPY_SRC_OFFSET ? 1 : 0, info->copy_flags & SEF_COPY_NEW_TO_NEW ? 1 : 0, info->copy_flags & SEF_COPY_OLD_TO_NEW ? 1 : 0); +#endif + if(info->copy_flags & SEF_COPY_NEW_TO_NEW) + return 1; + return 0; +} + +/*===========================================================================* + * sef_copy_state_region * + *===========================================================================*/ +int sef_copy_state_region(sef_init_info_t *info, + vir_bytes address, size_t size, vir_bytes dst_address) +{ + int r; + if(sef_copy_state_region_ctl(info, &address, &dst_address)) { +#if STATE_TRANS_DEBUG + printf("sef_copy_state_region: memcpy %d bytes, addr = 0x%08x -> 0x%08x...\n", + size, address, dst_address); +#endif + /* memcpy region from current state */ + memcpy((void*) dst_address, (void *)address, size); + } else { +#if STATE_TRANS_DEBUG + printf("sef_copy_state_region: copying %d bytes, addr = 0x%08x -> 0x%08x, gid = %d, source = %d...\n", + size, address, dst_address, SEF_STATE_TRANSFER_GID, info->old_endpoint); +#endif + /* Perform a safe copy of a region of the old state. */ + if((r = sys_safecopyfrom(info->old_endpoint, SEF_STATE_TRANSFER_GID, address, + dst_address, size)) != OK) { +#if STATE_TRANS_DEBUG + printf("sef_copy_state_region: sys_safecopyfrom failed\n"); +#endif + return r; + } + } + + return OK; +} + +/*===========================================================================* + * sef_old_state_table_lookup * + *===========================================================================*/ + int sef_old_state_table_lookup(sef_init_info_t *info, void *addr) +{ + struct priv old_priv; + int r; + + if ((r = sys_getpriv(&old_priv, info->old_endpoint)) != OK) { + printf("ERROR. sys_getpriv() failed.\n"); + return r; + } + + if (sef_copy_state_region(info, old_priv.s_state_table + , sef_llvm_state_table_size(), (vir_bytes) addr)) + { + printf("ERROR. state table transfer failed\n"); + return EGENERIC; + } + + return OK; +} + +/*===========================================================================* + * sef_old_state_table_lookup_opaque * + *===========================================================================*/ +int sef_old_state_table_lookup_opaque(void *info_opaque, void *addr) +{ + assert(info_opaque != NULL && "Invalid info_opaque pointer."); + return sef_old_state_table_lookup((sef_init_info_t *)(info_opaque), addr); +} + +/*===========================================================================* + * sef_copy_state_region_opaque * + *===========================================================================*/ +int sef_copy_state_region_opaque(void *info_opaque, uint32_t address, + size_t size, uint32_t dst_address) +{ + assert(info_opaque != NULL && "Invalid info_opaque pointer."); + return sef_copy_state_region((sef_init_info_t *)(info_opaque), + (vir_bytes) address, size, (vir_bytes) dst_address); +} + +/*===========================================================================* + * sef_st_state_transfer * + *===========================================================================*/ +int sef_st_state_transfer(sef_init_info_t *info) +{ + return sef_llvm_state_transfer(info); +} + diff --git a/minix/servers/rs/utility.c b/minix/servers/rs/utility.c index 62f3dd14c..62aad62e0 100644 --- a/minix/servers/rs/utility.c +++ b/minix/servers/rs/utility.c @@ -42,6 +42,7 @@ int type; /* type of initialization */ } /* Send initialization message. */ + memset(&m, 0, sizeof(message)); m.m_type = RS_INIT; m.m_rs_init.type = type; m.m_rs_init.rproctab_gid = rinit.rproctab_gid; diff --git a/minix/servers/vm/utility.c b/minix/servers/vm/utility.c index 81417870c..8d265d8d7 100644 --- a/minix/servers/vm/utility.c +++ b/minix/servers/vm/utility.c @@ -3,8 +3,6 @@ #define _SYSTEM 1 -#define brk _brk /* get rid of no previous prototype warning */ - #include #include #include @@ -24,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -305,7 +304,10 @@ int munmap(void * addr, size_t len) return 0; } -int brk(void *addr) +#ifdef __weak_alias +__weak_alias(brk, _brk) +#endif +int _brk(void *addr) { /* brk is a special case function to allow vm itself to allocate memory in it's own (cacheable) HEAP */