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.