BasicLoader.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
First created by Christophe Cuenod, August 30, 1988 1:06:13 pm PDT
Loads a simple a.out file into the SparcSoftcard
DIRECTORY
Basics USING [BITAND, BITNOT, HighHalf, LowHalf, UnsafeBlock],
Commander USING [CommandProc, Register],
DoveInputOutput USING [ Poke ],
IO USING [ CharClass, EndOfStream, GetTokenRope, RIS, STREAM],
RedBlackTree USING [LookupNode],
Rope USING [ROPE],
SparcSoftcardOps USING [SparcCacheDisable, SparcCacheFlushAndEnable, SparcReset, SparcResetAndStart],
SparcSoftcardVM USING [pageSiz, SegmentType, SetPageValue, SparcPageValue],
SunADotOut USING [Module, ModuleFromFile],
SunADotOutPrivate USING [ ModuleObject, Segment, Symbol ];
BasicLoader: CEDAR PROGRAM
IMPORTS Basics, Commander, DoveInputOutput, IO, RedBlackTree, SparcSoftcardOps, SparcSoftcardVM, SunADotOut
EXPORTS SunADotOut
~ BEGIN
Module: TYPE ~ SunADotOut.Module;
ModuleObject: PUBLIC TYPE ~ SunADotOutPrivate.ModuleObject;
Segment: TYPE ~ SunADotOutPrivate.Segment;
ROPE: TYPE ~ Rope.ROPE;
Sparc VM setting
PresetSparcVM: PROC [segType: SparcSoftcardVM.SegmentType, n: CARD16, dummyAddress: CARD32] ~ {
Preset the n first VM pages of segType to map a dummy page.
value: SparcSoftcardVM.SparcPageValue;
value.realPage ← dummyAddress / SparcSoftcardVM.pageSiz;
FOR i: NAT IN [0..n) DO
SparcSoftcardVM.SetPageValue[segType, i, value];
ENDLOOP;
};
SetSparcVM: PROC [segType: SparcSoftcardVM.SegmentType, n: CARD16, startAddress: CARD32] ~ {
Set the n first VM pages of segType to map the Softcard Physical memory Starting at address startAddress.
value: SparcSoftcardVM.SparcPageValue;
FOR i: NAT IN [0..n) DO
value.realPage ← startAddress / SparcSoftcardVM.pageSiz + i;
SparcSoftcardVM.SetPageValue[segType, i, value];
ENDLOOP;
};
backdoorStart: CARD32 ~ 03C0000H; --Backdoor starts at 3.75 meg
cpStart: CARD32 ~ 01000000H;  --CP has a 16 meg offset in specialIO VM space
SetBackdoorVM: PROC [n: CARD16, startAddress: CARD32] ~ {
Set the n first VM backdoor pages to map the Softcard Physical memory Starting at address startAddress.
value: SparcSoftcardVM.SparcPageValue;
virtualPage: CARD16;
FOR i: NAT IN [0..n) DO
virtualPage ← (backdoorStart + cpStart) / SparcSoftcardVM.pageSiz + i;
value.realPage ← startAddress / SparcSoftcardVM.pageSiz + i;
SparcSoftcardVM.SetPageValue[specialIO, virtualPage, value];
ENDLOOP;
};
Loading Sparc VM
LoadSegment: PROC [seg: Segment, startAddress: CARD32] ~ {
Load seg at address startAddress in the Sparc VM
word: CARD16;
p: LONG POINTER ← seg.block.base;
address: CARD32 ← (startAddress + backdoorStart)/2;
FOR i: INT IN [0..seg.block.count/2) DO
TRUSTED {word ← p^; p ← p + 1};
DoveInputOutput.Poke[address, word]; address ← address + 1;
ENDLOOP;
};
ZeroSegment: PUBLIC PROC [startAddress, length: CARD32] ~ {
address: CARD32 ← (startAddress + backdoorStart)/2;
FOR i: CARD32 IN [0..length/2) DO
DoveInputOutput.Poke[address, 0]; address ← address + 1;
ENDLOOP;
};
InsertResetPointer: PUBLIC PROC [resetVector: CARD32] ~ {
Insert by hand the instruction ba resetVector followed by nop
instruction: CARD32 ← 10800000H; -- ba 0
IF resetVector >= 1000000H THEN ERROR; -- verify max offest
instruction ← instruction + resetVector/4; -- add offsett
DoveInputOutput.Poke[backdoorStart/2, Basics.HighHalf[instruction]];
DoveInputOutput.Poke[backdoorStart/2 + 1, Basics.LowHalf[instruction]];
instruction ← 01000000H;  -- nop
DoveInputOutput.Poke[backdoorStart/2 + 2, Basics.HighHalf[instruction]];
DoveInputOutput.Poke[backdoorStart/2 + 3, Basics.LowHalf[instruction]];
};
IndicateVMSize: PUBLIC PROC [sparcVMSize: CARD32] ~ {
Insert by hand the size of the VM at address 8 (byte address)
DoveInputOutput.Poke[backdoorStart/2 + 4, Basics.HighHalf[sparcVMSize]];
DoveInputOutput.Poke[backdoorStart/2 + 5, Basics.LowHalf[sparcVMSize]];
};
Main proc and misc
CmdTokenBreak: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← THEN RETURN [break];
IF char = ' OR char = '\t OR char = ', OR char = '; OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE] = {
rope ← NIL;
rope ← stream.GetTokenRope[CmdTokenBreak ! IO.EndOfStream => CONTINUE].token;
};
BasicLoaderProc: Commander.CommandProc ~ {
in: IO.STREAMIO.RIS[cmd.commandLine];
inputFile: ROPE ← GetCmdToken[in];
m: Module ← SunADotOut.ModuleFromFile[inputFile];
sparcVMSize: CARD32 ~ 600000H - SparcSoftcardVM.pageSiz; -- 6 Meg minus one page.. the first 256 K are covered by backdoor
backdoorSize: CARD32 ~ 040000H; -- 256 K...
numberOfSparcPages: CARD16 ~ sparcVMSize / SparcSoftcardVM.pageSiz;
numberOfBackdoorPages: CARD16 ~ backdoorSize / SparcSoftcardVM.pageSiz;
numberOfUserPages: CARD16 ~ 02000H;
numberOfSuperPages: CARD16 ~ 02000H;
startAddress: CARD32 ~ 0200000H; --Uses real mem starting at 2 meg
loadText, loadData, loadBss: CARD32;
symbol: SunADotOutPrivate.Symbol;
firstModuleLoaded: ROPE ~ "initializesparc.o"; -- Name of the init module
Reset the Sparc and the cache
SparcSoftcardOps.SparcReset[];
SparcSoftcardOps.SparcCacheDisable[];
SparcSoftcardOps.SparcCacheFlushAndEnable[];
=== For christian tests ===
Set all the Sparc map entries to point outside any used area (the last page of the memory)
PresetSparcVM[userData, numberOfUserPages, sparcVMSize];
PresetSparcVM[userDataAlt, numberOfUserPages, sparcVMSize];
PresetSparcVM[userText, numberOfUserPages, sparcVMSize];
PresetSparcVM[userTextAlt, numberOfUserPages, sparcVMSize];
PresetSparcVM[superData, numberOfSuperPages, sparcVMSize];
PresetSparcVM[superText, numberOfSuperPages, sparcVMSize];
Set the map entries
SetSparcVM[userData, numberOfSparcPages, startAddress];
SetSparcVM[userText, numberOfSparcPages, startAddress];
SetSparcVM[superData, numberOfSparcPages, startAddress];
SetSparcVM[superText, numberOfSparcPages, startAddress];
SetBackdoorVM[numberOfBackdoorPages, startAddress];
Computes load address for text
IF RedBlackTree.LookupNode[m.symbolTable, firstModuleLoaded] = NIL THEN ERROR;
The first module to be linked has to be called "firstModuleLoaded"
symbol ← NARROW[RedBlackTree.LookupNode[m.symbolTable, firstModuleLoaded].data];
The loading address is the address of the first module
loadText ← symbol.value;
Loads text
LoadSegment[m.programText, loadText];
Computes load address for data
loadData ← Basics.BITAND[(loadText + m.programText.block.count + SparcSoftcardVM.pageSiz - 1), Basics.BITNOT[SparcSoftcardVM.pageSiz - 1]];
Round to the beginning of the page following the end of the text
Loads data
LoadSegment[m.programData, loadData];
Computes address for bss
loadBss ← loadData + m.programData.block.count;
Bss will be zeroed after the end of the data segment
Zero bss
ZeroSegment[loadBss, m.header.bss];
Clean up: Insert the reset pointer and the vmSize pointer
InsertResetPointer[m.header.entryPoint];
IndicateVMSize[sparcVMSize];
Put in a wellknown address the VM Size so the init program can load the Stack with it
Start the sparc
SparcSoftcardOps.SparcResetAndStart[];
};
Registration
Commander.Register[
key: "BasicLoader", proc: BasicLoaderProc, doc: "Loads a a.out file into the SparcSoftcard memory"];
END.