]> Zhao Yanbai Git Server - minix.git/commitdiff
Parsing of free memory chunks is now done at the process manager.
authorJorrit Herder <jnherder@minix3.org>
Fri, 17 Jun 2005 09:10:30 +0000 (09:10 +0000)
committerJorrit Herder <jnherder@minix3.org>
Fri, 17 Jun 2005 09:10:30 +0000 (09:10 +0000)
servers/pm/alloc.c
servers/pm/glo.h
servers/pm/main.c
servers/pm/misc.c
servers/pm/proto.h
servers/pm/utility.c

index a5e25e297251a529f686c6b20a05a3ae82005bcb..3e9830ee22a9638e7bdeb5dde5dedbf3047d222b 100644 (file)
@@ -19,6 +19,7 @@
 #include <minix/com.h>
 #include <minix/callnr.h>
 #include <signal.h>
+#include <stdlib.h>
 #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                                      *
index 6f99a59b1475b00563702775e9dab40e579580b4..716b267419efd7bbf7e22150bfdd22043b5799bd 100644 (file)
@@ -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. */
index ef6c7ae59e25aaac95e0a0081fa327531215cb70..990a3d8d3ee1bec69cd81eea63e2b9c4f060897c 100644 (file)
@@ -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 <minix/callnr.h>
 #include <minix/com.h>
 #include <signal.h>
+#include <stdlib.h>
 #include <fcntl.h>
 #include <sys/ioc_memory.h>
 #include <string.h>
@@ -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;
+       }
+  }
 }
+
index 9e6492e0ccc672a275070f46b2501f646bf5f72c..6992f95e2add2bdd8192108d28f2b28c1e43bffc 100644 (file)
 #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);
-}
-
index 87c2aa92389b37d21c350b4a27ad4453255f0d32..2e29ebee3a06d19bb1db6f3e276feec3ceb917bb 100644 (file)
@@ -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));
 
index 3375e92ef9fd1c942e331a22ef5abf1819e273c3..2a6a3aba25bac7d14ca41bee9be51ec749f4b7d7 100644 (file)
@@ -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                                          *
  *===========================================================================*/