From: Jorrit Herder Date: Fri, 17 Jun 2005 09:10:30 +0000 (+0000) Subject: Parsing of free memory chunks is now done at the process manager. X-Git-Tag: v3.1.0~754 X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/zlib_tech.html?a=commitdiff_plain;h=92f9bd02f80b0dd126948a520437ead0e1224a58;p=minix.git Parsing of free memory chunks is now done at the process manager. --- diff --git a/servers/pm/alloc.c b/servers/pm/alloc.c index a5e25e297..3e9830ee2 100644 --- a/servers/pm/alloc.c +++ b/servers/pm/alloc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "mproc.h" #include "../../kernel/const.h" #include "../../kernel/type.h" @@ -195,7 +196,8 @@ register struct hole *hp; /* ptr to hole to merge with its successors */ /*===========================================================================* * mem_init * *===========================================================================*/ -PUBLIC void mem_init(free) +PUBLIC void mem_init(chunks, free) +struct memory *chunks; /* list of free memory chunks */ phys_clicks *free; /* memory size summaries */ { /* Initialize hole lists. There are two lists: 'hole_head' points to a linked @@ -207,32 +209,27 @@ phys_clicks *free; /* memory size summaries */ * smaller holes), new table slots are needed to represent them. These slots * are taken from the list headed by 'free_slots'. */ - struct memory mem[NR_MEMS]; /* chunks of physical memory */ int i; register struct hole *hp; phys_clicks base; /* base address of chunk */ phys_clicks size; /* size of chunk */ message mess; - /* Get a copy of the physical memory chunks found at the kernel. */ - if ((i=sys_getmemchunks(mem)) != OK) - panic(__FILE__,"couldn't get mem chunks",i); - /* Put all holes on the free list. */ for (hp = &hole[0]; hp < &hole[NR_HOLES]; hp++) hp->h_next = hp + 1; hole[NR_HOLES-1].h_next = NIL_HOLE; hole_head = NIL_HOLE; free_slots = &hole[0]; - /* Ask the kernel for chunks of physical memory and allocate holes. */ + /* Use the chunks of physical memory to allocate holes. */ *free = 0; for (i=NR_MEMS-1; i>=0; i--) { - if (mem[i].size > 0) { - free_mem(mem[i].base, mem[i].size); - *free += mem[i].size; + if (chunks[i].size > 0) { + free_mem(chunks[i].base, chunks[i].size); + *free += chunks[i].size; #if ENABLE_SWAP - if (swap_base < mem[i].base + mem[i].size) - swap_base = mem[i].base+mem[i].size; + if (swap_base < chunks[i].base + chunks[i].size) + swap_base = chunks[i].base + chunks[i].size; #endif } } @@ -246,6 +243,7 @@ phys_clicks *free; /* memory size summaries */ #endif } + #if ENABLE_SWAP /*===========================================================================* * swap_on * diff --git a/servers/pm/glo.h b/servers/pm/glo.h index 6f99a59b1..716b26741 100644 --- a/servers/pm/glo.h +++ b/servers/pm/glo.h @@ -7,6 +7,8 @@ /* Global variables. */ EXTERN struct mproc *mp; /* ptr to 'mproc' slot of current process */ EXTERN int procs_in_use; /* how many processes are marked as IN_USE */ +EXTERN char monitor_params[128*sizeof(char *)]; /* boot monitor parameters */ +EXTERN struct kinfo kinfo; /* kernel information */ /* The parameters of the call are kept here. */ EXTERN message m_in; /* the incoming message itself is kept here. */ diff --git a/servers/pm/main.c b/servers/pm/main.c index ef6c7ae59..990a3d8d3 100644 --- a/servers/pm/main.c +++ b/servers/pm/main.c @@ -1,9 +1,8 @@ /* This file contains the main program of the process manager and some related * procedures. When MINIX starts up, the kernel runs for a little while, * initializing itself and its tasks, and then it runs PM and FS. Both PM - * and FS initialize themselves as far as they can. FS then makes a call to - * PM, because PM has to wait for FS to acquire a RAM disk. PM asks the - * kernel for all free memory and starts serving requests. + * and FS initialize themselves as far as they can. PM asks the kernel for + * all free memory and starts serving requests. * * The entry points into this file are: * main: starts PM running @@ -16,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +27,9 @@ FORWARD _PROTOTYPE( void get_work, (void) ); FORWARD _PROTOTYPE( void pm_init, (void) ); +FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks) ); +FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks, + struct mem_map *map_ptr) ); #define click_to_round_k(n) \ ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024)) @@ -138,8 +141,8 @@ PRIVATE void pm_init() register char *sig_ptr; phys_clicks ram_clicks, total_clicks, minix_clicks, free_clicks; message mess; - struct mem_map kernel_map[NR_LOCAL_SEGS]; - int mem; + struct mem_map mem_map[NR_LOCAL_SEGS]; + struct memory mem_chunks[NR_MEMS]; /* Build the set of signals which cause core dumps, and the set of signals * that are by default ignored. @@ -151,31 +154,40 @@ PRIVATE void pm_init() for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++) sigaddset(&ign_sset, *sig_ptr); + /* Obtain a copy of the boot monitor parameters and the kernel info struct. + * Parse the list of free memory chunks. This list is what the boot monitor + * reported, but it must be corrected for the kernel and system processes. + */ + if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK) + panic(__FILE__,"get monitor params failed",s); + if ((s=sys_getkinfo(&kinfo)) != OK) + panic(__FILE__,"get kernel info failed",s); + get_mem_chunks(mem_chunks); + /* Get the memory map of the kernel to see how much memory it uses. */ - if ((s=get_mem_map(SYSTASK, kernel_map)) != OK) - panic(__FILE__,"PM couldn't get proc entry of SYSTASK",s); - minix_clicks = (kernel_map[S].mem_phys + kernel_map[S].mem_len) - - kernel_map[T].mem_phys; + if ((s=get_mem_map(SYSTASK, mem_map)) != OK) + panic(__FILE__,"PM couldn't get memory map of SYSTASK",s); + minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys; + patch_mem_chunks(mem_chunks, mem_map); - /* Initialize PM's tables. Request a copy of the system image table that - * is defined at the kernel level to see which slots to fill in. + /* Initialize PM's process table. Request a copy of the system image table + * that is defined at the kernel level to see which slots to fill in. */ - if (OK != (s=sys_getimage(&image))) { - printf("PM: warning, couldn't get system image table: %d\n", s); - } + if (OK != (s=sys_getimage(&image))) + panic(__FILE__,"PM: warning, couldn't get image table: %d\n", s); procs_in_use = 0; /* start populating table */ for (ip = &image[0]; ip < &image[IMAGE_SIZE]; ip++) { if (ip->proc_nr >= 0) { /* task have negative nrs */ procs_in_use += 1; /* found user process */ - /* Set process details. */ - rmp = &mproc[ip->proc_nr]; + /* Set process details found in the image table. */ + rmp = &mproc[ip->proc_nr]; rmp->mp_flags |= IN_USE | DONT_SWAP; rmp->mp_pid = (ip->proc_nr == INIT_PROC_NR) ? INIT_PID : get_free_pid(); strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); - /* Change signal handling behaviour. */ + /* Change local signal handling behaviour. */ sigfillset(&rmp->mp_ignore); sigfillset(&rmp->mp_sigmask); sigemptyset(&rmp->mp_catch); @@ -186,6 +198,7 @@ PRIVATE void pm_init() if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE; minix_clicks += rmp->mp_seg[S].mem_phys + rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys; + patch_mem_chunks(mem_chunks, rmp->mp_seg); /* Tell FS about this system process. */ mess.PR_PROC_NR = ip->proc_nr; @@ -195,7 +208,7 @@ PRIVATE void pm_init() } } - /* Tell FS no more SYSTEM processes follow and synchronize. */ + /* Tell FS that no more system processes follow and synchronize. */ mess.PR_PROC_NR = NONE; if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK) panic(__FILE__,"PM can't sync up with FS", NO_NUM); @@ -205,13 +218,113 @@ PRIVATE void pm_init() sigemptyset(&mproc[INIT_PROC_NR].mp_sigmask); sigemptyset(&mproc[INIT_PROC_NR].mp_catch); - /* Initialize tables to all physical memory. */ - mem_init(&free_clicks); - total_clicks = minix_clicks + free_clicks; + /* Possibly we must correct the memory chunks for the boot device. */ + if (kinfo.bootdev_size > 0) { + mem_map[T].mem_phys = kinfo.bootdev_base >> CLICK_SHIFT; + mem_map[T].mem_len = 0; + mem_map[D].mem_len = (kinfo.bootdev_size+CLICK_SIZE-1) >> CLICK_SHIFT; + patch_mem_chunks(mem_chunks, mem_map); + } - /* Print memory information. */ + /* Initialize tables to all physical memory and print memory information. */ + mem_init(mem_chunks, &free_clicks); + total_clicks = minix_clicks + free_clicks; printf("Memory size=%uK ", click_to_round_k(total_clicks)); printf("System services=%uK ", click_to_round_k(minix_clicks)); printf("Available=%uK\n\n", click_to_round_k(free_clicks)); +} + + +/* In real mode only 1M can be addressed, and in 16-bit protected we can go + * no further than we can count in clicks. (The 286 is further limited by + * its 24 bit address bus, but we can assume in that case that no more than + * 16M memory is reported by the BIOS.) + */ +#define MAX_REAL 0x00100000L +#define MAX_16BIT (0xFFF0L << CLICK_SHIFT) + +/*=========================================================================* + * get_mem_chunks * + *=========================================================================*/ +PRIVATE void get_mem_chunks(mem_chunks) +struct memory *mem_chunks; /* store mem chunks here */ +{ +/* Initialize the free memory list from the 'memory' boot variable. Translate + * the byte offsets and sizes in this list to clicks, properly truncated. Also + * make sure that we don't exceed the maximum address space of the 286 or the + * 8086, i.e. when running in 16-bit protected mode or real mode. + */ + long base, size, limit; + char *s, *end; /* use to parse boot variable */ + int i; + struct memory *memp; +#if _WORD_SIZE == 2 + unsigned long max_address; + struct machine machine; + if (OK != (i=sys_getmachine(&machine))) + panic(__FILE__, "sys_getmachine failed", i); +#endif + + /* Initialize everything to zero. */ + for (i = 0; i < NR_MEMS; i++) { + memp = &mem_chunks[i]; /* next mem chunk is stored here */ + memp->base = memp->size = 0; + } + + /* The available memory is determined by MINIX' boot loader as a list of + * (base:size)-pairs in boothead.s. The 'memory' boot variable is set in + * in boot.s. The format is "b0:s0,b1:s1,b2:s2", where b0:s0 is low mem, + * b1:s1 is mem between 1M and 16M, b2:s2 is mem above 16M. Pairs b1:s1 + * and b2:s2 are combined if the memory is adjacent. + */ + s = find_param("memory"); /* get memory boot variable */ + for (i = 0; i < NR_MEMS; i++) { + memp = &mem_chunks[i]; /* next mem chunk is stored here */ + base = size = 0; /* initialize next base:size pair */ + if (*s != 0) { /* get fresh data, unless at end */ + + /* Read fresh base and expect colon as next char. */ + base = strtoul(s, &end, 0x10); /* get number */ + if (end != s && *end == ':') s = ++end; /* skip ':' */ + else *s=0; /* terminate, should not happen */ + + /* Read fresh size and expect comma or assume end. */ + size = strtoul(s, &end, 0x10); /* get number */ + if (end != s && *end == ',') s = ++end; /* skip ',' */ + else *s=0; /* found end */ + } + limit = base + size; +#if _WORD_SIZE == 2 + max_address = machine.protected ? MAX_16BIT : MAX_REAL; + if (limit > max_address) limit = max_address; +#endif + base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1); + limit &= ~(long)(CLICK_SIZE-1); + if (limit <= base) continue; + memp->base = base >> CLICK_SHIFT; + memp->size = (limit - base) >> CLICK_SHIFT; + } +} +/*=========================================================================* + * patch_mem_chunks * + *=========================================================================*/ +PRIVATE void patch_mem_chunks(mem_chunks, map_ptr) +struct memory *mem_chunks; /* store mem chunks here */ +struct mem_map *map_ptr; /* memory to remove */ +{ +/* Remove server memory from the free memory list. The boot monitor + * promises to put processes at the start of memory chunks. The + * tasks all use same base address, so only the first task changes + * the memory lists. The servers and init have their own memory + * spaces and their memory will be removed from the list. + */ + struct memory *memp; + for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) { + if (memp->base == map_ptr[T].mem_phys) { + memp->base += map_ptr[T].mem_len + map_ptr[D].mem_len; + memp->size -= map_ptr[T].mem_len + map_ptr[D].mem_len; + } + } } + diff --git a/servers/pm/misc.c b/servers/pm/misc.c index 9e6492e0c..6992f95e2 100644 --- a/servers/pm/misc.c +++ b/servers/pm/misc.c @@ -19,10 +19,6 @@ #include "mproc.h" #include "param.h" -FORWARD _PROTOTYPE( char *find_key, (const char *params, const char *key)); - -/* PM gets a copy of all boot monitor parameters. */ -PRIVATE char monitor_params[128*sizeof(char *)]; /*===========================================================================* * do_allocmem * @@ -164,30 +160,20 @@ PUBLIC int do_reboot() *=====================================================================*/ PUBLIC int do_svrctl() { - static int initialized = 0; int s, req; vir_bytes ptr; req = m_in.svrctl_req; ptr = (vir_bytes) m_in.svrctl_argp; - /* Initialize private copy of monitor parameters on first call. */ - if (! initialized) { - if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK) - printf("PM: Warning couldn't get copy of monitor params: %d\n",s); - else - initialized = 1; - } + /* Is the request for the kernel? Forward it, except for SYSGETENV. */ + if (((req >> 8) & 0xFF) == 'S') { - /* Binary compatibility check. */ - if (req == SYSGETENV) { -#if DEAD_CODE + /* Binary compatibility check. */ + if (req == SYSGETENV) { printf("SYSGETENV by %d (fix!)\n", who); -#endif req = MMGETPARAM; - } - - /* Is the request for the kernel? Forward it, except for SYSGETENV. */ - if (((req >> 8) & 0xFF) == 'S') { + } + else /* Simply forward call to the SYSTEM task. */ return(sys_svrctl(who, req, mp->mp_effuid == SUPER_USER, ptr)); @@ -202,9 +188,6 @@ PUBLIC int do_svrctl() size_t val_len; size_t copy_len; - /* Check if boot monitor parameters are in place. */ - if (! initialized) return(EAGAIN); - /* Copy sysgetenv structure to PM. */ if (sys_datacopy(who, ptr, SELF, (vir_bytes) &sysgetenv, sizeof(sysgetenv)) != OK) return(EFAULT); @@ -222,7 +205,7 @@ PUBLIC int do_svrctl() /* Make sure key is null-terminated and lookup value. */ search_key[sysgetenv.keylen-1]= '\0'; - if ((val_start = find_key(monitor_params, search_key)) == NULL) + if ((val_start = find_param(search_key)) == NULL) return(ESRCH); val_len = strlen(val_start) + 1; } @@ -293,24 +276,3 @@ PUBLIC int do_svrctl() } } -/*==========================================================================* - * find_key * - *==========================================================================*/ -PRIVATE char *find_key(params,name) -const char *params; -const char *name; -{ - register const char *namep; - register char *envp; - - for (envp = (char *) params; *envp != 0;) { - for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++) - ; - if (*namep == '\0' && *envp == '=') - return(envp + 1); - while (*envp++ != 0) - ; - } - return(NULL); -} - diff --git a/servers/pm/proto.h b/servers/pm/proto.h index 87c2aa923..2e29ebee3 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -3,11 +3,12 @@ struct mproc; struct stat; struct mem_map; +struct memory; /* alloc.c */ _PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks) ); _PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks) ); -_PROTOTYPE( void mem_init, (phys_clicks *free) ); +_PROTOTYPE( void mem_init, (struct memory *chunks, phys_clicks *free) ); #if ENABLE_SWAP _PROTOTYPE( int swap_on, (char *file, u32_t offset, u32_t size) ); _PROTOTYPE( int swap_off, (void) ); @@ -98,4 +99,5 @@ _PROTOTYPE( void panic, (char *who, char *mess, int num) ); _PROTOTYPE( void tell_fs, (int what, int p1, int p2, int p3) ); _PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp) ); _PROTOTYPE( int get_mem_map, (int proc_nr, struct mem_map *mem_map) ); +_PROTOTYPE( char *find_param, (const char *key)); diff --git a/servers/pm/utility.c b/servers/pm/utility.c index 3375e92ef..2a6a3aba2 100644 --- a/servers/pm/utility.c +++ b/servers/pm/utility.c @@ -1,6 +1,7 @@ /* This file contains some utility routines for PM. * * The entry points are: + * find_param: look up a boot monitor parameter * get_free_pid: get a free process or group id * allowed: see if an access is permitted * no_sys: called for invalid system call numbers @@ -146,6 +147,27 @@ int what, p1, p2, p3; } +/*==========================================================================* + * find_param * + *==========================================================================*/ +PUBLIC char *find_param(name) +const char *name; +{ + register const char *namep; + register char *envp; + + for (envp = (char *) monitor_params; *envp != 0;) { + for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++) + ; + if (*namep == '\0' && *envp == '=') + return(envp + 1); + while (*envp++ != 0) + ; + } + return(NULL); +} + + /*===========================================================================* * get_mem_map * *===========================================================================*/