1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %
4 % File:         PXK:bpsheap.c
5 % Description:  Code to dynamically set up bps and heap structures
6 % Author:       RAM, HP/FSD
7 % Created:      9-Mar-84
8 % Modified:
9 % Status:       Open Source: BSD License
10 % Mode:         Text
11 % Package:
12 %
13 % (c) Copyright 1982, University of Utah
14 %
15 % Redistribution and use in source and binary forms, with or without
16 % modification, are permitted provided that the following conditions are met:
17 %
18 %    * Redistributions of source code must retain the relevant copyright
19 %      notice, this list of conditions and the following disclaimer.
20 %    * Redistributions in binary form must reproduce the above copyright
21 %      notice, this list of conditions and the following disclaimer in the
22 %      documentation and/or other materials provided with the distribution.
23 %
24 % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
26 % THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 % PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS OR
28 % CONTRIBUTORS
29 % BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 % POSSIBILITY OF SUCH DAMAGE.
36 %
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 %
39 % Revisions:
40 %
41 % 11-Aug-88 (Julian Padget)
42 %  Added initialization of bpslowerbound in setupbps().
43 % 07-Apr-87 (Harold Carr & Leigh Stoller)
44 %  Put in error checking to ensure that the memory pointers will fit in
45 %   info field of the lisp item.
46 % 21-Dec-86 (Leigh Stoller)
47 %  Added allocatemorebps function, called from try-other-bps-spaces in
48 %   allocators.sl.
49 % 18-Dec-86 (Leigh Stoller)
50 %  Changed to newer model. Bps is now defined in bps.c so that unexec can
51 %  alter the text/data boundry. Took out code that allowed command line
52 %  modification of bpssize. (Now set in the Makefile). Added setupbps()
53 %  that initialzes nextbps and lastbps.
54 % 20-Sep-86 (Leigh Stoller)
55 %  Removed assembler alias statements because they are not portable. Instead,
56 %  a sed script will be used to convert the _variables of C to VARIABLES of
57 %  PSL.
58 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
59 */
60 
61 long unexec();
62 
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <errno.h>
66 #include <limits.h>    // for PAGESIZE
67 #include <inttypes.h>  // Make newer integer types  of known width available
68 #include <unistd.h>
69 
70 #ifndef PAGESIZE
71 #define PAGESIZE 4096
72 #endif
73 
74 
75 
76 
77 /* Use 1 if using compacting collector ($pxnk/compact-gc.sl).
78    Use 2 if using copying collector ($pnk/copying-gc.sl).
79    Be sure to update $pxnk/load-psl.sl to include correct collector. */
80 
81 #define NUMBEROFHEAPS 2
82 
83 #define MINSIZE        1000 * 1024 * 1024  /* Default total in number of bytes. */
84 #define MALLOCSIZE     500000              /* Default size for OS support functions. */
85 #define EXTRABPSSIZE   300000              /* Minimum amount to increase bps by. */
86 #define MINIMUMHEAPADD 20000               /* Minimum amount to increase heap by */
87 
88 
89 #ifndef BPSSIZE
90 #define BPSSIZE         1600000    /* Default bps size in number of bytes */
91 #endif
92 
93 extern int Debug;
94 
95 char *  imagefile;
96 char *  abs_imagefile = NULL; /* like imagefile, but as an absolute path */
97 long long   max_image_size;
98 long long   oldbreakvalue;
99 
100 long bpscontrol[2];
101 
102 extern long long  alreadysetupbpsandheap;
103 extern long long  hashtable;
104 extern char bps[];
105 extern long long  symval;
106 extern long long  lastbps;
107 extern long long  nextbps;
108 extern long long  bpslowerbound;
109 extern long long  _infbitlength_;
110 
111 extern long long  heaplowerbound;
112 extern long long  heapupperbound;
113 extern long long  heaplast;
114 extern long long  heaptrapbound;
115 
116 extern long long  oldheaplowerbound;
117 extern long long  oldheapupperbound;
118 extern long long  oldheaplast;
119 extern long long  oldheaptrapbound;
120 
121 /* Write this ourselves to keep from including half the math library */
power(x,n)122 static int power(x, n)
123      int x, n;
124 {
125   int i, p;
126 
127   p = 1;
128   for (i = 1; i <= n; ++i)
129     p = p * x;
130   return(p);
131 }
132 
133 int creloc (long long array, long len, long long diff, long long lowb);
134 
135 long sizeofsymvectors = 0;
136 
137 void setupbps();
138 void getheap(long long);
139 void read_error(char *,long long,long long);
140 
141 int
setupbpsandheap(argc,argv)142 setupbpsandheap(argc,argv)
143      int argc;
144      char *argv[];
145 { long long ohl,ohtb,ohlb,ohub,hl,htb,hlb,hub,diff;
146   int memset = 0;
147   FILE * imago;
148   long long headerword [8];
149   long long i, total, bpssize, heapsize, mallocsize;
150   long long current_size_in_bytes, heapsize_in_bytes;
151   double bpspercent, heappercent;
152   char   *argp, *scanptr, *scanformat;
153   int ii1,ii2,ii3,ii4,ii5,ii6,ii7,ii8,ii9,ii10,ii11;
154   long hugo;
155 
156   total        = MINSIZE;
157   mallocsize    = MALLOCSIZE;
158 
159   for (i=1; i<argc-1; i++)
160     {
161       argp = argv[i];
162       if (*argp++ == '-')
163         {
164           scanformat = "";
165           switch (*argp++) {
166             case 't': scanptr = (char *)&total;
167 		      memset = 1;
168                       switch (*argp) {
169                 case 'x': scanformat = "%x";
170                       break;
171                         case 'd': scanformat = "%d";
172                                   break;
173               }
174                       break;
175             case 'm': scanptr = (char *)&mallocsize;
176                       switch (*argp) {
177                         case 'x': scanformat = "%lx";
178                                   break;
179                         case 'd': scanformat = "%ld";
180                                   break;
181                       }
182                       break;
183 	   case 'f': imagefile = argv[i+1]; break;
184           }
185           if (*scanformat != 0)
186             sscanf(argv[i+1],scanformat,scanptr);
187         }
188     }   /* end of for loop -- arg vector searched */
189 
190   /* insure valid values */
191 
192   if (total < 1000000)  total = total * 1000000;
193 
194   if (total == 0)
195     total = MINSIZE;
196 
197   if (mallocsize <= 0)
198     mallocsize = MALLOCSIZE;
199 
200   /* Reserve some space for C's usr of io buffers, etc. By mallocing then
201      freeing, the memory is sbrk'ed onto the image, but available for future
202      calls to malloc, which will not need to call sbrk again. */
203 
204   bpssize = BPSSIZE;
205 
206   heapsize_in_bytes = total - bpssize;
207 
208   /* On systems in which the image does not start at address 0, this won't
209      really allocate the full maximum, but close enough. */
210   current_size_in_bytes = (((long long) sbrk(0))<<5)>>5;
211   max_image_size = 0x1000000000000; /* 1 more than allowable size */
212 
213   if ((heapsize_in_bytes + current_size_in_bytes) >= max_image_size) {
214     heapsize_in_bytes = max_image_size - current_size_in_bytes;
215     total = heapsize_in_bytes + bpssize;
216 printf("total %llx %llx %llx\n",heapsize_in_bytes , current_size_in_bytes,total);
217     printf("Size requested will result in pointer values larger than\n");
218     printf(" PSL items can handle. Will allocate maximum size instead.\n\n");
219   }
220 
221 #if (NUMBEROFHEAPS == 2)
222   heapsize =(heapsize_in_bytes / 8) * 4;  /* insure full words */
223 #else
224   heapsize =(heapsize_in_bytes / 8) * 8;  /* insure full words */
225 #endif
226 
227   heappercent = ((float) (total - bpssize) / total) * 100.0;
228   bpspercent  = ((float) bpssize / total) * 100.0;
229 
230   if (imagefile == NULL)
231   { printf("Setting heap limit as follows:\n");
232     if (Debug > 0) {
233      printf("Total heap & bps space = %lld (%llx), bps = %.2f, heap = %.2f\n",
234           total, total, bpspercent, heappercent);
235     }
236   }
237 
238   setupbps();
239   if (imagefile != NULL) imago = fopen (imagefile,"r");
240    /* before getheap */
241 
242   getheap(heapsize);
243 
244   if (imagefile == NULL)
245   printf("bpssize = %lld (%llX), heapsize = %lld (%llX)\nTotal image size = %lld (%llX)\n",
246           bpssize, bpssize,
247           heapsize, heapsize,
248           (long long) sbrk(0), (long long) sbrk(0));
249 
250    if (imagefile != NULL) {
251 	ohl = oldheaplowerbound; ohub = oldheapupperbound;
252 	ohl =  oldheaplast; ohtb = oldheaptrapbound;
253         hlb = heaplowerbound; hub = heapupperbound;
254         hl =  heaplast; htb = heaptrapbound;
255     /* save the new values around restore of the old ones */
256 
257        printf("Loading image file: %s \n",imagefile);
258        if (imago == NULL) {
259 	 perror ("error");
260 	 exit (-1);
261        }
262        fread (headerword,8,2,imago);
263        unexec();      /* set control vector */
264        if ((int) bpscontrol[0] != headerword[0]
265 	   || bpscontrol[1] != headerword[1])
266 	 { printf(" Cannot start the image with this bpsl \n");
267 	   printf(" %lx != %llx, %lx != %llx\n", bpscontrol[0], headerword [0], bpscontrol[1], headerword[1]);
268 	   exit (-19);
269 	 }
270        fread (headerword,8,4,imago);
271 #ifdef DEBUG
272 	printf("symbol table: %ld (%lx) bytes\n",headerword[0],headerword[0]);
273 #endif
274        hugo = fread (&symval,1,headerword[0],imago);
275 //       printf("neu: %lx => %lx\n",hlb, heaplowerbound);
276        diff = hlb-heaplowerbound;
277        if (hlb < heaplowerbound)
278              {creloc((long long) &symval,headerword[0]/8,diff,hlb -1);}
279         else {creloc((long long) &symval,headerword[0]/8,diff, heaplowerbound -1);}
280 
281        sizeofsymvectors = headerword[0]/8;
282 
283        if (hugo != headerword[0]) read_error("symbol table",hugo,headerword[0]);
284 
285 #ifdef DEBUG
286 	printf("heap: %ld (%lx) bytes\n",headerword[1],headerword[1]);
287 #endif
288        hugo = fread ((char*)hlb,1,headerword[1],imago);
289        if (hlb < heaplowerbound)
290              {creloc(hlb,headerword[1]/8,diff,hlb -1);}
291         else {creloc(hlb,headerword[1]/8,diff, heaplowerbound -1);}
292        heaplast += diff;
293 
294        if (hugo != headerword[1]) read_error("heap",hugo,headerword[1]);
295 #ifdef DEBUG
296        printf("hash table: %ld (%lx) bytes\n",headerword[2],headerword[2]);
297 #endif
298        hugo = fread (&hashtable,1,headerword[2],imago);
299        if (hugo != headerword[2]) read_error("hash table",hugo,headerword[2]);
300 #ifdef DEBUG
301        printf("BPS: %ld (%lx) bytes\n",headerword[3],headerword[3]);
302 #endif
303        hugo = fread ((char*)bpslowerbound,1,headerword[3],imago);
304        if (hugo != headerword[3]) read_error("BPS",hugo,headerword[3]);
305        fclose (imago);
306        if (memset) {
307         oldheaplowerbound = ohl; oldheapupperbound = ohub;
308         oldheaplast = ohl; oldheaptrapbound = ohtb;
309         heaplowerbound = hlb; heapupperbound = hub;
310         heaptrapbound = htb;}
311        abs_imagefile = realpath(imagefile,NULL);
312        return (4711);
313      }
314 return (0);
315 
316 }
317 
318 void
read_error(char * what,long long bytesread,long long byteswanted)319 read_error(char * what,long long bytesread,long long byteswanted)
320   {
321     printf("File too short while reading %s: bytes read = %lld (%llx), bytes expected = %lld (%llx)\n",
322            what,bytesread,bytesread,byteswanted,byteswanted);
323     exit(-1);
324   }
325 
326 
327 /* The current procedure is to convert the starting address of the char
328    array defined in bps.c to an address and store it in nextbps. A check
329    is made to make sure that nextbps falls on an even word boundry.
330  */
331 
332 #include <sys/mman.h>
333 
334 void
setupbps()335 setupbps()
336 { char *p = (char *) bps;
337   int bpssize;
338   char c;
339 
340   nextbps  =  ((long long)bps + 7) & ~7;        /* Up to a multiple of 8. */
341   bpslowerbound = nextbps;
342   lastbps  =  ((long long)bps + BPSSIZE) & ~7;    /* Down to a multiple of 8. */
343   p = (char *)(((long long) bpslowerbound  -1) & ~(PAGESIZE-1));
344   bpssize =  ((BPSSIZE + PAGESIZE-1) & ~(PAGESIZE-1));
345   if (mprotect(p, bpssize, PROT_READ | PROT_WRITE | PROT_EXEC)) {
346             perror("Couldn’t mprotect");
347             exit(errno);
348           }
349 }
350 
351 
352 /* Allocate alternate bps space. Note: The use of sbrk(), and the fact that
353    nextbps is now greater than heaplast means that unexec should be not be
354    tried after this routine is called. The image would be huge.
355  */
356 long long
allocatemorebps()357 allocatemorebps()
358 {
359   long long current_size_in_bytes;
360   long old_nextbps = nextbps;
361 
362   current_size_in_bytes = (long long)sbrk(0);
363 
364   if ((current_size_in_bytes + EXTRABPSSIZE) >= max_image_size)
365     return(0);
366 
367   if (((long long)sbrk(0)) % 2)      /* force to even word boundary*/
368      nextbps = (long long)sbrk(1);
369 
370   nextbps = (long long)sbrk(EXTRABPSSIZE);   /* allocate extra BPS */
371   if (nextbps == -1) {
372     nextbps = old_nextbps;
373     return(0);
374   }
375   lastbps = nextbps + EXTRABPSSIZE;
376 
377   return(EXTRABPSSIZE);   /* This will be a parameter later */
378 }
379 
380 void
getheap(heapsize)381 getheap(heapsize)
382      long long heapsize;
383 {
384 
385 #if (NUMBEROFHEAPS == 1)
386   heaplowerbound        = (long long)sbrk(heapsize);  /* allocate first heap */;
387   oldheaplowerbound     = -1;
388 #else
389 
390   heaplowerbound        = (long long )malloc(2 * heapsize);  /* allocate first heap */;
391 #endif
392   if (heaplowerbound  == (long long) NULL )  {
393     perror("GETHEAP");
394     exit(-1);
395   }
396   heapupperbound        = heaplowerbound + heapsize;
397   heaplast              = heaplowerbound;
398   heaptrapbound         = heapupperbound -120;
399 
400 #if (NUMBEROFHEAPS == 2)
401   oldheaplowerbound     = heapupperbound;
402   oldheapupperbound     = oldheaplowerbound + heapsize;
403   oldheaplast           = oldheaplowerbound;
404   oldheaptrapbound      = oldheapupperbound -120;
405 #endif
406   oldbreakvalue = (long long )sbrk(0);
407 }
408 
409 /* Tag( alterheapsize )
410  */
411 long long
alterheapsize(increment)412 alterheapsize(increment)
413 int increment;
414 {
415 /*
416   alters the size of the heap by the specified increment.  Returns
417   the increment if successful, otherwise returns 0.  May fail if
418   the sbrk is unsuccessful or if the user tries to cut the heap back
419   to nothing or the current break value does not match the old value.
420   The latter case occurs when a malloc or sbrk has allocated space for
421   some other software, in which case we cannot allocate any more space
422   contiguously.
423 
424   Modifies both the heap and gcarray size.
425   NOTE: a garbage collection should probably be performed before this
426     routine is called.
427   NOTE: only implemented for the one heap version on the 68000.
428 */
429 
430   int heapsize;
431   int current_size_in_bytes;
432   long long diff;
433 
434 #if (NUMBEROFHEAPS == 1)
435   int gcarraysize, newbreakvalue;
436 
437   printf("***** cannot extend heap on this machine\n");
438   return(0);
439 
440   if ((long long) sbrk(0) != oldbreakvalue)  /* Non contiguous memory */
441       return(0);
442 
443   newbreakvalue = oldbreakvalue + increment;
444 
445   /* don't let the user cut his heap back to nothing, taking into account
446      space for the gcarray. */
447   if ((increment < 0) &&
448       ((newbreakvalue - heaplowerbound) <
449        (((heaplast + MINIMUMHEAPADD - heaplowerbound) * 9) / 8)))
450     return(0);
451 
452   current_size_in_bytes = sbrk(0);
453 
454   if ((current_size_in_bytes +  increment) >= max_image_size)
455     return(0);
456 
457   if ((long long)sbrk(increment) == -1)     /* the sbrk failed. */
458      return(0);
459 
460   newbreakvalue = (long long) sbrk(0);
461   heapsize = (((newbreakvalue - heaplowerbound) / 4) * 4);
462 
463   gcarraysize = (((heapsize / 9) / 4) * 4);
464   heapsize = heapsize - gcarraysize;
465 
466   heapupperbound = heaplowerbound + heapsize;
467   heaptrapbound     = heapupperbound;
468 
469   oldbreakvalue    = newbreakvalue;
470   return(increment);
471 #else
472   /* assumes the current heap is the 'lower' one */
473   int newbreakvalue;
474   void * realo;
475 
476   if ((long long) sbrk(0) != oldbreakvalue)  /* Non contiguous memory */
477       {  printf(" unable to allocate %llx %llx\n",(long long)sbrk(0),oldbreakvalue);
478         return(0); }
479 
480   current_size_in_bytes = ( (long long) sbrk(0) <<5) >>5;
481 
482   if ((current_size_in_bytes + 2* increment) >= max_image_size)
483     return(-1);
484 
485   realo = realloc((void *)heaplowerbound,
486                oldheapupperbound - heaplowerbound + 2*increment);
487   if (realo == (void *) NULL) {
488     if (Debug > 0) {
489       fprintf(stderr,"realloc returned NULL\n");
490     }
491      return (-2);
492   }
493   if (Debug > 0) {
494     fprintf(stderr,"Old heaplowerbound = %lld (%llX), new = %lld (%llX)\n",heaplowerbound,heaplowerbound,(long long)realo,(long long)realo);
495   }
496   diff =  realo - (void *)heaplowerbound;
497   if (realo < (void *)heaplowerbound)
498              {creloc((long long) &symval,sizeofsymvectors,diff,(long long)realo -1);}
499         else {creloc((long long) &symval,sizeofsymvectors,diff, heaplowerbound -1);}
500    if (realo < (void *)heaplowerbound)
501              {creloc((long long)realo,(heapupperbound - heaplowerbound)/8,diff,(long long)realo -1);}
502         else {creloc((long long)realo,(heapupperbound - heaplowerbound)/8,diff,
503               heaplowerbound -1);}
504 
505 
506 
507   newbreakvalue = (long long) sbrk(0);
508 
509   heaplowerbound        = (unsigned long long) realo;
510   heaplast              = heaplast + diff ;
511   heapupperbound        = heapupperbound  + diff + increment ;
512   heaptrapbound         = heapupperbound - 120;
513   oldheaplowerbound     = oldheaplowerbound + diff + increment;
514   oldheapupperbound     = oldheapupperbound + diff + 2* increment ;
515   oldheaplast           = oldheaplowerbound + diff ;
516   oldheaptrapbound      = oldheapupperbound -120;
517 
518 
519 /*
520   heapupperbound        = heapupperbound + increment ;
521   heaptrapbound         = heapupperbound - 120;
522   oldheaplowerbound     = oldheaplowerbound + increment;
523   oldheapupperbound     = oldheapupperbound + 2* increment ;
524   oldheaplast           = oldheaplowerbound;
525   oldheaptrapbound      = oldheapupperbound -120;
526 */
527 
528 
529   oldbreakvalue = newbreakvalue;
530   return(increment);
531 #endif
532 
533 }
534 
unexec()535 long unexec()
536 {
537   bpscontrol[0] = bpslowerbound;
538   bpscontrol[1] = BPSSIZE;
539   return((long) bpscontrol);
540 }
541 
get_imagefilepath()542 char * get_imagefilepath ()
543 {
544   return abs_imagefile;
545 }
546