home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / djgpp / go32 / paging.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-30  |  15.2 KB  |  636 lines

  1. /* This is file PAGING.C */
  2. /*
  3. ** Copyright (C) 1991 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
  4. **
  5. ** This file is distributed under the terms listed in the document
  6. ** "copying.dj", available from DJ Delorie at the address above.
  7. ** A copy of "copying.dj" should accompany this file; if not, a copy
  8. ** should be available from where this file was obtained.  This file
  9. ** may not be distributed without a verbatim copy of "copying.dj".
  10. **
  11. ** This file is distributed WITHOUT ANY WARRANTY; without even the implied
  12. ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. */
  14.  
  15. /* History:112,12 */
  16.  
  17. #include <dos.h>
  18. #include <fcntl.h>
  19. #include <io.h>
  20. #include <sys/stat.h>
  21.  
  22. #include "build.h"
  23. #include "types.h"
  24. #include "paging.h"
  25. #include "graphics.h"
  26. #include "tss.h"
  27. #include "gdt.h"
  28. #include "valloc.h"
  29. #include "dalloc.h"
  30. #include "utils.h"
  31. #include "aout.h"
  32. #include "mono.h"
  33.  
  34. #define VERBOSE 0
  35.  
  36. #if DEBUGGER
  37. #define MAX_PAGING_NUM 1
  38. #else
  39. #define MAX_PAGING_NUM 4
  40. #endif
  41.  
  42. extern word32 ptr2linear(void far *ptr);
  43.  
  44. extern TSS *utils_tss;
  45. extern int debug_mode;
  46. extern word16 mem_avail;
  47. extern int self_contained;
  48. extern long header_offset;
  49.  
  50. typedef struct AREAS {
  51.   word32 first_addr;
  52.   word32 last_addr;
  53.   word32 foffset; /* corresponding to first_addr; -1 = zero fill only */
  54.   } AREAS;
  55.  
  56. #define MAX_AREA    8
  57. static AREAS areas[MAX_AREA];
  58. static char *aname[MAX_AREA] = {
  59.     "text ",
  60.     "data ",
  61.     "bss  ",
  62.     "arena",
  63.     "stack",
  64.     "vga  ",
  65.     "syms ",
  66.     "emu"
  67. };
  68. static char achar[MAX_AREA] = "tdbmsg?e";
  69. typedef enum {
  70.   A_text,
  71.   A_data,
  72.   A_bss,
  73.   A_arena,
  74.   A_stack,
  75.   A_vga,
  76.   A_syms,
  77.   A_emu
  78. } AREA_TYPES;
  79.  
  80. static aout_f;
  81. static emu_f;
  82.  
  83. word32 far *pd = 0;
  84. word32 far *graphics_pt;
  85. extern word32 graphics_pt_lin;
  86. char paging_buffer[4096*MAX_PAGING_NUM];
  87.  
  88. handle_screen_swap(word32 far *pt)
  89. {
  90.   struct REGPACK r;
  91.   int have_mono=0;
  92.   int have_color=0;
  93.   int have_graphics=0;
  94.   int save, new, i;
  95.  
  96.   r.r_ax = 0x1200;
  97.   r.r_bx = 0xff10;
  98.   r.r_cx = 0xffff;
  99.   intr(0x10, &r);
  100.   if (r.r_cx == 0xffff)
  101.     pokeb(0x40, 0x84, 25); /* the only size for CGA/MDA */
  102.  
  103.   save = peekb(screen_seg, 0);
  104.   pokeb(screen_seg, 0, ~save);
  105.   new = peekb(screen_seg, 0);
  106.   pokeb(screen_seg, 0, save);
  107.   if (new == ~save)
  108.     have_color = 1;
  109.  
  110.   save = peekb(0xb000, 0);
  111.   pokeb(0xb000, 0, ~save);
  112.   new = peekb(0xb000, 0);
  113.   pokeb(0xb000, 0, save);
  114.   if (new == ~save)
  115.     have_mono = 1;
  116.  
  117.   r.r_ax = 0x0f00;
  118.   intr(0x10, &r);
  119.   if ((r.r_ax & 0xff) > 0x07)
  120.     have_graphics = 1;
  121.  
  122.   if (have_graphics && have_mono)
  123.     have_color = 1;
  124.   else if (have_graphics && have_color)
  125.     have_mono = 1;
  126.  
  127.   if (have_color && !have_mono)
  128.   {
  129.     for (i=0; i<8; i++)
  130.       pt[0xb0+i] = pt[0xb8+i];
  131.     return;
  132.   }
  133.   if (have_mono & !have_color)
  134.   {
  135.     for (i=0; i<8; i++)
  136.       pt[0xb8+i] = pt[0xb0+i];
  137.     return;
  138.   }
  139.  
  140.   if ((biosequip() & 0x0030) == 0x0030) /* mono mode, swap! */
  141.   {
  142.     for (i=0; i<8; i++)
  143.     {
  144.       pt[0xb0+i] ^= pt[0xb8+i];
  145.       pt[0xb8+i] ^= pt[0xb0+i];
  146.       pt[0xb0+i] ^= pt[0xb8+i];
  147.     }
  148.     return;
  149.   }
  150. }
  151.  
  152. paging_set_file(char *fname)
  153. {
  154.   word32 far *pt;
  155.   FILEHDR filehdr;
  156.   AOUTHDR aouthdr;
  157.   SCNHDR scnhdr[3];
  158.   GNU_AOUT gnu_aout;
  159.   int i;
  160.   aout_f = open(fname, O_RDONLY|O_BINARY);
  161.   if (aout_f < 0)
  162.   {
  163.     printf("Can't open file <%s>\n", fname);
  164.     exit(1);
  165.   }
  166.  
  167. #if TOPLINEINFO
  168.   for (i=0; fname[i]; i++)
  169.     poke(screen_seg, i*2+10, fname[i] | 0x0700);
  170. #endif
  171.  
  172.   lseek(aout_f, header_offset, 0);
  173.  
  174.   read(aout_f, &filehdr, sizeof(filehdr));
  175.   if (filehdr.f_magic != 0x14c)
  176.   {
  177.     lseek(aout_f, header_offset, 0);
  178.     read(aout_f, &gnu_aout, sizeof(gnu_aout));
  179.     a_tss.tss_eip = gnu_aout.entry;
  180.     aouthdr.tsize = gnu_aout.tsize;
  181.     aouthdr.dsize = gnu_aout.dsize;
  182.     aouthdr.bsize = gnu_aout.bsize;
  183.   }
  184.   else
  185.   {
  186.     read(aout_f, &aouthdr, sizeof(aouthdr));
  187.     a_tss.tss_eip = aouthdr.entry;
  188.     read(aout_f, scnhdr, sizeof(scnhdr));
  189.   }
  190.   a_tss.tss_cs = g_acode*8;
  191.   a_tss.tss_ds = g_adata*8;
  192.   a_tss.tss_es = g_adata*8;
  193.   a_tss.tss_fs = g_adata*8;
  194.   a_tss.tss_gs = g_adata*8;
  195.   a_tss.tss_ss = g_adata*8;
  196.   a_tss.tss_esp = 0x7ffffffc;
  197.  
  198.   if (filehdr.f_magic == 0x14c)
  199.   {
  200.     areas[0].first_addr = aouthdr.text_start + ARENA;
  201.     areas[0].foffset = scnhdr[0].s_scnptr + header_offset;
  202.     areas[0].last_addr = areas[0].first_addr + aouthdr.tsize;
  203.   }
  204.   else if (filehdr.f_magic == 0x10b)
  205.   {
  206.     areas[0].first_addr = ARENA;
  207.     if (a_tss.tss_eip >= 0x1000)    /* leave space for null reference */
  208.       areas[0].first_addr += 0x1000;    /* to cause seg fault */
  209.     areas[0].foffset = header_offset;
  210.     areas[0].last_addr = areas[0].first_addr + aouthdr.tsize + 0x20;
  211.   }
  212. #if DEBUGGER
  213.   else if (filehdr.f_magic == 0x107)
  214.   {
  215.     struct stat sbuf;
  216.     fstat(aout_f, &sbuf);
  217.     areas[0].first_addr = ARENA;
  218.     areas[0].foffset = 0x20 + header_offset;
  219.     areas[0].last_addr = sbuf.st_size + ARENA - 0x20;
  220.   }
  221.   else
  222.   {
  223.     struct stat sbuf;
  224.     fstat(aout_f, &sbuf);
  225.     areas[0].first_addr = ARENA;
  226.     areas[0].foffset = header_offset;
  227.     areas[0].last_addr = sbuf.st_size + ARENA;
  228.   }
  229. #else
  230.   else
  231.   {
  232.     printf("Unknown file type 0x%x (0%o)\n", filehdr.f_magic, filehdr.f_magic);
  233.     exit(-1);
  234.   }
  235. #endif
  236. #if DEBUGGER
  237.   if (debug_mode)
  238.     printf("%ld+", aouthdr.tsize);
  239. #endif
  240.  
  241.   if (filehdr.f_magic == 0x14c)
  242.   {
  243.     areas[1].first_addr = aouthdr.data_start + ARENA;
  244.     areas[1].foffset = scnhdr[1].s_scnptr + header_offset;
  245.   }
  246.   else
  247.   {
  248.     areas[1].first_addr = (areas[0].last_addr+0x3fffffL)&~0x3fffffL;
  249.     areas[1].foffset = ((aouthdr.tsize + 0x20 + 0xfffL) & ~0xfffL) + header_offset;
  250.   }
  251.   areas[1].last_addr = areas[1].first_addr + aouthdr.dsize - 1;
  252. #if DEBUGGER
  253.   if (debug_mode)
  254.     printf("%ld+", aouthdr.dsize);
  255. #endif
  256.  
  257.   areas[2].first_addr = areas[1].last_addr + 1;
  258.   areas[2].foffset = -1;
  259.   areas[2].last_addr = areas[2].first_addr + aouthdr.bsize - 1;
  260. #if DEBUGGER
  261.   if (debug_mode)
  262.     printf("%ld = %ld\n", aouthdr.bsize,
  263.       aouthdr.tsize+aouthdr.dsize+aouthdr.bsize);
  264. #endif
  265.  
  266.   areas[3].first_addr = areas[2].last_addr;
  267.   areas[3].last_addr = areas[3].first_addr;
  268.   areas[3].foffset = -1;
  269.  
  270.   areas[4].first_addr = 0x50000000;
  271.   areas[4].last_addr = 0x8fffffff;
  272.   areas[4].foffset = -1;
  273.  
  274.   areas[5].first_addr = 0xe0000000;
  275.   areas[5].last_addr = 0xe03fffff;
  276.   areas[5].foffset = -1;
  277.  
  278.   areas[A_syms].first_addr = 0xa0000000;
  279.   areas[A_syms].last_addr = 0xafffffff;
  280.   areas[A_syms].foffset = -1;
  281.  
  282.   pd = (word32 far *)((long)valloc(VA_640) << 24);
  283.   pt = (word32 far *)((long)valloc(VA_640) << 24);
  284.   for (i=0; i<1024; i++)
  285.     pd[i] = 0;
  286.   for (i=0; i<256; i++)
  287.     pt[i] = ((unsigned long)i<<12) | PT_P | PT_W | PT_I;
  288.   for (; i<1024; i++)
  289.     pt[i] = 0;
  290.   pd[0] = ((word32)pt >> 12) | PT_P | PT_W | PT_I;    /* map 0-1M 1:1 */
  291.   pd[0x3c0] = ((word32)pt >> 12) | PT_P | PT_W | PT_I;    /* map also to 0xF0000000 */
  292.   handle_screen_swap(pt);
  293.  
  294.   graphics_pt = (word32 far *)((long)valloc(VA_640) << 24);
  295.   graphics_pt_lin = ptr2linear(graphics_pt);
  296.   for (i=0; i<1024; i++)
  297.     graphics_pt[i] = 0x000a0000L | ((i * 4096L) & 0xffffL) | PT_W | PT_U;
  298.   pd[0x380] = ((word32)graphics_pt >> 12) | PT_P | PT_W | PT_U;
  299.  
  300.   c_tss.tss_cr3 = (unsigned long)pd >> 12;
  301.   a_tss.tss_cr3 = (unsigned long)pd >> 12;
  302.   o_tss.tss_cr3 = (unsigned long)pd >> 12;
  303.   i_tss.tss_cr3 = (unsigned long)pd >> 12;
  304.   p_tss.tss_cr3 = (unsigned long)pd >> 12;
  305.   f_tss.tss_cr3 = (unsigned long)pd >> 12;
  306.  
  307. #if VERBOSE
  308.     for (i=0; i<5; i++)
  309.       printf("%d %-10s %08lx-%08lx (offset 0x%08lx)\n", i, aname[i], areas[i].first_addr, areas[i].last_addr, areas[i].foffset);
  310. #endif
  311. }
  312.  
  313. #if TOPLINEINFO
  314. static update_status(int c, int col)
  315. {
  316.   int r;
  317.   r = peek(screen_seg, 2*79);
  318.   poke(screen_seg, 2*col, c);
  319.   return r;
  320. }
  321. #endif
  322.  
  323. word32 paging_brk(word32 b)
  324. {
  325.   word32 r = (areas[3].last_addr - ARENA + 7) & ~7;
  326.   areas[3].last_addr = b + ARENA;
  327.   return r;
  328. }
  329.  
  330. word32 paging_sbrk(int32 b)
  331. {
  332.   word32 r = (areas[3].last_addr - ARENA + 7) & ~7;
  333.   areas[3].last_addr = r + b + ARENA;
  334.   return r;
  335. }
  336.  
  337. page_is_valid(word32 vaddr)
  338. {
  339.   int a;
  340.   for (a=0; a<MAX_AREA; a++)
  341.     if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
  342.       return 1;
  343.   if (vaddr >= 0xf000000L)
  344.     return 1;
  345.   return 0;
  346. }
  347.  
  348. page_in()
  349. {
  350.   int old_status;
  351.   TSS *old_util_tss;
  352.   word32 far *pt;
  353.   word32 far *p;
  354.   word32 vaddr, foffset, cnt32;
  355.   word32 eaddr, vtran, vcnt, zaddr;
  356.   int pdi, pti, pn, a, cnt, count;
  357.   unsigned dblock;
  358.  
  359. #if 0
  360.   unsigned char buf[100];
  361.   sprintf(buf, "0x%08lx", a_tss.tss_cr2 - ARENA);
  362.   for (a=0; buf[a]; a++)
  363.     poke(screen_seg, 80+a*2, 0x0600 | buf[a]);
  364. #endif
  365.  
  366.   old_util_tss = utils_tss;
  367.   utils_tss = &f_tss;
  368.   vaddr = tss_ptr->tss_cr2;
  369.  
  370.   for (a=0; a<MAX_AREA; a++)
  371.     if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
  372.       goto got_area;
  373.  
  374.   printf("Segmentation Violation referencing address %#lx\n",
  375.          tss_ptr->tss_cr2-ARENA);
  376. #if !DEBUGGER
  377. /*  exit(1); */
  378. #endif
  379.   return 1;
  380.  
  381. got_area:
  382.   vaddr &= 0xFFFFF000;    /* points to beginning of page */
  383. #if 0 /* handled in protected mode for speed */
  384.   if (a == A_vga)
  385.     return graphics_fault(vaddr, graphics_pt);
  386. #endif
  387.  
  388. #if VERBOSE
  389.     printf("area(%d) - ", a);
  390. #endif
  391.  
  392.   if ((a == 2) & (vaddr < areas[a].first_addr)) /* bss, but data too */
  393.   {
  394. #if VERBOSE
  395.       printf("split page (data/bss) detected - ");
  396. #endif
  397.     a = 1; /* set to page in data */
  398.   }
  399.  
  400. #if TOPLINEINFO
  401.   old_status = update_status(achar[a] | 0x0a00, 78);
  402. #endif
  403. #if VERBOSE
  404.   printf("Paging in %s block for vaddr %#010lx -", aname[a], tss_ptr->tss_cr2-ARENA);
  405. #endif
  406.   pdi = (vaddr >> 22) & 0x3ff;
  407.   if (!(pd[pdi] & PT_P))    /* put in an empty page table if required */
  408.   {
  409.     pn = valloc(VA_640);
  410.     pt = (word32 far *)((word32)pn << 24);
  411.     pd[pdi] = ((word32)pn<<12) | PT_P | PT_W | PT_I | PT_S;
  412.     for (pti=0; pti<1024; pti++)
  413.       pt[pti] = PT_W | PT_S;
  414.   }
  415.   else
  416.     pt = (word32 far *)((pd[pdi]&~0xFFF) << 12);
  417.   pti = (vaddr >> 12) & 0x3ff;
  418.   if (pt[pti] & PT_P)
  419.   {
  420.     utils_tss = old_util_tss;
  421. #if TOPLINEINFO
  422.     update_status(old_status, 78);
  423. #endif
  424.     return 0;
  425.   }
  426.   count = MAX_PAGING_NUM;
  427.   if (count > mem_avail/4)
  428.     count = mem_avail/4;
  429.   if (pti + count > 1024)
  430.     count = 1024 - pti;
  431.   if (vaddr + count*4096L > areas[a].last_addr+4096L)
  432.     count = (areas[a].last_addr - vaddr + 4095) / 4096;
  433.   if (count < 1)
  434.     count = 1;
  435.   zaddr = eaddr = -1;
  436.   vtran = vaddr;
  437.   vcnt = 0;
  438.   for (; count; count--, pti++, vaddr+=4096)
  439.   {
  440.     if (pt[pti] & PT_P)
  441.       break;
  442.     dblock = pt[pti] >> 12;
  443.     pn = valloc(VA_1M);
  444.     pt[pti] &= 0xfffL & ~(word32)(PT_A | PT_D | PT_C);
  445.     pt[pti] |= ((word32)pn << 12) | PT_P;
  446.  
  447.     if (pt[pti] & PT_I)
  448.     {
  449. #if VERBOSE
  450.         printf(" swap");
  451. #endif
  452.       dread(paging_buffer, dblock);
  453.       dfree(dblock);
  454.       memput(vaddr, paging_buffer, 4096);
  455.     }
  456.     else
  457.     {
  458.       if (areas[a].foffset != -1)
  459.       {
  460. #if VERBOSE
  461.         if (a == A_emu)
  462.           printf(" emu");
  463.         else
  464.           printf(" exec");
  465. #endif
  466.         if (eaddr == -1)
  467.         {
  468.           eaddr = areas[a].foffset + (vaddr - areas[a].first_addr);
  469.           vtran = vaddr;
  470.         }
  471.         cnt32 = areas[a].last_addr - vaddr + 1;
  472.         if (cnt32 > 4096)
  473.           cnt32 = 4096;
  474.         else
  475.           zaddr = vaddr;
  476.         vcnt += cnt32;
  477.       }
  478.       else
  479.       {
  480.         zero32(vaddr);
  481. #if VERBOSE
  482.         printf(" zero");
  483. #endif
  484.       }
  485.       pt[pti] |= PT_I;
  486.     }
  487.   }
  488.   if (eaddr != -1)
  489.   {
  490.     int cur_f, rsize;
  491.     if (a == A_emu)
  492.       cur_f = emu_f;
  493.     else
  494.       cur_f = aout_f;
  495.     lseek(cur_f, eaddr, 0);
  496.     rsize = read(cur_f, paging_buffer, vcnt);
  497.     if (rsize < vcnt)
  498.       memset(paging_buffer+rsize, 0, vcnt-rsize);
  499.     if (zaddr != -1)
  500.       zero32(zaddr);
  501.     memput(vtran, paging_buffer, vcnt);
  502.   }
  503. #if VERBOSE
  504.   printf("\n");
  505. #endif
  506.   utils_tss = old_util_tss;
  507. #if TOPLINEINFO
  508.   update_status(old_status, 78);
  509. #endif
  510.   return 0;
  511. }
  512.  
  513. static last_po_pdi = 0;
  514. static last_po_pti = 0;
  515.  
  516. int page_out() /* return 1 if paged out, 0 if not */
  517. {
  518.   int start_pdi, start_pti, old_status;
  519.   word32 far *pt, v;
  520.   unsigned dblock, pn;
  521. #if TOPLINEINFO
  522.   old_status = update_status('>' | 0x0a00, 79);
  523. #endif
  524.   start_pdi = last_po_pdi;
  525.   start_pti = last_po_pti;
  526.   pt = (word32 far *)((pd[last_po_pdi]&~0xFFF) << 12);
  527.   do {
  528.     if ((pd[last_po_pdi] & (PT_P | PT_S)) == (PT_P | PT_S))
  529.     {
  530.       if ((pt[last_po_pti] & (PT_P | PT_S)) == (PT_P | PT_S))
  531.       {
  532.         pn = pt[last_po_pti] >> 12;
  533.         dblock = dalloc();
  534.         v = ((word32)last_po_pdi << 22) | ((word32)last_po_pti << 12);
  535.         memget(v, paging_buffer, 4096);
  536.         dwrite(paging_buffer, dblock);
  537.         pt[last_po_pti] &= 0xfff & ~PT_P; /* no longer present */
  538.         pt[last_po_pti] |= (long)dblock << 12;
  539.         vfree(pn);
  540. #if TOPLINEINFO
  541.         update_status(old_status, 79);
  542. #endif
  543.         return 1;
  544.       }
  545.     }
  546.     else /* imagine we just checked the last entry */
  547.       last_po_pti = 1023;
  548.     if (++last_po_pti == 1024)
  549.     {
  550.       last_po_pti = 0;
  551.       if (++last_po_pdi == 1024)
  552.         last_po_pdi = 0;
  553.       pt = (word32 far *)((pd[last_po_pdi]&~0xFFF) << 12);
  554.     }
  555.   } while ((start_pdi != last_po_pdi) || (start_pti != last_po_pti));
  556. #if TOPLINEINFO
  557.   update_status(old_status, 79);
  558. #endif
  559.   return 0;
  560. }
  561.  
  562. unsigned pd_dblock;
  563.  
  564. page_out_everything()
  565. {
  566.   int pdi;
  567.   unsigned ptb;
  568.   void far *fp;
  569.   while (page_out());
  570.   for (pdi=0; pdi<1024; pdi++)
  571.     if (pd[pdi])
  572.     {
  573.       ptb = dalloc();
  574.       fp = (void far *)((pd[pdi]&~0xFFF)<<12);
  575.       movedata(FP_SEG(fp), FP_OFF(fp), _DS, paging_buffer, 4096);
  576.       dwrite(paging_buffer, ptb);
  577.       vfree(pd[pdi]>>12);
  578.       pd[pdi] = (pd[pdi] & (0xFFF&~PT_P)) | ((word32)ptb<<12);
  579.     }
  580.   movedata(FP_SEG(pd), FP_OFF(pd), _DS, paging_buffer, 4096);
  581.   pd_dblock = dalloc();
  582.   dwrite(paging_buffer, pd_dblock);
  583.   vfree(((word32)pd)>>24);
  584.   xms_free();
  585. }
  586.  
  587. extern int valloc_initted;
  588.  
  589. page_in_everything()
  590. {
  591.   int pdi;
  592.   unsigned ptb;
  593.   word32 far *pt;
  594.   unsigned pta;
  595.   valloc_initted = 0;
  596.   pta = valloc(VA_640);
  597.   pd = (word32 far *)((word32)pta << 24);
  598.   dread(paging_buffer, pd_dblock);
  599.   dfree(pd_dblock);
  600.   movedata(_DS, paging_buffer, FP_SEG(pd), FP_OFF(pd), 4096);
  601.   for (pdi=0; pdi<1024; pdi++)
  602.     if (pd[pdi])
  603.     {
  604.       pta = valloc(VA_640);
  605.       pt = (word32 far *)((word32)pta << 24);
  606.       ptb = pd[pdi] >> 12;
  607.       dread(paging_buffer, ptb);
  608.       dfree(ptb);
  609.       movedata(_DS, paging_buffer, FP_SEG(pt), FP_OFF(pt), 4096);
  610.       pd[pdi] = (pd[pdi] & 0xFFF) | ((word32)pta<<12) | PT_P;
  611.     }
  612.   graphics_pt = (word32 far *)((pd[0x380]&~0xfff) << 12);
  613.   graphics_pt_lin = ptr2linear(graphics_pt);
  614. }
  615.  
  616.  
  617. int emu_install(char *filename)
  618. {
  619.   GNU_AOUT eh;
  620.   areas[A_emu].first_addr = EMU_TEXT+ARENA;
  621.   areas[A_emu].last_addr = EMU_TEXT-1+ARENA;
  622.   areas[A_emu].foffset = 0;
  623.  
  624.   if (filename == 0)
  625.     return 0;
  626.   emu_f = open(filename, O_RDONLY|O_BINARY);
  627.   if (emu_f < 0)
  628.   {
  629.     printf("Can't open 80387 emulator file <%s>\n", filename);
  630.     return 0;
  631.   }
  632.   read(emu_f, &eh, sizeof(eh));
  633.   areas[A_emu].last_addr += eh.tsize + eh.dsize + eh.bsize + 0x20;
  634.   return 1;
  635. }
  636.