-- RunImage.mesa; edited by Sandman; July 1, 1980  8:27 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [PageSize],
  AltoFileDefs USING [CFP],
  BcplOps USING [BcplJSR],
  BFSDefs USING [MakeCFP],
  BinaryDefs USING [MesaBootLoader],
  ControlDefs USING [FieldDescriptor, StateVector, SVPointer],
  CoreSwapDefs USING [PuntInfo],
  DiskDefs USING [DA, RealDA],
  ImageFormat USING [ImageHeader, MapItem, VersionID],
  ImageDefs USING [],
  MiscDefs USING [DestroyFakeModule, Zero],
  Mopcodes USING [zLI4, zRFS, zSHIFT, zWFS],
  ProcessDefs USING [ConditionVector, CV, DIW],
  ProcessOps USING [ActiveWord],
  SegmentDefs USING [
    CopyFileToDataSegment, DataSegmentAddress, DataSegmentHandle,
    DeleteDataSegment, DeleteFileSegment, FileHandle, FileSegmentAddress,
    FileSegmentHandle, GetFileSegmentDA, MakeDataSegment, memConfig, MemoryConfig,
    NewFileSegment, PageFromAddress, Read, SwapIn, VMnotFree];

RunImage: PROGRAM
  IMPORTS BFSDefs, BinaryDefs, DiskDefs, MiscDefs, BcplOps, SegmentDefs
  EXPORTS ImageDefs
  SHARES DiskDefs, SegmentDefs =
  BEGIN OPEN SegmentDefs, ImageFormat;

  PageSize: CARDINAL = AltoDefs.PageSize;

  BD: PROCEDURE [CARDINAL] RETURNS [ControlDefs.FieldDescriptor] = MACHINE CODE
    BEGIN Mopcodes.zLI4; Mopcodes.zSHIFT END;

  SetBit: PROCEDURE [[0..1], POINTER, ControlDefs.FieldDescriptor] = MACHINE CODE
    BEGIN Mopcodes.zWFS END;

  GetBit: PROCEDURE [POINTER, ControlDefs.FieldDescriptor] RETURNS [[0..1]] =
    MACHINE CODE BEGIN Mopcodes.zRFS END;

  BootData: TYPE = RECORD [
    pageMap: POINTER TO PageTable,
    firstDa: DiskDefs.DA,
    initialState: ControlDefs.SVPointer,
    bltItem: BltItem,
    terminator: WORD]; -- = 0

  BltItem: TYPE = RECORD [
    firstSourceM1: POINTER, lastDest: POINTER, minusCount: INTEGER];

  PageTableHeader: TYPE = RECORD [cfp: AltoFileDefs.CFP, firstpage: CARDINAL];

  PageTable: TYPE = RECORD [
    header: PageTableHeader, address: ARRAY [0..0) OF UNSPECIFIED];

  InvalidImage: PUBLIC SIGNAL = CODE;

  NoRoomForLoader: PUBLIC SIGNAL = CODE;

  RunImage: PUBLIC PROCEDURE [headerseg: FileSegmentHandle] =
    BEGIN
    boottable: POINTER TO BootData;
    map: ARRAY [0..16) OF UNSPECIFIED;
    ptwords: CARDINAL ← SIZE[PageTableHeader] + 1;
    pt: POINTER TO PageTable;
    j: CARDINAL;
    mapi: POINTER TO MapItem;
    loader, pagetable, bootseg: DataSegmentHandle;
    image: POINTER TO ImageHeader;
    initMemConfig: POINTER TO SegmentDefs.MemoryConfig ← LOOPHOLE[3];
    state: ControlDefs.SVPointer =
      LOOPHOLE[175000B - SIZE[ControlDefs.StateVector]];
    ifile: FileHandle = headerseg.file;
    SwapIn[headerseg];
    image ← FileSegmentAddress[headerseg];
    IF image.prefix.versionident # ImageFormat.VersionID OR image.prefix.options #
      0 THEN SIGNAL InvalidImage;
    MiscDefs.Zero[@map, 16];
    mapi ← @image.map[0];
    DO
      IF mapi.count = 0 THEN EXIT;
      ptwords ← ptwords + mapi.count;
      FOR j IN [mapi.page..mapi.page + mapi.count] DO
	SetBit[1, @map, BD[j]] ENDLOOP;
      WITH mapi SELECT FROM
	change =>
	  BEGIN ptwords ← ptwords + 2; mapi ← mapi + SIZE[change MapItem]; END;
	normal => mapi ← mapi + SIZE[normal MapItem];
	ENDCASE => ERROR;
      ENDLOOP;
    SetBit[1, @map, BD[PageFromAddress[image.prefix.diskAddresses]]];
    loader ← Alloc[@map, 1];
    IF loader = NIL THEN ERROR NoRoomForLoader;
    bootseg ← Alloc[@map, 1];
    IF bootseg = NIL THEN
      BEGIN DeleteDataSegment[loader]; ERROR NoRoomForLoader END;
    boottable ← DataSegmentAddress[bootseg];
    pagetable ← Alloc[@map, (ptwords + PageSize - 1)/PageSize];
    IF pagetable = NIL THEN
      BEGIN
      DeleteDataSegment[loader];
      DeleteDataSegment[bootseg];
      ERROR NoRoomForLoader;
      END;
    SetUpBootMap[pt ← DataSegmentAddress[pagetable], image];
    BFSDefs.MakeCFP[cfp: @pt.header.cfp, fp: @ifile.fp];
    pt.header.firstpage ← headerseg.base + 1;
    state↑ ← image.prefix.state;
    boottable↑ ←
      [pageMap: image.prefix.diskAddresses,
	firstDa: FindDa[ifile, pt.header.firstpage], initialState: state,
	bltItem:
	[firstSourceM1: pt - 1,
	  lastDest: image.prefix.diskAddresses + ptwords - 1,
	  minusCount: -INTEGER[ptwords]], terminator: 0];
    CopyFileToDataSegment[
      MiscDefs.DestroyFakeModule[LOOPHOLE[BinaryDefs.MesaBootLoader]].seg,
      loader];
    initMemConfig↑ ← SegmentDefs.memConfig;
    initMemConfig.useXM ← initMemConfig.xmMicroCode AND initMemConfig.banks #
      100000B;
    BEGIN OPEN ProcessDefs, ProcessOps;
    ActiveWord↑ ← DIW↑ ← 0;
    MiscDefs.Zero[CV, SIZE[ConditionVector]];
    CoreSwapDefs.PuntInfo↑ ← NIL;
    END;
    [] ← BcplOps.BcplJSR[JSR, DataSegmentAddress[loader], boottable];
    END;

  Alloc: PROCEDURE [map: POINTER, npages: CARDINAL]
    RETURNS [d: DataSegmentHandle] =
    BEGIN
    i, j: CARDINAL;
    d ← NIL;
    FOR i IN [4..249] DO
      IF GetBit[map, BD[i]] = 0 THEN
	BEGIN
	ENABLE VMnotFree => BEGIN SetBit[1, map, BD[i]]; CONTINUE END;
	d ← MakeDataSegment[i, npages, [hard, topdown, other]];
	FOR j IN [0..npages) DO SetBit[1, map, BD[i + j]] ENDLOOP;
	IF d # NIL THEN RETURN;
	i ← i + npages - 1;
	END
      ENDLOOP;
    RETURN
    END;

  SetUpBootMap: PROCEDURE [
    pt: POINTER TO PageTable, image: POINTER TO ImageHeader] =
    BEGIN
    j: CARDINAL ← 0;
    memaddress, memcount: CARDINAL;
    mapi: POINTER TO ImageFormat.MapItem ← @image.map[0];
    DO
      IF (memcount ← mapi.count) = 0 THEN EXIT;
      memaddress ← mapi.page*PageSize;
      WITH mapi SELECT FROM
	change =>
	  BEGIN
	  pt.address[j] ← base*2 + 1;
	  pt.address[j + 1] ← da;
	  j ← j + 2;
	  mapi ← mapi + SIZE[change ImageFormat.MapItem];
	  END;
	normal => mapi ← mapi + SIZE[normal ImageFormat.MapItem];
	ENDCASE;
      THROUGH [0..memcount) DO
	pt.address[j] ← memaddress;
	memaddress ← memaddress + PageSize;
	j ← j + 1;
	ENDLOOP;
      ENDLOOP;
    pt.address[j] ← 0;
    END;

  FindDa: PROCEDURE [file: FileHandle, page: CARDINAL] RETURNS [da: DiskDefs.DA] =
    BEGIN
    seg: FileSegmentHandle ← NewFileSegment[file, page, 1, Read];
    da ← DiskDefs.RealDA[SegmentDefs.GetFileSegmentDA[seg]];
    DeleteFileSegment[seg];
    RETURN
    END;


  END...