minix/servers/rs/memory.c
Cristiano Giuffrida f4574783dc Rewrite of boot process
KERNEL CHANGES:
- The kernel only knows about privileges of kernel tasks and the root system
process (now RS).
- Kernel tasks and the root system process are the only processes that are made
schedulable by the kernel at startup. All the other processes in the boot image
don't get their privileges set at startup and are inhibited from running by the
RTS_NO_PRIV flag.
- Removed the assumption on the ordering of processes in the boot image table.
System processes can now appear in any order in the boot image table.
- Privilege ids can now be assigned both statically or dynamically. The kernel
assigns static privilege ids to kernel tasks and the root system process. Each
id is directly derived from the process number.
- User processes now all share the static privilege id of the root user
process (now INIT).
- sys_privctl split: we have more calls now to let RS set privileges for system
processes. SYS_PRIV_ALLOW / SYS_PRIV_DISALLOW are only used to flip the
RTS_NO_PRIV flag and allow / disallow a process from running. SYS_PRIV_SET_SYS /
SYS_PRIV_SET_USER are used to set privileges for a system / user process.
- boot image table flags split: PROC_FULLVM is the only flag that has been
moved out of the privilege flags and is still maintained in the boot image
table. All the other privilege flags are out of the kernel now.

RS CHANGES:
- RS is the only user-space process who gets to run right after in-kernel
startup.
- RS uses the boot image table from the kernel and three additional boot image
info table (priv table, sys table, dev table) to complete the initialization
of the system.
- RS checks that the entries in the priv table match the entries in the boot
image table to make sure that every process in the boot image gets schedulable.
- RS only uses static privilege ids to set privileges for system services in
the boot image.
- RS includes basic memory management support to allocate the boot image buffer
dynamically during initialization. The buffer shall contain the executable
image of all the system services we would like to restart after a crash.
- First step towards decoupling between resource provisioning and resource
requirements in RS: RS must know what resources it needs to restart a process
and what resources it has currently available. This is useful to tradeoff
reliability and resource consumption. When required resources are missing, the
process cannot be restarted. In that case, in the future, a system flag will
tell RS what to do. For example, if CORE_PROC is set, RS should trigger a
system-wide panic because the system can no longer function correctly without
a core system process.

PM CHANGES:
- The process tree built at initialization time is changed to have INIT as root
with pid 0, RS child of INIT and all the system services children of RS. This
is required to make RS in control of all the system services.
- PM no longer registers labels for system services in the boot image. This is
now part of RS's initialization process.
2009-12-11 00:08:19 +00:00

214 lines
6.6 KiB
C

/* This file contains memory management routines for RS.
*
* Changes:
* Nov 22, 2009: Created (Cristiano Giuffrida)
*/
#include "inc.h"
#include "../../kernel/const.h"
#include "../../kernel/type.h"
#include "../../kernel/proc.h"
EXTERN char *_brksize;
PRIVATE char * _rs_startbrksize = NULL;
PRIVATE char * _rs_endbrksize = NULL;
#define munmap _munmap
#define munmap_text _munmap_text
#include <sys/mman.h>
#undef munmap
#undef munmap_text
PUBLIC int unmap_ok = 0;
/*===========================================================================*
* check_mem_available *
*===========================================================================*/
PRIVATE int check_mem_available(char *new_brksize)
{
/* Check if enough memory is available to grow break size. */
register struct mem_map *mem_sp, *mem_dp;
vir_clicks sp_click, gap_base, sp_lower;
int s;
long base_of_stack, sp_delta; /* longs avoid certain problems */
vir_bytes sp;
struct proc proc;
vir_clicks data_clicks;
/* Get stack pointer and pointers to data/stack segment maps. */
if ((s=sys_getproc(&proc, SELF)) != OK) {
return(s);
}
sp = proc.p_reg.sp; /* stack pointer */
mem_dp = &proc.p_memmap[D]; /* pointer to data segment map */
mem_sp = &proc.p_memmap[S]; /* pointer to stack segment map */
/* Compute how many clicks the data segment is to become. */
data_clicks = (vir_clicks) ( ((long) new_brksize + CLICK_SIZE - 1) >>
CLICK_SHIFT) - mem_dp->mem_vir;
/* See if stack size has gone negative (i.e., sp too close to 0xFFFF...) */
base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
sp_click = sp >> CLICK_SHIFT; /* click containing sp */
if (sp_click >= base_of_stack)
{
return(ENOMEM); /* sp too high */
}
/* Compute size of gap between stack and data segments. */
sp_delta = (long) mem_sp->mem_vir - (long) sp_click;
sp_lower = (sp_delta > 0 ? sp_click : mem_sp->mem_vir);
/* Add a safety margin for future stack growth. Impossible to do right. */
#define SAFETY_BYTES (384 * sizeof(char *))
#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
if (sp_lower < gap_base)
{
return(ENOMEM); /* data and stack collided */
}
return(OK);
}
/*===========================================================================*
* rs_startup_sbrk *
*===========================================================================*/
PUBLIC void* rs_startup_sbrk(size)
size_t size; /* the size to grow */
{
/* RS's own sbrk() used at startup. */
void* addr;
char* new_brksize;
/* Check input for non-positive size or size overflows. */
new_brksize = _brksize + size;
if (size <= 0 || new_brksize < _brksize) {
return( (char *) -1);
}
/* Check if enough memory is available. */
if(check_mem_available(new_brksize) != OK) {
return( (char *) -1);
}
/* Save initial break size. */
if(_rs_startbrksize == NULL) {
_rs_startbrksize = _brksize;
}
/* Set address and adjust break size. */
addr = _brksize;
_brksize = new_brksize;
_rs_endbrksize = _brksize;
return addr;
}
/*===========================================================================*
* rs_startup_sbrk_synch *
*===========================================================================*/
PUBLIC void* rs_startup_sbrk_synch(size)
size_t size; /* the size to grow */
{
/* Synchronize RS's own sbrk() with the rest of the system right after
* startup. We use the original sbrk() here.
*/
void* addr;
/* Restore original break size. */
_brksize = _rs_startbrksize;
/* Call original sbrk() and see if we observe the same effect. */
addr = (void*)sbrk(size);
if(_rs_startbrksize != addr) {
printf("Unable to synch rs_startup_sbrk() and sbrk(): addr 0x%x!=0x%x\n",
(int) _rs_startbrksize, (int) addr);
return( (char *) -1);
}
if(_rs_endbrksize != _brksize) {
printf("Unable to synch rs_startup_sbrk() and sbrk(): size 0x%x!=0x%x\n",
(int) _rs_endbrksize, (int) _brksize);
return( (char *) -1);
}
return addr;
}
/*===========================================================================*
* rs_startup_segcopy *
*===========================================================================*/
PUBLIC int rs_startup_segcopy(src_proc, src_seg, dst_seg, dst_vir, bytes)
endpoint_t src_proc; /* source process */
int src_seg; /* source memory segment */
int dst_seg; /* destination memory segment */
vir_bytes dst_vir; /* destination virtual address */
phys_bytes bytes; /* how many bytes */
{
/* Copy a process's T, D, S segment to RS's address space. Used at startup. */
struct proc src_p, dst_p;
phys_bytes src_phys, dst_phys;
int s;
/* Check input. */
if((src_seg != T && src_seg != D && src_seg != S) || bytes <= 0) {
return EINVAL;
}
/* We don't override normal behavior when not copying to our data segment. */
if(dst_seg != D) {
s = sys_vircopy(src_proc, src_seg, 0, SELF, dst_seg, dst_vir, bytes);
return(s);
}
/* Get kernel process slot for both source and destination. */
if ((s=sys_getproc(&src_p, src_proc)) != OK) {
return(s);
}
if ((s=sys_getproc(&dst_p, SELF)) != OK) {
return(s);
}
/* Map source address to physical address. */
src_phys = (phys_bytes) src_p.p_memmap[src_seg].mem_phys << CLICK_SHIFT;
/* Check if destination address is out of bounds or overflows. */
if(dst_vir+bytes > (vir_bytes)_rs_endbrksize
|| dst_vir < (vir_bytes)_rs_startbrksize || dst_vir+bytes < dst_vir) {
return EFAULT;
}
/* Map destination address to physical address. */
dst_phys = (phys_bytes) dst_p.p_memmap[D].mem_phys << CLICK_SHIFT;
dst_phys += dst_vir - (dst_p.p_memmap[D].mem_vir << CLICK_SHIFT);
/* Make a physical copy for the requested data. */
s = sys_abscopy(src_phys, dst_phys, bytes);
return(s);
}
/*===========================================================================*
* munmap *
*===========================================================================*/
PUBLIC int munmap(void *addrstart, vir_bytes len)
{
if(!unmap_ok)
return ENOSYS;
return _munmap(addrstart, len);
}
/*===========================================================================*
* munmap_text *
*===========================================================================*/
PUBLIC int munmap_text(void *addrstart, vir_bytes len)
{
if(!unmap_ok)
return ENOSYS;
return _munmap_text(addrstart, len);
}