struct minix_kerninfo *get_minix_kerninfo(void);
+vir_bytes minix_get_user_sp(void);
+
struct ps_strings; /* forward declaration for minix_stack_fill. */
void minix_stack_params(const char *path, char * const *argv,
#include <sys/sigtypes.h>
#include <stdint.h>
+#include <stddef.h>
/* Type definitions. */
typedef unsigned int vir_clicks; /* virtual addr/length in clicks */
u32_t tcrr; /* tcrr address */
};
+/* The userland ABI portion of general information exposed by the kernel.
+ * This structure may only ever be extended with new fields!
+ */
+struct kuserinfo {
+ size_t kui_size; /* size of this structure, for ABI testing */
+ vir_bytes kui_user_sp; /* initial stack pointer for exec'd process */
+};
+
+/* If MINIX_KIF_USERINFO is set, use this to check for a particular field. */
+#define KUSERINFO_HAS_FIELD(kui,f) \
+ (kui->kui_size >= offsetof(struct kuserinfo, f) + sizeof(kui->f))
+
struct minix_kerninfo {
- /* Binaries will depend on the offsets etc. in this
- * structure, so it can't be changed willy-nilly. In
- * other words, it is ABI-restricted.
+ /* Binaries will depend on the offsets etc. in this structure, so it
+ * can't be changed willy-nilly. In other words, it is ABI-restricted.
+ * However, various fields are to be used by services only, and are not
+ * to be used by userland directly. For pointers to non-userland-ABI
+ * structures, these structures themselves may be changed without
+ * breaking the userland ABI.
+ *
+ * There is currently one important legacy exception: the 'kinfo'
+ * structure should not be part of the userland ABI, but one of its
+ * fields, "user_sp" at offset 2440, is used by legacy user binaries.
+ * This field has since been moved into the 'kuserinfo' structure, but
+ * it will take another major release before we can start changing the
+ * layout of the 'kinfo' structure.
*/
#define KERNINFO_MAGIC 0xfc3b84bf
u32_t kerninfo_magic;
u32_t flags_unused2;
u32_t flags_unused3;
u32_t flags_unused4;
- struct kinfo *kinfo;
+ struct kinfo *kinfo; /* see note above! */
struct machine *machine; /* NOT userland ABI */
struct kmessages *kmessages; /* NOT userland ABI */
struct loadinfo *loadinfo; /* NOT userland ABI */
- struct minix_ipcvecs *minix_ipcvecs;
- u32_t reserved;
+ struct minix_ipcvecs *minix_ipcvecs; /* userland ABI */
+ struct kuserinfo *kuserinfo; /* userland ABI */
struct arm_frclock *arm_frclock; /* NOT userland ABI */
volatile struct kclockinfo *kclockinfo; /* NOT userland ABI */
-} __packed;
+};
-#define MINIX_KIF_IPCVECS (1L << 0)
+#define MINIX_KIF_IPCVECS (1L << 0) /* minix_ipcvecs is valid */
+#define MINIX_KIF_USERINFO (1L << 1) /* kuserinfo is valid */
#endif /* _TYPE_H */
-
ASSIGN(machine);
ASSIGN(kmessages);
ASSIGN(loadinfo);
+ ASSIGN(kuserinfo);
ASSIGN(arm_frclock);
ASSIGN(kclockinfo);
minix_kerninfo.kerninfo_magic = KERNINFO_MAGIC;
minix_kerninfo.minix_feature_flags = minix_feature_flags;
minix_kerninfo_user = (vir_bytes) FIXEDPTR(&minix_kerninfo);
+
+ minix_kerninfo.ki_flags |= MINIX_KIF_USERINFO;
+
return OK;
}
ASSIGN(machine);
ASSIGN(kmessages);
ASSIGN(loadinfo);
+ ASSIGN(kuserinfo);
ASSIGN(arm_frclock); /* eh, why not. */
ASSIGN(kclockinfo);
minix_kerninfo.ki_flags |= MINIX_KIF_IPCVECS;
}
+ minix_kerninfo.ki_flags |= MINIX_KIF_USERINFO;
+
return OK;
}
#include "debug.h"
/* Kernel information structures. This groups vital kernel information. */
-extern struct kinfo kinfo; /* kernel information for users */
-extern struct machine machine; /* machine information for users */
+extern struct kinfo kinfo; /* kernel information for services */
+extern struct machine machine; /* machine info for services */
extern struct kmessages kmessages; /* diagnostic messages in kernel */
extern struct loadinfo loadinfo; /* status of load average */
+extern struct kuserinfo kuserinfo; /* kernel information for users */
extern struct arm_frclock arm_frclock; /* ARM free-running timer info */
extern struct kclockinfo kclockinfo; /* clock information */
extern struct minix_kerninfo minix_kerninfo;
/* Initialize various user-mapped structures. */
memset(&arm_frclock, 0, sizeof(arm_frclock));
+ memset(&kuserinfo, 0, sizeof(kuserinfo));
+ kuserinfo.kui_size = sizeof(kuserinfo);
+ kuserinfo.kui_user_sp = kinfo.user_sp;
+
#ifdef USE_APIC
value = env_get("no_apic");
if(value)
struct minix_kerninfo minix_kerninfo __section(".usermapped");
/* Kernel information structures. */
-struct kinfo kinfo __section(".usermapped"); /* kernel information for users */
-struct machine machine __section(".usermapped"); /* machine information for users */
+struct kinfo kinfo __section(".usermapped"); /* kernel information for services */
+struct machine machine __section(".usermapped"); /* machine information for services */
struct kmessages kmessages __section(".usermapped"); /* diagnostic messages in kernel */
struct loadinfo loadinfo __section(".usermapped"); /* status of load average */
+struct kuserinfo kuserinfo __section(".usermapped");
+ /* kernel information for users */
struct arm_frclock arm_frclock __section(".usermapped");
/* ARM free running timer information */
struct kclockinfo kclockinfo __section(".usermapped"); /* clock information */
/*
* This file contains the main routine for retrieval of the kernel information
- * page.
+ * page, as well as abstraction routines for retrieval of specific values from
+ * this kernel-mapped user information structure. These routines may be used
+ * from both userland and system services, and their accesses are considered to
+ * establish part of the userland ABI. Do not add routines here that are not
+ * for retrieval of userland ABI fields (e.g., clock information)! Also, since
+ * these functions are MINIX3 specific, their names should contain - preferably
+ * be prefixed with - "minix_".
*/
#define _MINIX_SYSTEM
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
+#include <minix/param.h>
#include <assert.h>
extern struct minix_kerninfo *_minix_kerninfo;
return _minix_kerninfo;
}
+
+/*
+ * Obtain the initial stack pointer for a new userland process. This value
+ * is used by routines that set up the stack when executing a new program.
+ * It is used for userland exec(2) and in various system services.
+ */
+vir_bytes
+minix_get_user_sp(void)
+{
+ struct minix_kerninfo *ki;
+
+ /* All information is obtained from the kernel information page. */
+ ki = get_minix_kerninfo();
+
+ /*
+ * Check whether we can retrieve the user stack pointer value from the
+ * kuserinfo structure. In general, this test is the correct one to
+ * see whether the kuserinfo structure has a certain field.
+ */
+ if ((ki->ki_flags & MINIX_KIF_USERINFO) &&
+ KUSERINFO_HAS_FIELD(ki->kuserinfo, kui_user_sp)) {
+ return ki->kuserinfo->kui_user_sp;
+ }
+
+ /*
+ * Otherwise, fall back to legacy support: retrieve the value from the
+ * kinfo structure. This field will eventually be removed.
+ */
+ return ki->kinfo->user_sp;
+}
#include <unistd.h>
#include <string.h>
#include <stddef.h>
-#include <minix/param.h>
#include <sys/exec_elf.h>
#include <sys/exec.h>
size_t const min_size = STACK_MIN_SZ;
/* Virtual address of the stack pointer, in new memory space. */
- *vsp = get_minix_kerninfo()->kinfo->user_sp - stack_size;
+ *vsp = minix_get_user_sp() - stack_size;
/* Fill in the frame now. */
fpw = (char **) frame;
#include <assert.h>
#include <sys/exec.h>
#include <libexec.h>
-#include <minix/param.h>
#include <machine/vmparam.h>
static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
memset(&execi, 0, sizeof(execi));
- execi.stack_high = get_minix_kerninfo()->kinfo->user_sp;
+ execi.stack_high = minix_get_user_sp();
execi.stack_size = DEFAULT_STACK_LIMIT;
execi.proc_e = proc_e;
execi.hdr = exec;
/* passed from exec() libc code */
execi.userflags = 0;
- execi.args.stack_high = get_minix_kerninfo()->kinfo->user_sp;
+ execi.args.stack_high = minix_get_user_sp();
execi.args.stack_size = DEFAULT_STACK_LIMIT;
fp->text_size = 0;
#include "kernel/arch/i386/include/archconst.h" /* for the KTS_ constants */
#endif
#include <lib.h>
-#include <minix/param.h>
/*
* Working area. By obtaining values from the kernel into these local process
kernel_get_stacktop(void)
{
- return get_minix_kerninfo()->kinfo->user_sp;
+ return minix_get_user_sp();
}
/*