ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/paging.c

This is paging.c in view mode; [Download] [Up]

/* This is file PAGING.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained.  This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
/* Modified for DPMI Implement by H.Tsubakimoto */
/* NUR paging algorithm by rcharif@math.utexas.edu */
/* Merged DPMI with V1.09+ code C. Sandmann sandmann@clio.rice.edu */

#include <stdio.h>
#include <dos.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <bios.h>
#include <string.h>
#include <stdlib.h>

#include "gotypes.h"
#include "paging.h"
#include "graphics.h"
#include "tss.h"
#include "idt.h"
#include "gdt.h"
#include "valloc.h"
#include "dalloc.h"
#include "utils.h"
#include "aout.h"
#include "mono.h"
#include "vcpi.h"
#include "dpmi.h"
#include "extdebug.h"
#include "exphdlr.h"
#include "stubinfo.h"
#include "proginfo.h"
#include "control.h"

#define VERBOSE 0

#define KEEP_ON_EXEC

#define MAX_PAGING_NUM 2


#define DOS_PAGE 256            /*  1MB / 4KB = 256 Pages  */


extern char transfer_buffer[4096];

extern word32 ptr2linear(void far *ptr);

struct {
  word16 limit;
  word32 base;
} gdt_phys, idt_phys;

CLIENT  client;         /*  VCPI Change Mode Structure  */
word32  abs_client;     /*  _DS * 16L + &client         */
far32   vcpi_entry;
SYS_TBL int_descriptor;
SYS_TBL gbl_descriptor;

extern word16 vcpi_installed;   /*  VCPI Installed Flag  */
extern near protect_entry();
word32 DPMI_STACK = 0x40000L; /* 256Kb Min */
#define DPMIgetpage 0xffffL /* 64K instead of 4K for speed */
DPMImemory DPMImem;         /* protected memory block */
static word32 oldbase;     /* DPMI selector base for allocated memory */
static word16 DPMIselect; /* selectors for application */
                          /* DPMIselect + 0  : data selector */
                          /* DPMIselect + 8  : code selector */
                          /* DPMIselect + 16 : stack selector */ 
                          /* DPMIselect + 24 : linear 1Mb range */ 

extern TSS *utils_tss;
extern int debug_mode;
extern word32 mem_avail;
extern int self_contained;
extern long header_offset;

word16 core_selector, arena_ds, arena_cs;

AREAS areas[MAX_AREA];
#if VERBOSE
static char *aname[MAX_AREA] = {
        "text ",
        "data ",
        "bss  ",
        "arena",
        "stack",
        "vga  ",
        "syms ",
        "syms2",
        "emu"
};
#endif
static char achar[MAX_AREA] = "tdbmsg?e";

word32 far *pd = 0;
word8 pd_seg[1024];
word32 far *vcpi_pt = 0;
word8 paging_buffer[4096*MAX_PAGING_NUM];

word32 screen_primary, screen_secondary;

word32 ptr2linear(void far *ptr)
{
  return (word32)FP_SEG(ptr) * 16L + (word32)FP_OFF(ptr);
}

static word32 far2pte(void far *ptr, word32 flags)
{
  return (vcpi_pt[(int)(((word32)ptr) >> 24)] & 0xfffff000L) | flags;
}

static word32 pn2pte(unsigned pn, word32 flags)
{
  return (vcpi_pt[pn] & 0xfffff000L) | flags;
}

static void setDPMISelectors(int firsttime)
{
  int selfail;

  selfail = 0;
  if(!DPMIassignSelector(DPMIselect, 0xc0b3, DPMImem.address,
      DPMImem.bytes - 1 ) ) selfail = 1; /* win 3.1 needs f, 3.0 b */

  if(firsttime){
    if(!DPMIassignSelector(DPMIselect + 8, 0xc0bb, DPMImem.address, 
        DPMImem.bytes - 1) ) selfail |= 2;
    if(!DPMIassignSelector(DPMIselect + 16, 0xc0b7, DPMImem.address,
        (areas[A_stack].first_addr - 1) ) ) selfail |= 4;
  } else if(DPMImem.address != oldbase) {
    if(!DPMISelectorBase(DPMIselect + 8, DPMImem.address) ) selfail |= 10;
    if(!DPMISelectorBase(DPMIselect + 16, DPMImem.address) ) selfail |= 12;
    if(using_external_debugger) {
      DPMIrealMode();
      clear_break_DPMI();       /* This clears the breakpoints */
      set_break_DPMI();         /* This resets them with new base */
      DPMIprotectedMode();
    }
  }
  oldbase = DPMImem.address;

#if VERBOSE
  if(selfail) {
    /* For some reason stack #4 fails under OS2 but it still works; thus
       the workaround is to ignore this section unless in verbose mode */
    DPMIrealMode();
    fprintf(stderr,"DPMI: AssignSelector %d failed!\n",selfail);
/*    exit(3);  */
    DPMIprotectedMode();  /* Only if exit commented */
  }
#endif
}

void loadAout(const AREAS* areas)
{
  word32 count = areas->last_addr + 1 - areas->first_addr;

  if (count > 0) {
    word32 loadAddr = areas->first_addr;
    lseek(areas->fileno, areas->foffset, 0);
    while (count > 0) {
      word16 readBytes;
      word16 bytes = (count > 4096) ? 4096 : (word16)count;
      readBytes = read(areas->fileno, transfer_buffer, bytes);
      if (readBytes < bytes) memset(transfer_buffer + readBytes, 0, bytes - readBytes);
      memput(loadAddr, transfer_buffer, bytes);
      loadAddr += bytes;
      count -= bytes;
    }
  }
}

void clearDPMIstate(void)
{
  DPMIfree(&DPMImem);  /* QDPMI bug fix - child processes don't free memory */
}

static void saveDPMIstate(void)
{
  int a;
  word32 firsta, lengtha;
  word16 bytes;
  unsigned block;

  block = 0;
  for (a=0; a<MAX_AREA; a++) {
    firsta = areas[a].first_addr;
    if ( a == A_stack ) firsta = a_tss.tss_esp & 0xfffff000L;
    lengtha = areas[a].last_addr - firsta + 1;
    while (lengtha > 0) {
      bytes = (lengtha > 4096) ? 4096 : (word16)lengtha;
      Pmemget(DPMIselect, firsta, paging_buffer, bytes);
      dwrite(paging_buffer, block++);
      firsta += bytes;
      lengtha -= bytes;
    }
  }
  DPMIprotectedMode();
  DPMIfree(&DPMImem);
  restoreDPMIvector();
  DPMIrealMode();
}

static void restoreDPMIstate(void)
{
  int a;
  word32 firsta, lengtha;
  word16 bytes;
  unsigned block;

  DPMIprotectedMode();
  setDPMIvector();
  lengtha = (areas[A_arena].last_addr + 1 + DPMIgetpage) & ~DPMIgetpage;
  if (! DPMIalloc(&DPMImem, lengtha)) {
    DPMIrealMode();
    fprintf(stderr,"\nDPMI: Not enough memory (0x%08lx bytes).\n", lengtha);
    exit(3);
  }
  setDPMISelectors(0);
  DPMIrealMode();
  firsta = areas[A_arena].last_addr + 1;
  if(lengtha > firsta)
    Pmemset(DPMIselect, firsta, 0, lengtha - firsta );

  block = 0;
  for (a=0; a<MAX_AREA; a++) {
    firsta = areas[a].first_addr;
    if ( a == A_stack ) firsta = a_tss.tss_esp & 0xfffff000L;
    lengtha = areas[a].last_addr - firsta + 1;
    while (lengtha > 0) {
      bytes = (lengtha > 4096) ? 4096 : (word16)lengtha;
      dread(paging_buffer, block++);
      Pmemput(DPMIselect, firsta, paging_buffer, bytes);
      firsta += bytes;
      lengtha -= bytes;
    }
  }
}

int changeBreak(word32 breakPoint)
{
  word32 oldbytes, newbytes;

  newbytes = (breakPoint + DPMIgetpage) & ~DPMIgetpage; /* 64K for performance */
  oldbytes = DPMImem.bytes;
  if (newbytes < areas[A_arena].first_addr) newbytes=areas[A_arena].first_addr;
#if VERBOSE
  fprintf(stderr,"changeBreak: old=0x%08lx  break=0x%08lx  new=0x%08lx\n",
    oldbytes, breakPoint, newbytes);
#endif
  if (DPMImem.bytes != newbytes) {
    DPMIprotectedMode();
    if (! DPMIrealloc(&DPMImem, newbytes)) {
      DPMIrealMode();
      fprintf(stderr,"\nDPMI: Not enough memory (0x%08lx bytes).\n", newbytes);
      return 0;
    }
    setDPMISelectors(0);
    DPMIrealMode();
  }
  if(newbytes > oldbytes) 
    Pmemset(DPMIselect, oldbytes, 0, newbytes - oldbytes );
  return 1;
}

/*  VCPI Get Interface  */
void    link_vcpi(word32 far *dir, word32 far *table)
{

  vcpi_entry.selector = g_vcpicode * 8;
  vcpi_entry.offset32 = get_interface(table,&gdt[g_vcpicode]);
  client.page_table   = far2pte(dir, 0); /* (word32)dir>>12; */
  client.gdt_address  = ptr2linear(&gdt_phys);
  client.idt_address  = ptr2linear(&idt_phys);
  client.ldt_selector = 0;
  client.tss_selector = g_ctss * 8;
  client.entry_eip    = (word16)protect_entry;
  client.entry_cs     = g_rcode * 8;

  abs_client = ptr2linear(&client);
}

void handle_screen_swap(word32 far *pt)
{
  struct REGPACK r;
  int have_mono=0;
  int have_color=0;
  int have_graphics=0;
  int save, new;

  r.r_ax = 0x1200;
  r.r_bx = 0xff10;
  r.r_cx = 0xffff;
  intr(0x10, &r);
  if (r.r_cx == 0xffff)
    pokeb(0x40, 0x84, 24); /* the only size for CGA/MDA */

  if (!vcpi_installed || (pt[0xb8] & (PT_U|PT_W)) == (PT_W|PT_U))
  {
    save = peekb(screen_seg, 0);
    pokeb(screen_seg, 0, ~save);
    new = peekb(screen_seg, 0);
    pokeb(screen_seg, 0, save);
    if (new == ~save)
      have_color = 1;
  }

  if (!vcpi_installed || (pt[0xb0] & (PT_U|PT_W)) == (PT_W|PT_U))
  {
    save = peekb(0xb000, 0);
    pokeb(0xb000, 0, ~save);
    new = peekb(0xb000, 0);
    pokeb(0xb000, 0, save);
    if (new == ~save)
      have_mono = 1;
  }

  r.r_ax = 0x0f00;
  intr(0x10, &r);
  if ((r.r_ax & 0xff) > 0x07)
    have_graphics = 1;

  if (have_graphics && have_mono)
    have_color = 1;
  else if (have_graphics && have_color)
    have_mono = 1;

  screen_primary = 0xe00b8000L;
  screen_secondary = 0xe00b0000L;

  if (have_color && !have_mono)
  {
    screen_secondary = 0xe00b8000L;
    return;
  }
  if (have_mono & !have_color)
  {
    screen_primary = 0xe00b0000L;
    return;
  }

  if ((biosequip() & 0x0030) == 0x0030) /* mono mode, swap! */
  {
    screen_primary = 0xe00b0000L;
    screen_secondary = 0xe00b8000L;
    return;
  }
}

void paging_set_file(char *fname)
{
  word32 newbytes;
  word32 far *pt;
  FILEHDR filehdr;
  AOUTHDR aouthdr;
  SCNHDR scnhdr[3];
  GNU_AOUT gnu_aout;
  unsigned short *exe_hdr;
  int i;
  int aout_f;

  aout_f = open(fname, O_RDONLY|O_BINARY);
  if (aout_f < 0)
  {
    fprintf(stderr, "Can't open file <%s>\n", fname);
    exit(1);
  }
  
  areas[A_text].fileno = aout_f;
  areas[A_data].fileno = aout_f;
  for (i=A_bss; i<A_max; i++)
    areas[i].fileno = 0;

  if (topline_info)
    for (i=0; fname[i]; i++)
      poke(screen_seg, i*2+10, fname[i] | 0x0700);

  lseek(aout_f, header_offset, 0);
  read(aout_f, &filehdr, sizeof(filehdr));

  if (filehdr.f_magic == 0x5a4d) /* .EXE */
  {
    exe_hdr = (unsigned short *)&filehdr;
    header_offset += (long)exe_hdr[2]*512L;
    if (exe_hdr[1])
      header_offset += (long)exe_hdr[1] - 512L;
    lseek(aout_f, header_offset, 0);
    read(aout_f, &filehdr, sizeof(filehdr));
  }

  if (filehdr.f_magic != 0x14c)
  {
    lseek(aout_f, header_offset, 0);
    read(aout_f, &gnu_aout, sizeof(gnu_aout));
    a_tss.tss_eip = gnu_aout.entry;
    aouthdr.tsize = gnu_aout.tsize;
    aouthdr.dsize = gnu_aout.dsize;
    aouthdr.bsize = gnu_aout.bsize;
  }
  else
  {
    if (filehdr.f_opthdr)
    {
      read(aout_f, &aouthdr, sizeof(aouthdr));
      a_tss.tss_eip = aouthdr.entry;
    }
    else
      a_tss.tss_eip = 0;
    read(aout_f, scnhdr, sizeof(scnhdr));
    if (! filehdr.f_opthdr)
    {
      aouthdr.tsize = scnhdr[0].s_size;
      aouthdr.dsize = scnhdr[1].s_size;
      aouthdr.bsize = scnhdr[2].s_size;
    }
  }
  arena_cs =
  a_tss.tss_cs = g_acode*8;
  arena_ds =
  a_tss.tss_ds =
  a_tss.tss_es =
  a_tss.tss_fs =
  a_tss.tss_ss = g_adata*8;
  a_tss.tss_esp = 0x7ffffffcL;

  if (filehdr.f_magic == 0x14c && filehdr.f_opthdr)
  {
    areas[A_text].first_addr = aouthdr.text_start + ARENA;
    areas[A_text].foffset = scnhdr[0].s_scnptr + header_offset;
    areas[A_text].last_addr = areas[A_text].first_addr + aouthdr.tsize - 1;
  }
  else if (filehdr.f_magic == 0x14c && debug_mode)
  {
    areas[A_text].first_addr = scnhdr[0].s_vaddr + ARENA;
    areas[A_text].foffset = scnhdr[0].s_scnptr + header_offset;
    areas[A_text].last_addr = areas[A_text].first_addr + scnhdr[0].s_size - 1;
  }
  else if (filehdr.f_magic == 0x10b)
  {
    areas[A_text].first_addr = ARENA;
    if (a_tss.tss_eip >= 0x1000)        /* leave space for null reference */
      areas[A_text].first_addr += 0x1000;    /* to cause seg fault */
    areas[A_text].foffset = header_offset;
    areas[A_text].last_addr = areas[A_text].first_addr + aouthdr.tsize + 0x20 - 1;
  }
  else if (debug_mode && filehdr.f_magic == 0x107)
  {
    struct stat sbuf;
    fstat(aout_f, &sbuf);
    areas[A_text].first_addr = ARENA;
    areas[A_text].foffset = 0x20 + header_offset;
    areas[A_text].last_addr = sbuf.st_size + ARENA - 0x20;
  }
  else if (debug_mode)
  {
    struct stat sbuf;
    fstat(aout_f, &sbuf);
    areas[A_text].first_addr = ARENA;
    areas[A_text].foffset = header_offset;
    areas[A_text].last_addr = sbuf.st_size + ARENA;
  }
  else
  {
    fprintf(stderr, "Unknown file type 0x%x (0%o)\n", filehdr.f_magic, filehdr.f_magic);
    exit(-1);
  }
  if (debug_mode)
    fprintf(stderr, "%ld+", aouthdr.tsize);

  if (filehdr.f_magic == 0x14c)
  {
    areas[A_data].first_addr = aouthdr.data_start + ARENA;
    areas[A_data].foffset = scnhdr[1].s_scnptr + header_offset;
  }
  else
  {
    areas[A_data].first_addr = (areas[A_text].last_addr+0x3fffffL)&~0x3fffffL;
    areas[A_data].foffset = ((aouthdr.tsize + 0x20 + 0xfffL) & ~0xfffL) + header_offset;
  }
  areas[A_data].last_addr = areas[A_data].first_addr + aouthdr.dsize - 1;
  if (debug_mode)
    fprintf(stderr, "%ld+", aouthdr.dsize);

  areas[A_bss].first_addr = areas[A_data].last_addr + 1;
  areas[A_bss].foffset = -1;
  areas[A_bss].last_addr = areas[A_bss].first_addr + aouthdr.bsize - 1;
  if (debug_mode)
    fprintf(stderr, "%ld = %ld\n", aouthdr.bsize,
      aouthdr.tsize+aouthdr.dsize+aouthdr.bsize);

  areas[A_arena].first_addr = (areas[A_bss].last_addr + 1 + 7) & ~7L;
  areas[A_arena].last_addr = areas[A_arena].first_addr - 1;
  areas[A_arena].foffset = -1;

  if(!use_DPMI)
  {
    areas[A_stack].first_addr = 0x50000000L;
    areas[A_stack].last_addr = 0x8fffffffL;
    areas[A_stack].foffset = -1;
  
    areas[A_vga].first_addr = 0xe0000000L;
    areas[A_vga].last_addr = 0xe03fffffL;
    areas[A_vga].foffset = -1;
  
    areas[A_syms].first_addr = 0xa0000000L;
    areas[A_syms].last_addr = 0xafffffffL;
    areas[A_syms].foffset = -1;
  
    pd = (word32 far *)((long)valloc(VA_640) << 24);
    vcpi_pt = pt = (word32 far *)((long)valloc(VA_640) << 24);
    for (i=0; i<1024; i++)
    {
      pd[i] = 0;
      pd_seg[i] = 0;
    }
  
    if (vcpi_installed)
    {
      link_vcpi(pd,pt);           /*  Get VCPI Page Table  */
      for ( i=0; i<1024; i++)
        if (pt[i] & PT_P)
          pt[i] |= PT_I;
    }
    else
    {
      for (i=0; i < DOS_PAGE; i++)
        pt[i] = ((unsigned long)i<<12) | PT_P | PT_W | PT_I;
      for (; i<1024; i++)
        pt[i] = 0;
    }

    pd[0] = 
      pd[0x3c0] = far2pte(pt, PT_P | PT_W | PT_I);  /* map 1:1 1st Mb */
    pd_seg[0] = 
      pd_seg[0x3c0] = (word32)pt >> 24;
  
    gdt_phys.limit = gdt[g_gdt].lim0;
    gdt_phys.base = ptr2linear(&gdt);
    idt_phys.limit = gdt[g_idt].lim0;
    idt_phys.base = ptr2linear(&idt);
  
    handle_screen_swap(pt);
    a_tss.tss_ebx = screen_primary;
    a_tss.tss_ebp = screen_secondary;
    prog_info.linear_address_of_primary_screen = screen_primary;
    prog_info.linear_address_of_secondary_screen = screen_secondary;
  
/* CB changes: two page tables + stuff for graphics page fault handler */
/* to move around page tables in the page directory */
/* OLD:
 * graphics_pt = (word32 far *)((long)valloc(VA_640) << 24);
 * graphics_pt_lin = ptr2linear(graphics_pt);
 * for (i=0; i<1024; i++)
 *   graphics_pt[i] = 0x000a0000L | ((i * 4096L) & 0xffffL) | PT_W | PT_U;
 * pd[0x380] = far2pte(graphics_pt, PT_P | PT_W | PT_U);
 * pd_seg[0x380] = (word32)graphics_pt >> 24;
 */
  graphics_pd       = &pd[0x380];
  graphics_pd_seg     = &pd_seg[0x380];
  graphics_pd_lin     = ptr2linear(graphics_pd);
  graphics_pd_seg_lin = ptr2linear(graphics_pd_seg);
  graphics_pt1              = (word32 far *)((long)valloc(VA_640) << 24);
  graphics_pt2              = (word32 far *)((long)valloc(VA_640) << 24);
  graphics_pt1_lin    = ptr2linear(graphics_pt1);
  graphics_pt2_lin    = ptr2linear(graphics_pt2);
  graphics_pt1_loc    = 0;                            /* first RW page */
  graphics_pt2_loc    = (0x03000000L / 4096L / 1024L);  /* first page of the 16 MB write only area */
  graphics_pd[(word16)graphics_pt1_loc] = far2pte(graphics_pt1,(PT_P | PT_W | PT_U));
  graphics_pd[(word16)graphics_pt2_loc] = far2pte(graphics_pt2,(PT_P | PT_W | PT_U));
  graphics_pd_seg[(word16)graphics_pt1_loc] = (word32)graphics_pt1 >> 24;
  graphics_pd_seg[(word16)graphics_pt2_loc] = (word32)graphics_pt2 >> 24;
  for(i = 0; i < 1024; i++) {
    graphics_pt1[i] = 0L;
    graphics_pt2[i] = 0L;
  }
/* end CB changes */
  
    c_tss.tss_cr3 = 
    a_tss.tss_cr3 = 
    o_tss.tss_cr3 = 
    i_tss.tss_cr3 = 
    p_tss.tss_cr3 = 
    f_tss.tss_cr3 = 
    r_tss.tss_cr3 = 
    v74_tss.tss_cr3 = 
    v78_tss.tss_cr3 = 
    v79_tss.tss_cr3 = far2pte(pd, 0);
  
    a_tss.tss_esi = far2pte(pd,0) >> 12; /* PID */
    prog_info.pid = far2pte(pd,0) >> 12;
  
  }
  else   /* use_DPMI */
  {
  
    if (areas[A_bss].last_addr < 0x11000L)
     areas[A_bss].last_addr = 0x11000L;
    handle_screen_swap(NULL);
    a_tss.tss_ebx = screen_primary;
    a_tss.tss_ebp = screen_secondary;
    prog_info.linear_address_of_primary_screen = screen_primary;
    prog_info.linear_address_of_secondary_screen = screen_secondary;
    a_tss.tss_esi = FP_SEG(paging_buffer);
    prog_info.pid = FP_SEG(paging_buffer);
#if VERBOSE
    fprintf(stderr,"%ld+%ld+%ld = %ld\n", aouthdr.tsize, aouthdr.dsize, aouthdr.bsize,
      aouthdr.tsize+aouthdr.dsize+aouthdr.bsize);
#endif
  
    /* In certain instances, there is a large gap between text and data.  If it
       is larger than the stack size, lets take advantage of it. */
  
    if (areas[A_data].first_addr - areas[A_text].last_addr <= DPMI_STACK)
    {  /* No room, put stack between bss and arena */
      areas[A_stack].first_addr = (areas[A_bss].last_addr + 1 + 0xfff) & ~0xfff;
      if (areas[A_stack].first_addr < 0x11000L) 
        areas[A_stack].first_addr = 0x11000L; /* Some bizzare windows bug */
      areas[A_stack].last_addr = areas[A_stack].first_addr + DPMI_STACK - 1;
      areas[A_arena].first_addr = areas[A_stack].last_addr + 1;
      areas[A_arena].last_addr = areas[A_stack].last_addr;
  } else {  /* Put stack in gap */
      areas[A_stack].last_addr = areas[A_data].first_addr - 1;
/*    areas[A_stack].first_addr = areas[A_stack].last_addr - DPMI_STACK + 1; */
      areas[A_stack].first_addr = (areas[A_text].last_addr + 1 + 0xfff) & ~0xfff;
      if (areas[A_stack].first_addr < 0x11000L) 
        areas[A_stack].first_addr = 0x11000L; /* Some bizzare windows bug */
    }
    areas[A_vga].first_addr =
     areas[A_syms].first_addr =
     areas[A_syms2].first_addr = 1; /* Not used */
    areas[A_vga].last_addr =
     areas[A_syms].last_addr =
     areas[A_syms2].last_addr = 0;   /* len zero */
  
    /* Here and in changeBreak we use 64K breaks to minimize calls to DPMI */
    newbytes = (areas[A_arena].last_addr + 1 + DPMIgetpage) & ~DPMIgetpage;
    DPMIprotectedMode();
    if (! DPMIalloc(&DPMImem, newbytes))
    {
      DPMIrealMode();
      fprintf(stderr,"DPMI: Not enough memory (0x%08lx bytes).\n", newbytes);
      exit(1);
    }
    DPMIselect = DPMIselector(4);
    if (DPMIselect == 0)
    {
      DPMIrealMode();
      fprintf(stderr,"DPMI: Not enough selectors.\n");
      exit(1);
    }
    setDPMISelectors(1);
    DPMIassignSelector(DPMIselect+24, 0xc0b3, 0L, 0xfffffL);
    DPMIrealMode();

    core_selector =  
    a_tss.tss_gs =
    prog_info.selector_for_linear_memory = (word16)(DPMIselect+24);
  
    a_tss.tss_eax = (word32)(DPMIselect + 24) << 16;  /* Hi word for "core" selector */
    arena_ds = a_tss.tss_ds = a_tss.tss_es = a_tss.tss_fs = DPMIselect;
    arena_cs = a_tss.tss_cs = DPMIselect + 8;
    a_tss.tss_ss = DPMIselect + 16;
    a_tss.tss_esp = areas[A_stack].last_addr + 1;
    a_tss.tss_eflags = 0x0202;

    r_tss.tss_es = r_tss.tss_fs = DPMIselect;
    r_tss.tss_cs = DPMIselect + 8;
  
    loadAout(&areas[A_text]);
    loadAout(&areas[A_data]);
    Pmemset(DPMIselect, areas[A_bss].first_addr, 0, areas[A_bss].last_addr + 1 - areas[A_bss].first_addr);
    Pmemset(DPMIselect, areas[A_arena].first_addr, 0, newbytes - areas[A_arena].first_addr);
  
    close(aout_f);
  } /* end else use_DPMI */

#if VERBOSE
    for (i=0; i<5; i++)
      fprintf(stderr,"%d %-10s %08lx-%08lx (offset 0x%08lx)\n", i, aname[i], areas[i].first_addr, areas[i].last_addr, areas[i].foffset);
#endif
}

static update_status(int c, int col)
{
  int r;
  r = peek(screen_seg, 2*79);
  poke(screen_seg, 2*col, c);
  return r;
}

static int cant_ask_for(int32 amount)
{
  static word32 reserved = 0;
  static word32 used_at_first = 0;
  word32 max;
  
  if (use_DPMI)
    return 0;
  if (used_at_first == 0)
    used_at_first = (valloc_used() - dalloc_used()) * 4096L + 8192L /* stack */;
  max = valloc_max_size()*4092L - used_at_first;	/* 4096 - PTE */

  if (reserved + amount >= max)
    max += dalloc_max_size() * 4092L;

  if (reserved + amount < max)
  {
    reserved += amount;
    return 0;
  }
  return 1;
}

word32 paging_brk(word32 b)
{
  word32 r;

  r = (areas[A_arena].last_addr - ARENA + 1 + 7) & ~7;  /* Even value */
  if (use_DPMI)
    if (! changeBreak(b)) return -1L;
  if (cant_ask_for(b-r))
    return -1L;
  areas[A_arena].last_addr = b + ARENA - 1;
  return r;
}

word32 paging_sbrk(int32 b)
{
  word32 r;

  r = (areas[A_arena].last_addr - ARENA + 1 + 7) & ~7;  /* Even value */
  if (use_DPMI)
    if (! changeBreak(r + b)) return -1L;
  if (cant_ask_for(b))
    return -1L;
  areas[A_arena].last_addr = r + b + ARENA - 1;
  return r;
}

int page_is_valid(word32 vaddr)
{
  int a;
  for (a=0; a<MAX_AREA; a++)
    if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
      return 1;
  if ( use_DPMI )
    return 0;
  if (vaddr >= 0xf0000000L)
    return 1;
  return 0;
}

int page_in(void)
{
  int old_status;
  TSS *old_util_tss;
  word32 far *pt;
  word32 vaddr, cnt32;
  word32 eaddr, vtran, vcnt, zaddr;
  int pdi, pti, pn, a, count;
  unsigned dblock;

  if (use_DPMI)
    return 1;

#if 0
  unsigned char buf[100];
  sprintf(buf, "0x%08lx", a_tss.tss_cr2 - ARENA);
  for (a=0; buf[a]; a++)
    poke(screen_seg, 80+a*2, 0x0600 | buf[a]);
#endif

  old_util_tss = utils_tss;
  utils_tss = &f_tss;
  vaddr = tss_ptr->tss_cr2;

  for (a=0; a<MAX_AREA; a++)
    if ((vaddr <= areas[a].last_addr) && (vaddr >= areas[a].first_addr))
      goto got_area;

  if (vaddr >= 0xf0000000L)
  {
    pdi = (word16)(vaddr >> 22) & 0x3ff;
    if (!(pd[pdi] & PT_P))      /* put in a mapped page table */
    {
      pn = valloc(VA_640);
      pt = (word32 far *)((word32)pn << 24);
      if (pd[pdi] & PT_S)
      {
        dread(paging_buffer, (word16)(pd[pdi]>>12));
        movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
        dfree((word16)(pd[pdi]>>12));
        pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
        pd_seg[pdi] = pn;
      }
      else
      {
        pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
        pd_seg[pdi] = pn;
        vaddr &= 0x0fc00000L;
        for (pti = 0; pti < 1024; pti++)
          pt[pti] = PT_P | PT_W | PT_I | vaddr | (((word32)pti)<<12);
      }
      return 0;
    }
    pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
    vaddr &= 0x0ffff000L;
    pti = (word16)(vaddr>>12) & 0x3ff;
    pt[pti] = vaddr | PT_P | PT_W | PT_I;
    return 0;
  }

  segfault(tss_ptr->tss_cr2);
  return 1;

got_area:
  vaddr &= 0xFFFFF000L;  /* points to beginning of page */
#if 0 /* handled in protected mode for speed */
  if (a == A_vga)
    return graphics_fault(vaddr, graphics_pt);
#endif

#if VERBOSE
    printf("area(%d) - ", a);
#endif

  if ((a == A_bss) & (vaddr < areas[a].first_addr)) /* bss, but data too */
  {
#if VERBOSE
      printf("split page (data/bss) detected - ");
#endif
    a = A_data; /* set to page in data */
  }

  if (topline_info)
    old_status = update_status(achar[a] | 0x0a00, 78);
#if VERBOSE
  printf("Paging in %s block for vaddr %#010lx -", aname[a], tss_ptr->tss_cr2-ARENA);
#endif
  pdi = (word16)(vaddr >> 22) & 0x3ff;
  if (!(pd[pdi] & PT_P))        /* put in an empty page table if required */
  {
    pn = valloc(VA_640);
    pt = (word32 far *)((word32)pn << 24);
    if (pd[pdi] & PT_I)
    {
      dread(paging_buffer, (word16)(pd[pdi]>>12));
      movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
      dfree((word16)(pd[pdi] >> 12));
      pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
      pd_seg[pdi] = pn;
    }
    else
    {
      pd[pdi] = pn2pte(pn, PT_P | PT_W | PT_I | PT_S);
      pd_seg[pdi] = pn;
      for (pti=0; pti<1024; pti++)
        pt[pti] = PT_W | PT_S;
    }
  }
  else
    pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
  pti = (word16)(vaddr >> 12) & 0x3ff;
  if (pt[pti] & PT_P)
  {
    utils_tss = old_util_tss;
    if (topline_info)
      update_status(old_status, 78);
    return 0;
  }
  count = MAX_PAGING_NUM;
  if (count > mem_avail/4)
    count = 1;
  if (pti + count > 1024)
    count = 1024 - pti;
  if (vaddr + count*4096L > areas[a].last_addr+4096L)
    count = (word16)((areas[a].last_addr - vaddr + 4095) / 4096);
  if (count < 1)
    count = 1;
  zaddr = eaddr = -1;
  vtran = vaddr;
  vcnt = 0;
  for (; count; count--, pti++, vaddr+=4096)
  {
    if (pt[pti] & PT_P)
      break;
    if (eaddr != -1 && (pt[pti] & PT_I) != 0) 
      break;  /* EastWind 1993 */
    dblock = (word16)(pt[pti] >> 12);
    pn = valloc(VA_1M);
    pt[pti] &= 0xfffL & ~(word32)(PT_A | PT_D);
    pt[pti] |= ((word32)pn << 12) | PT_P;

    if (pt[pti] & PT_I)
    {
#if VERBOSE
      printf(" swap");
#endif
      dread(paging_buffer, dblock);
      dfree(dblock);
      memput(vaddr, paging_buffer, 4096);
      pt[pti] &= ~(word32)(PT_A | PT_D);  /* clean dirty an accessed bits (set by memput) */
    }
    else
    {
      pt[pti] &= ~(word32)(PT_C);
      if (areas[a].foffset != -1)
      {
#if VERBOSE
        if (a == A_emu)
          printf(" emu");
        else
          printf(" exec");
#endif
        if (eaddr == -1)
        {
          eaddr = areas[a].foffset + (vaddr - areas[a].first_addr);
          vtran = vaddr;
        }
        cnt32 = areas[a].last_addr - vaddr + 1;
        if (cnt32 > 4096)
          cnt32 = 4096;
        else
          zaddr = vaddr;
        vcnt += cnt32;
      }
      else
      {
        zero32(vaddr);
#if VERBOSE
        printf(" zero");
#endif
      }
      pt[pti] |= PT_I;
    }
/*  if (paged_out_something) */
      break;
  }
  if (eaddr != -1)
  {
    int cur_f, rsize, vc;
    cur_f = areas[a].fileno;
    lseek(cur_f, eaddr, 0);
    rsize = read(cur_f, paging_buffer, (word16)vcnt);
    if (rsize < vcnt)
      memset(paging_buffer+rsize, 0, (word16)(vcnt-rsize));
    if (zaddr != -1)
      zero32(zaddr);
    memput(vtran, paging_buffer, vcnt);
    vc = (word16)(vcnt / 4096); /* don't reset BSS parts */
    while (vc)
    {
      pdi = (word16)(vtran >> 22);
      pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
      pti = (word16)(vtran >> 12) & 0x3ff;
      pt[pti] &= ~(word32)(PT_A | PT_D);  /* clean dirty an accessed bits (set by memput) */
      vc--;
      vtran += 4096;
    }
  }
#if VERBOSE
  printf("\n");
#endif
  utils_tss = old_util_tss;
  if (topline_info)
    update_status(old_status, 78);
  return 0;
}

static fInPageOutEverything = 0;
static last_po_pdi = 0;
static last_po_pti = 0;
static last_pti = 0;

unsigned page_out(int where) /* return >= 0 page which is paged out, 0xffff if not */
{
  int start_pdi, start_pti, pti;
  word32 far *pt, v, rv;
  unsigned dblock;
  int old_status;
  if (topline_info)
  {
    old_status = update_status('>' | 0x0a00, 79);
  }
  start_pdi = last_po_pdi;
  start_pti = last_po_pti;
  if (where == VA_640)
  {
    for (pti = last_pti+1; pti != last_pti; pti = (pti+1)%1024)
      if ((pd[pti] & (PT_P | PT_S)) == (PT_P | PT_S))
      {
        dblock = dalloc();
        movedata(pd_seg[pti]<<8, 0, _DS, FP_OFF(paging_buffer), 4096);
        dwrite(paging_buffer, dblock);
#if VERBOSE
        printf ("out_640 %d\n", pti);
#endif
        pd[pti] &= 0xfff & ~(word32)(PT_P); /* no longer present */
        pd[pti] |= (long)dblock << 12;
        if (topline_info)
          update_status(old_status, 79);
        last_pti = pti;
        return pd_seg[pti];
      }
    return -1;
  }
  pt = (word32 far *)((word32)(pd_seg[last_po_pdi]) << 24);
  do {
    if ((pd[last_po_pdi] & (PT_P | PT_S)) == (PT_P | PT_S))
    {
      if ((pt[last_po_pti] & (PT_P | PT_S)) == (PT_P | PT_S))
      {
        rv = pt[last_po_pti] >> 12;
        v = ((word32)last_po_pdi << 22) | ((word32)last_po_pti << 12);
        if (!fInPageOutEverything)
          if ((v & 0xfffff000L) == ((tss_ptr->tss_eip + ARENA) & 0xfffff000L) ||
              (v & 0xfffff000L) == ((tss_ptr->tss_esp + ARENA) & 0xfffff000L))
          {
#if VERBOSE
            printf("\nskip: v=%08lx - ", v);
#endif
            goto bad_choice;
          }
        if (pt[last_po_pti] & (PT_C | PT_D))
        {
          pt[last_po_pti] |= PT_C;
          dblock = dalloc();
          memget(v, paging_buffer, 4096);
#if VERBOSE
          printf ("dout %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12));
#endif
          dwrite(paging_buffer, dblock);
          pt[last_po_pti] &= 0xfff & ~PT_P; /* no longer present */
          pt[last_po_pti] |= (long)dblock << 12;
        }
        else
        {
          pt[last_po_pti] = PT_W | PT_S;
#if VERBOSE
          printf ("dflush %08lx", ((word32)last_po_pdi<<22) | ((word32)last_po_pti<<12));
#endif
        }
        if (topline_info)
          update_status(old_status, 79);
        return (word16)rv;
      }
    }
    else /* imagine we just checked the last entry */
      last_po_pti = 1023;

bad_choice:
    if (++last_po_pti == 1024)
    {
      last_po_pti = 0;
      if (++last_po_pdi == 1024)
        last_po_pdi = 0;
      pt = (word32 far *)((word32)(pd_seg[last_po_pdi]) << 24);
    }
  } while ((start_pdi != last_po_pdi) || (start_pti != last_po_pti));
  if (topline_info)
    update_status(old_status, 79);
  return 0xffff;
}

unsigned pd_dblock;
static int kept_on_exec;

extern int valloc_initted;
extern void vfree_640(void);
extern void vrecover_640(void);

void page_out_everything(void)
{
  int pdi, i;
  word32 opde;
  unsigned ptb;
  void far *fp;

  if(use_DPMI)
  {
    saveDPMIstate();
    return;
  }

  fInPageOutEverything = 1;

  kept_on_exec = (valloc_used()*4096 <= stub_info.max_keep_on_spawn);
  if (!kept_on_exec)
    while (page_out(-1) != 0xffff)
      vfree();

  for (pdi=0; pdi<1024; pdi++)
    if (pd[pdi] & PT_P)
    {
      ptb = dalloc();
      opde = pd[pdi] & 0xfffff001L;
      fp = (word32 far *)((word32)pd_seg[pdi] << 24);
      movedata(FP_SEG(fp), FP_OFF(fp), _DS, FP_OFF(paging_buffer), 4096);
      dwrite(paging_buffer, ptb);
      vfree();
      pd[pdi] = (pd[pdi] & (0xFFF&~PT_P)) | ((word32)ptb<<12);
      for (i=pdi+1; i<1024; i++)
        if ((pd[i] & 0xfffff001L) == opde)
          pd[i] = pd[pdi];
    }
  movedata(FP_SEG(pd), FP_OFF(pd), _DS, FP_OFF(paging_buffer), 4096);
  pd_dblock = dalloc();
  dwrite(paging_buffer, pd_dblock);
  vfree();
  if (!kept_on_exec)
  {
    vcpi_flush();
    valloc_uninit();
  }
  else
    vfree_640();
}

void page_in_everything(void)
{
  int pdi, i;
  word32 opde;
  unsigned ptb;
  word32 far *pt;
  unsigned pta;

  if(use_DPMI)
  {
    restoreDPMIstate();
    return;
  }

  fInPageOutEverything = 0;

  if (!kept_on_exec)
    valloc_initted = 0;
  else
    vrecover_640();

  pta = valloc(VA_640);
  pd = (word32 far *)((word32)pta << 24);
  dread(paging_buffer, pd_dblock);
  dfree(pd_dblock);
  movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pd), FP_OFF(pd), 4096);
  for (pdi=0; pdi<1024; pdi++)
    if (pd[pdi] && !(pd[pdi] & PT_P))
    {
      pta = valloc(VA_640);
      opde = pd[pdi] & 0xfffff001L;
      pt = (word32 far *)((word32)pta << 24);
      ptb = (word16)(opde >> 12);
      dread(paging_buffer, ptb);
      dfree(ptb);
      movedata(_DS, FP_OFF(paging_buffer), FP_SEG(pt), FP_OFF(pt), 4096);
      if (pdi == 0)
        vcpi_pt = (word32 far *)((word32)pta << 24);
      pd[pdi] = pn2pte(pta, (pd[pdi] & 0xFFF) | PT_P);
      pd_seg[pdi] = pta;
      for (i=pdi+1; i<1024; i++)
        if ((pd[i] & 0xfffff001L) == opde)
        {
          pd[i] = pd[pdi];
          pd_seg[i] = pd_seg[pdi];
        }
    }
/* CB changes: two tables + page directory stuff */
/* OLD:
 * graphics_pt = (word32 far *)((long)pd_seg[0x380] << 24);
 * graphics_pt_lin = ptr2linear(graphics_pt);
 */
  graphics_pd    = &pd[0x380];
  graphics_pd_lin  = ptr2linear(graphics_pd);
  graphics_pt1           = (word32 far *)((word32)graphics_pd_seg[(word16)graphics_pt1_loc] << 24);
  graphics_pt2           = (word32 far *)((word32)graphics_pd_seg[(word16)graphics_pt2_loc] << 24);
  graphics_pt1_lin = ptr2linear(graphics_pt1);
  graphics_pt2_lin = ptr2linear(graphics_pt2);
  for(i = 0; i < 1024; i++) {
    graphics_pt1[i] = 0L;
    graphics_pt2[i] = 0L;
  }
/* end CB changes */
}


static word32 emu_start_ip_val = 0;

word32 emu_start_ip()
{
  return emu_start_ip_val;
}

int emu_install(char *filename)
{
  FILEHDR filehdr;
  AOUTHDR aouthdr;
  GNU_AOUT gnu_aout;
  int emu_f;

  areas[A_emu].first_addr = EMU_TEXT+ARENA;
  areas[A_emu].last_addr = EMU_TEXT-1+ARENA;
  areas[A_emu].foffset = 0;

  if (use_DPMI)
    return 0;
  if (filename == 0)
    return 0;
  emu_f = open(filename, O_RDONLY|O_BINARY);
  if (emu_f < 0)
  {
    fprintf(stderr, "Can't open 80387 emulator file <%s>\n", filename);
    return 0;
  }
  areas[A_emu].fileno = emu_f;
  
  read(emu_f, &filehdr, sizeof(filehdr));
  if (filehdr.f_magic != 0x14c)
  {
    lseek(emu_f, 0L, 0);
    read(emu_f, &gnu_aout, sizeof(gnu_aout));
    emu_start_ip_val = gnu_aout.entry;
    aouthdr.tsize = gnu_aout.tsize;
    aouthdr.dsize = gnu_aout.dsize;
    aouthdr.bsize = gnu_aout.bsize;
  }
  else
  {
    read(emu_f, &aouthdr, sizeof(aouthdr));
    emu_start_ip_val = aouthdr.entry;
  }

  areas[A_emu].last_addr += aouthdr.tsize + aouthdr.dsize + aouthdr.bsize + (emu_start_ip_val & 0xff);
  return 1;
}

word32 stack_used(void)
{
  int pdi,pti;
  word32 far *pt;

  for(pdi=0x140;pdi<0x240;pdi++)
    if( pd[pdi] & PT_I ) {  /* really should check for PT_P here, but */
      pt = (word32 far *)((word32)(pd_seg[pdi]) << 24);
      for(pti=0;pti<1024;pti++)
        if( pt[pti] & PT_I )
          return ((word32)(0x23f-pdi) << 22) | ((word32)(1024-pti) << 12);
    }
  return 0L;  /* No stack pd entries found! */
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.