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. */
void* init_buff_start;
void* init_buff_cleanup_start;
size_t init_buff_len;
+ int copy_flags;
} sef_init_info_t;
/* Callback type definitions. */
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. */
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. */
/* 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
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 \
.endif
CPPFLAGS.sched_start.c+= -I${NETBSDSRCDIR}/minix
+CPPFLAGS.sef_st.c+= -I${NETBSDSRCDIR}/minix
.include <bsd.lib.mk>
#include "syslib.h"
#include <assert.h>
#include <minix/sysutil.h>
+#include <minix/rs.h>
+#include <minix/timers.h>
+#include <minix/endpoint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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;
/* 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);
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. */
#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;
}
/*===========================================================================*
#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;
}
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 *
*===========================================================================*/
__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 *
/* 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 *
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);
+
+ /* 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;
+ }
+ }
- default:
- /* Not a valid SEF init type. */
- result = EINVAL;
- break;
+ 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));
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;
}
int r;
int type;
sef_init_info_t info;
+ memset(&info, 0, sizeof(info));
/* Get init parameters from SEF. */
type = SEF_INIT_FRESH;
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);
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);
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 *
*===========================================================================*/
#include "syslib.h"
#include <assert.h>
#include <minix/sysutil.h>
+#include <minix/rs.h>
/* 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;
/* 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);
/* Information about SELF. */
EXTERN endpoint_t sef_self_endpoint;
-EXTERN int sef_self_first_receive_done;
/*===========================================================================*
* do_sef_lu_before_receive *
/* 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
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);
}
}
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, where no reply is requested. */
+ if(state == SEF_LU_STATE_NULL) {
+ sef_lu_state_change(SEF_LU_STATE_NULL, 0);
+ return OK;
+ }
- /* Deal with prepare cancel requests first. */
- is_valid_state = (state == SEF_LU_STATE_NULL);
+ /* 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);
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);
}
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();
* 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);
}
/* 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<num_ipc_filters;i++) {
+ int num_elements=0;
+ r = sys_safecopyfrom(src_e, rs_state_data.ipcf_els_gid, i*ipc_filter_size,
+ (vir_bytes) ipc_filter, ipc_filter_size);
+ if(r != OK) {
+ break;
+ }
+#if SEF_LU_DEBUG
+ sef_lu_debug_begin();
+ sef_lu_dprint("%s, Installing ipc filter:\n", sef_debug_header());
+#endif
+ while(num_elements < IPCF_MAX_ELEMENTS && ipc_filter[num_elements].flags) {
+#if SEF_LU_DEBUG
+ sef_lu_dprint("el[%d]=(flags=%c%c%c%c, m_source=%d, m_type=%d)",
+ num_elements,
+ (ipc_filter[num_elements].flags & IPCF_MATCH_M_SOURCE) ? 'S' : '-',
+ (ipc_filter[num_elements].flags & IPCF_MATCH_M_TYPE) ? 'T' : '-',
+ (ipc_filter[num_elements].flags & IPCF_EL_BLACKLIST) ? 'B' : '-',
+ (ipc_filter[num_elements].flags & IPCF_EL_WHITELIST) ? 'W' : '-',
+ ipc_filter[num_elements].m_source, ipc_filter[num_elements].m_type);
+ sef_lu_dprint("\n");
+#endif
+ num_elements++;
+ }
+#if SEF_LU_DEBUG
+ sef_lu_debug_end();
+#endif
+ if(num_elements == 0) {
+ r = EINVAL;
+ break;
+ }
+ r = sys_statectl(ipc_filter[0].flags & IPCF_EL_BLACKLIST ? SYS_STATE_ADD_IPC_BL_FILTER : SYS_STATE_ADD_IPC_WL_FILTER,
+ ipc_filter, num_elements*sizeof(ipc_filter_el_t));
+ if(r != OK) {
+ break;
+ }
+ }
+ if(r != OK) {
+ sys_statectl(SYS_STATE_CLEAR_IPC_FILTERS, 0, 0);
+ return r;
+ }
+ }
+ return OK;
+}
+
/*===========================================================================*
* sef_setcb_lu_prepare *
*===========================================================================*/
return OK;
}
+/*===========================================================================*
+ * sef_cb_lu_prepare_eval *
+ *===========================================================================*/
+int sef_cb_lu_prepare_eval(int UNUSED(state))
+{
+ char result = 0;
+ int ret = sef_llvm_eval_bool(sef_lu_state_eval, &result);
+
+#if SEF_LU_DEBUG
+ sef_lu_debug_begin();
+ sef_lu_dprint("%s, cycle=%d. Evaluated state expression '%s' with error code %d and result %d\n",
+ sef_debug_header(), sef_lu_debug_cycle, sef_lu_state_eval, ret, result);
+ sef_lu_debug_end();
+#endif
+
+ if(ret < 0) {
+ return ret == ENOTREADY ? EINTR : ret;
+ }
+ return result ? OK : ENOTREADY;
+}
+
/*===========================================================================*
* sef_cb_lu_state_isvalid_standard *
*===========================================================================*/
return (state == SEF_LU_STATE_EVAL) || sef_cb_lu_state_isvalid_workfree(state, flags);
}
+/*===========================================================================*
+ * sef_cb_lu_state_dump_eval *
+ *===========================================================================*/
+void sef_cb_lu_state_dump_eval(int state)
+{
+ if(state == SEF_LU_STATE_EVAL) {
+ sef_llvm_dump_eval(sef_lu_state_eval);
+ }
+ else {
+ return sef_cb_lu_state_dump_null(state);
+ }
+}
+
/*===========================================================================*
* sef_cb_lu_response_rs_reply *
*===========================================================================*/
--- /dev/null
+#include "syslib.h"
+#include <assert.h>
+#include <unistd.h>
+#include <minix/sysutil.h>
+
+/* 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();
+}
+
--- /dev/null
+#include "syslib.h"
+#include <assert.h>
+#include <string.h>
+#include <machine/archtypes.h>
+#include <minix/timers.h>
+#include <minix/sysutil.h>
+
+#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);
+}
+
}
/* 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;
#define _SYSTEM 1
-#define brk _brk /* get rid of no previous prototype warning */
-
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/config.h>
#include <env.h>
#include <unistd.h>
#include <assert.h>
+#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/resource.h>
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 */