Kernel: separate userland ABI on kernel page

Currently, the userland ABI uses a single field ('user_sp') far
into the very large 'kinfo' structure on the shared kernel
information page.  This precludes us from modifying or getting
rid of 'kinfo' in the future without breaking userland.  This
patch adds a separate 'kuserinfo' structure to the kernel
information page, with only information that is part of the
userland ABI, in an extensible manner.  Userland now uses this
field if it is present, and falls back to the old field if not.

Change-Id: Ib7b24b53a440f40a2edc28cdfa48447ac2179288
This commit is contained in:
David van Moolenbroek 2015-09-21 14:52:29 +00:00
parent 26f5c8f84b
commit 20054ae93f
12 changed files with 94 additions and 21 deletions

View file

@ -23,6 +23,8 @@
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,

View file

@ -13,6 +13,7 @@
#include <sys/sigtypes.h>
#include <stdint.h>
#include <stddef.h>
/* Type definitions. */
typedef unsigned int vir_clicks; /* virtual addr/length in clicks */
@ -190,10 +191,32 @@ struct arm_frclock {
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;
@ -202,17 +225,17 @@ struct minix_kerninfo {
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 */

View file

@ -714,6 +714,7 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
ASSIGN(machine);
ASSIGN(kmessages);
ASSIGN(loadinfo);
ASSIGN(kuserinfo);
ASSIGN(arm_frclock);
ASSIGN(kclockinfo);
@ -723,6 +724,9 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
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;
}

View file

@ -879,6 +879,7 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
ASSIGN(machine);
ASSIGN(kmessages);
ASSIGN(loadinfo);
ASSIGN(kuserinfo);
ASSIGN(arm_frclock); /* eh, why not. */
ASSIGN(kclockinfo);
@ -920,6 +921,8 @@ int arch_phys_map_reply(const int index, const vir_bytes addr)
minix_kerninfo.ki_flags |= MINIX_KIF_IPCVECS;
}
minix_kerninfo.ki_flags |= MINIX_KIF_USERINFO;
return OK;
}

View file

@ -19,10 +19,11 @@
#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;

View file

@ -439,6 +439,10 @@ void cstart()
/* 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)

View file

@ -4,10 +4,12 @@
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 */

View file

@ -1,6 +1,12 @@
/*
* 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
@ -8,6 +14,7 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <minix/param.h>
#include <assert.h>
extern struct minix_kerninfo *_minix_kerninfo;
@ -23,3 +30,33 @@ get_minix_kerninfo(void)
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;
}

View file

@ -12,7 +12,6 @@
#include <unistd.h>
#include <string.h>
#include <stddef.h>
#include <minix/param.h>
#include <sys/exec_elf.h>
#include <sys/exec.h>
@ -131,7 +130,7 @@ void minix_stack_fill(const char *path, int argc, char * const *argv,
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;

View file

@ -2,7 +2,6 @@
#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,
@ -73,7 +72,7 @@ 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;

View file

@ -214,7 +214,7 @@ int pm_exec(vir_bytes path, size_t path_len, vir_bytes frame, size_t frame_len,
/* 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;

View file

@ -24,7 +24,6 @@
#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
@ -154,7 +153,7 @@ vir_bytes
kernel_get_stacktop(void)
{
return get_minix_kerninfo()->kinfo->user_sp;
return minix_get_user_sp();
}
/*