|
|
DataMuseum.dkPresents historical artifacts from the history of: Bogika Butler |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Bogika Butler Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 20224 (0x4f00)
Types: TextFile
Names: »IMMUPROC.PAS«
└─⟦08e5746f0⟧ Bits:30009789/_.ft.Ibm2.50007359.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »IMMUPROC.PAS«
PROCEDURE InitMMU;
(* The MM_Proc initialization gets control right after the preface
The following steps are carried out:
(1) Allocate page table
(2) Set up initial mem-rec structure
(3) Boot loaded modules (in ram) are described as one segment object
(4) Create the fulspace segment object and initial pointers
(5) Allocate and initialize the stub object, except local pointers
(6) Create the boot owner set, describing the boot loaded modules
in local-2 of the stub object
(7) Initialize local-1: Ref to the code of the stub
local-6: ref to the fulspace segment object
(8) Create the alloc object
*)
PROCEDURE MMBusErr;
(* Bus_error_exception may be generated by illegal address
specifications in the ram area list *)
BEGIN (* MMBusErr *)
Error(0);
END; (* MMBusErr *)
FUNCTION Get_LdMd: AddressType;
(* Return address of boot loaded modules *)
BEGIN (* Get_LdMd *)
Get_LdMd := AllocObj.Se_fir
END; (* Get_LdMd *)
FUNCTION Get_StMd: AddressType;
(* Return the stub module address *)
BEGIN (* Get_StMd *)
IF KV_Stub = -1 THEN
Get_StMd := Get_LdMd
ELSE
Get_StMd := KVStub
END; (* Get_StMd *)
FUNCTION GetStubE: AddressType;
(* Get address of the stub envelope *)
BEGIN (* GetStubE *)
GetStubE := KV_IManP.Common.Pointer.Next (* First env. in list *)
END; (* GetStubE *)
FUNCTION GetStubO: AddressType;
(* Get address of the stub object *)
BEGIN (* GetStubO *)
GetStubO := KV_IOwnP.Common.Pointer.Next (* First obj. in list *)
END; (* GetStubO *)
PROCEDURE MakeSegm(
UserSize: LongInteger; (* Length of user part (D1) *)
UserAddress: AddressType; (* Address of user part (A1) *)
SegmentObject: NonEmbeddedSegmentObjectType
(* Address of kernell part (A0) *)
);
(* Make a non embedded segment object *)
VAR
d0: AddressType; (* Top address of user part =
UserAddress + UserSize *)
Dummy: AddressType;
BEGIN (* MakeSegm *)
(* prt_reg(parameters) *)
d0 := UserAddress + UserSize;
IF d0 IN (. F_Alloc..L_Alloc .) THEN
PgTabSet(d0, KernelAddress); (* PageTable(d0):=KernelAddress *)
WITH SegmentObject DO
BEGIN
WITH CommonPart DO
BEGIN
OB_Kin := OB_SEOB; (* Kind := segment object *)
OB_Sta := OB_SEGM; (* State := segment *)
END;
WITH SegmentPart DO
BEGIN
SE_io := 0; (* io_count := 0 *)
SE_Fir := UserAddress;
SE_Len := UserSize;
InitHead(SE_Wait, Dummy);
END;
WITH SpacePart DO
(* Possibly this should be handled dynamically so that SpacePart
could be positioned anywhere. See line 1260 in MMPROCS.SA
Something like WITH CommonPart.OB_Spa^ DO *)
BEGIN
SP_FirU := UserAddress;
SP_FreU := 0;
SP_SizU := UserSize;
SP_FirK := SP_FirK + (SE_Siz - OB_Siz); (* Add size of SegmentPart *)
SP_FreK := SP_FreK - (SE_Siz - OB_Siz);
END;
END;
(*
prt_mem('Makesegm', SegmentObject, AllocSiz);
*)
END; (* MakeSegm *)
VAR
d1: integer; (* Allocation Space *)
d2: integer; (* Page Table Size *)
Inx: integer; (* MemList index *)
Curr: integer; (* Current mem rec *)
Prev: integer; (* Previous mem rec *)
Next: integer; (* Next mem rec *)
FFre: integer; (* First free byte *)
TFre: integer; (* Top free byte *)
Holder: MemRecPointerType; (* ^Holder mem rec of loaded modules *)
CMRPtr: MemRecPointerType; (* ^Current mem rec *)
CLMPtr: LdMdHeaderPtrType; (* ^Current load module *)
TopModuleAddress: AddressType; (* Highest addr. in modules *)
TopModuleSize: Integer; (* Size of loaded modules *)
ObjDscPtr: LdMdObjectDescriptionPtrType;
(* ^Program object descriptor *)
KernelPart: AddressType; (* Address of kernel part of object *)
UserPart: AddressType; (* Address of user part of object *)
Size: integer; (* Size of primary envelope *)
Envelope: AddressType; (* Address of envelope *)
SpaceDsc: AddressType; (* Address of space descriptor *)
LDSD_Inx: word; (* Local data segment descriptor index *)
LSD_Inx: word; (* Load section descriptor index *)
SegmentSize: integer; (* Size of segment *)
Rest: integer; (* Remaining size of protected modules *)
ObjDscAddr: AddressType; (* Addr. of program object descriptor *)
LDSDAddr: AddressType; (* Addr. of local data segment descriptor *)
LSDAddr: AddressType; (* Addr. of load section descriptor *)
BEGIN (* InitMMU *)
(**** The bus error exception handler gets control if a non
existing address or uneven address is referenced by the
MMproc initialization phase *)
KV_InVec(.2.) := addr(MMBusErr); (* Bus error vector*)
KV_InVec(.3.) := addr(MMBusErr); (* Address error vector*)
(**** Format the last part of the last ram area:
Compute the addresses of:
Page_Tab, L_Alloc, F_Alloc, F_Supvs, SupvStk *)
WITH Mem_List (* pointed to by KV_FrMem *) DO
BEGIN
d1 := List(.Length.).End - List(.1.).Start;
IF d1 <= 0 THEN
Error(3)
END;
(**** The page table need not describe the memory holding
the page table. The table contains 4 bytes for each
page of 256 bytes, consequently:
TABSIZE * 64 + TABSIZE = ALLOCSPACE
<=>
TABSIZE = ALLOCSPACE DIV 65
Divide allocspace with 65;
Tabsize may be larger than 2*16, hence simple
division is insufficient *)
d2 := 0; (* tabsize *)
WHILE d1 > 65*65000 DO
BEGIN
d1 := d1 - 65*65000;
d2 := d2 + 65000;
END;
d2 := (d2 + d1 DIV 65) + 7; (* round up by 7 *)
IF odd(d2) THEN
d2 := d2 - 1; (* tabsize must be even *)
WITH Mem_List DO
d1 := (List(.Length.).End - d2) DIV 256 * 256;
(* d1 = ( top of last ram area - tabsize ) truncated to page boundary *)
L_Alloc := d1; (* L_Alloc := last mem_rec *)
Supv_Stk := d1; (* Top byte of Supv_Stk := L_Alloc *)
(**** Set up the supervisor stack. Subroutines may now be called *)
(*
Subroutines called so far (this is a subroutine) have been using
the initial supervisor stack pointer Init_SSP based at RAM_TOP.
Init_SSP is boot loaded into the exception vector area.
Will this stack be overwritten during initialization??
*)
(* stack pointer register "a7" := d1; *)
F_Supvs := (d1 - KV_StkSiz) DIV 256 * 256;
(**** The variable called page_tab should contain the address of
entry # 0 of the page table and not the address of entry # 1 *)
WITH Mem_List DO
BEGIN
Page_Tab := List(.Length.).End - d2 - List(.1.).Start DIV 256 * 4;
F_Alloc := List(.1.).Start;
END;
(*
Prt_Mem('F_Alloc_etc', F_alloc, MM_Queue-F_Alloc);
*)
(**** Set up initial mem_recs *)
FOR Inx := 1 TO Mem_List.Length DO
WITH Mem_List.List(.Inx.) DO
BEGIN
FFre := Start;
IF Inx = 1 THEN
BEGIN
FFre := Start + MR_Siz;
Curr := Start;
Prev := FFre; (* Bad trick WIR says *)
END;
TFre := (End - MR_Siz) div 256 * 256;
Next := TFre;
IF Inx = Mem_List.Length THEN
BEGIN
TFre := F_Supvs;
Next := L_Alloc;
END;
IF Curr >= TFre THEN
Error(4);
NewHead(Curr, User, Prev, Next);
WITH MemRecPtr(Curr)^ DO
BEGIN
MR_Fst := FFre;
MR_Fre := TFre - FFre;
END;
(*
Prt_Mem('NewHead', Curr, MR_Siz);
*)
Prev := Curr;
Curr := Next;
END;
(**** Curr = Last mem rec. Prev = mem rec holding supervisor stack
adjust these mem rec.
Assign known but illegal addresses to undefined chain fields *)
WITH MemRecPtr(Curr)^ DO
BEGIN
MR_Prv := MemRecPtr(Prev); (* last mem rec.prev := prior mem rec *)
MR_Nxt := MemRecPtr(10#4711); (* next to last := odd address *)
MR_Fix := Initial; (* L_Alloc.fix := initial *)
MR_Fre := 0; (* L_Alloc.Free_Bytes := 0 *)
(*
Prt_Mem('LastHead', Curr, MR_Siz);
*)
END;
MemRecPtr(Prev)^.MR_Typ := User;
MemRecPtr(F_Alloc)^.MR_Prv :=
MemRecPtr(10#7913) ; (* prior to first := uneven address *)
(*
Prt_Mem('FirstHead', F_Alloc, MR_Siz);
*)
(**** Create one segment object that has the boot loaded modules as
segment data. This will protect the modules during the
initialization. The AllocObj is used as the kernel part of this
segment object *)
IF KV_BotLd <> -1 THEN (* Modules have been boot loaded *)
BEGIN
(**** Find the mem rec that holds the boot loaded modules. This
mem rec is called holder. The modules must be present in one
of the mem recs. The modules may have been damaged by the
previous initialization if they were located too near to the
end (or beginning) of the ram area that holds the modules *)
CMRPtr := MemRecPtr(F_Alloc); (* First mem rec *)
REPEAT
Holder := CMMRPtr;
CMRPtr := CMRPtr^.MR_Nxt
UNTIL PtrVal(CurrPtr) > KV_BotLd;
(**** Find length of boot loaded modules *)
TopModuleAddress := KV_BotLd + 256; (* including the zero module *)
CLMPtr := LdMdPtr(KV_BotLd);
REPEAT
TopModuleAddress := TopModuleAddress + CLMPtr^.MOD_Size
UNTIL CLMPtr^.MOD_Size = 0; (* Size of dummy top module = 0 *)
(**** Restructure holder^. Create MemRec at TopModuleAddress *)
(*
Prt_reg('BootModule', **local variables ** *);
*)
IF TopModuleAddress mod 256 <> 0 THEN
Error(1);
ModuleSize := TopModuleAddress - KV_BotLd;
IF ModuleSize mod 256 <> 0 THEN
Error(2);
IF ModuleSize > 256 THEN
ReChainC(Holder^, KV_BotLd, ModuleSize, User)
END
ELSE (* No boot loaded modules *)
ModuleSize := 0;
InitKnel(AllocObj, AllocSiz);
IF ModuleSize > 256 THEN
MakeSegm(ModuleSize, KV_BotLd, AllocObj);
(**** Create Fulspace Object *)
InitKnel(FulSpace, NEmb_Siz);
MakeSegm(16#1000000, 0, FulSpace);
(**** Initial Pointer Init *)
WITH KV_IOwnP.Common DO
BEGIN
WITH Pointer.Chain DO
BEGIN
Next := ChainPtr(addr(KV_IOwnP));
Prev := ChainPtr(addr(KV_IOwnP))
END;
PT_Inf := PT_lsc;
END;
WITH KV_IManP.Common DO
BEGIN
WITH Pointer.Chain DO
BEGIN
Next := ChainPtr(addr(KV_IManP));
Prev := ChainPtr(addr(KV_IManP))
END;
PT_Inf := PT_lsc;
END;
(**** Various global variables *)
MM_Lock := open;
WITH MM_queue DO (* := empty *)
BEGIN
Next := ChainPtr(addr(MM_queue));
PRev := ChainPtr(addr(MM_queue))
END;
CurKMove := 0; (* Clear move candidate *)
(**** Allocate Stub Object. The Stub module can be found in KV_Stub
(Stub in ROM) or (when KV_Stub = -1) in allocObj.SE_fir
(Stub in RAM). *)
ObjDscPtr: = LdMdObjDscPtr(Get_StMd +
LdMdHdrPtr(Get_StMd)^.MOD_Prog
);
WITH ObjDscPtr DO
BEGIN
IF MOD_Locs < 10 THEN (* If #local pointers < 10 then error *)
Error(8);
Size := (MOD_Locs*Pt_Siz)+SP_Siz+GE_Siz+EN_Siz;
MM_Cre(Size, 0, KernelPart, UserPart);
IF false THEN (* Compare with line 2190 of mmprocs.sa *)
Error(5);
END;
(**** Initial owner pointer holds the stub as the first member *)
ChainOwn( KernelPart, KV_IOwnP, 0 (*, omitting a2 *) );
(**** Create primary envelope *)
Size := Size - SP_Siz - GE_Siz;
MM_PushK(KernelPart, Envelope, Size, SpaceDsc);
Init_Env(Size, Envelope, SpaceDsc);
(**** Initial manager pointer holds the stub envelope as first member *)
ChainMan( Envelope, KV_IManP, 0 (*, omitting a2 *) );
(**** Initialize general part of stub object *)
InitGein(PtrVal(Get_StubO), ObjDscPtr^.MOD_Ent);
(**** Modify the stub object according to the description *)
WITH GePtr(Get_StubO)^.GeneralPart, ObjDscPtr^ DO
BEGIN
GE_Temp := MOD_Temp + 1; (* including T(0) *)
GE_Stk := MOD_Stk; (* Sizetype *)
(* Push MOD_Stk on stack to be picked up when boot process is
created *)
(* *** ??? *** *)
GE_TemD := MOD_TemD
END;
(**** Create a set of non embedded segment objects.
Each segment object contains a header segment or a load section
from the boot loaded modules currently protected by the alloc
object.The segment data of the alloc object shrinks as the new
set grows. The set is owned by local-2 oof the stub object.
The header sections as well as the load sections must be an integral
number of pages *)
IF KV_BotLd <> -1 THEN
REPEAT
WITH LdMdHdrPtr(Get_LdMd)^ DO
BEGIN
(*
PrtMem('HeaderSection', Get_LdMd, 300 );
*)
(* Move the size of the header section and of the associated
load sections to the stack *)
(* Save old stack pointer a7 in a6 *)
Rest := MOD_Size;
TstPage(MOD_HSiz, 6);
Rest := Rest - MOD_HSiz;
(*Push MOD_HSiz *)
ObjDscAddr := Get_LdMd + MOD_prog;
WITH LdMdObjDscPtr(ObjDscAddr)^ DO
BEGIN
LDSDAddr := ObjDscAddr + MOD_FDSD;
FOR LDSD_Inx := 1 TO MOD_LDSS DO
BEGIN
WITH LdMdLDSDPtr(LDSDAddr)^ DO
BEGIN
LSDAddr := LDSDAddr + MOD_LDSz;
FOR LSD_Inx := 1 TO MOD_LSDS DO
WITH LdMdLSDPtr(LSDAddr)^ DO
BEGIN
TstPage(MOD_Slen,6);
Rest := Rest - MOD_Slen;
(* Push MOD_Slen *)
LSDAddr := LSDAddr + MOD_LSDZ
END;
LDSDAddr := LDSDAddr + MOD_DSiz;
END
END
END;
IF Rest <> 0 THEN
Error(7);
(* Push saved old stck pointer in a6 onto stack *)
(* The stack now contains a word and a number of longs.
Create segment objects according to these values. *)
(* items are read from the stack bottom i.e. in the
sequence they were pushed *)
(* SegmentSize := signextend(unpush(a6)); *)
REPEAT
MM_Cre(NEmb_Siz, 0, KernelPart, UserPart);
IF false THEN
Error(8);
(**** Remap data into new object *)
MakeSegm(SegmentSize, Get_LdMd, KernelPart);
(**** Remove data from the protecting alloc segment *)
WITH AllocObj DO
BEGIN
SE_Fir := SE_Fir + SegmentSize;
SE_Len := SE_Len - SegmentSize;
WITH SpaceDscPtr(OB_Spa)^ DO
BEGIN
SP_FirU := SP_FirU + SegmentSize;
SP_SizU := SP_SizU - SegmentSize;
END
END;
(*
PrtMem('Unprotect', AllocObj, AllocSiz);
*)
(**** Chain new segment object to local-2 of stub object *)
ChainOwn(KernelPart, Get_StubE, EN_Siz+PT_Siz (*,omitting a2*));
(* SegmentSize := unpush(a6) size of next segment *)
UNTIL (* a6 = a7 *);
(* Restore old stak pointer a7 := a6; *)
END
UNTIL LdMDHdrPtr(Get_LdMd)^.MOD_Size = 0 (* zero module is reached *);
IF AllocObj.SE_Len <> 256 THEN
Error(7); (* Module jam *)
RemoveUS(AllocObj.SE_Len, Get_LdMd);
(**** Set up program ref in local-1 of stub *)
IF KV_Stub <> -1 THEN (* Stub module in ROM *)
BEGIN
(* Create a subsegment of the fulspace segment describing the local
sections of the module *)
MM_Cre(SU_Siz+SP_Siz, 0, KernelPart, UserPart);
WITH LdMdHdrPtr(KV_Stub)^, SuPtr(KernelPart)^ DO
BEGIN
WITH CommonPart DO
BEGIN
OB_Kin := OB_SEOB;
OB_Sta := OB_SUB;
END;
WITH SegmentPart DO
BEGIN
SE_Io := 0;
SE_Fir := KV_Stub + MOD_HSiz;
SE_Len := MOD_Size - MOD_HSiz;
InitHead(SE_Wait, DummyAddr); (* Make list empty *)
END;
ChainOwn(KernelPart, GetStubE, EN_Siz);
(**** Let the segment pointer of the subsegment point to
the fulspace segment object *)
WITH SubSegmentPart DO
BEGIN
SimplePt(SU_P, FulSpace);
SU_P.Common.PT_Kin := PT_Seg
END
END
END
ELSE
(* The stub is in RAM. The second object in the owner set
of local-2 of the stub will be the code segment. Create a
simple pointer to that object *)
SimplePt(PointerPtr(EN_Siz+GetStubR)^,
SePtr(PointerPtr(EN_Siz+PT_Siz+GetStubE)^.Next)^);
(**** Local-6 of the stub envelope should point to the fulspace
object *)
SimplePt( PointerPtr(EN_Siz+5*PT_Siz+GetStubE)^, FulSpace9;
(**** Initialize the AllocObj as the initila alloc object
of the kernel *)
InitKnel(AllocObj, AllocSiz);
WITH AllocObj.Common DO
BEGIN
OB_Kin := OB_Allo;
OB_Sta := (.OB_Reen.);
(*
PrtMem('FinalAlloc', AllocObj, AllocSiz);
*)
END;
(**** Local-3 of the stub should point to the AllocObj *)
SimplePt(PointerPtr(EN_Siz+2*PT_Siz+GetStubE)^, AllocObj);
(**** Locals 4,5,7,8, and 9 are initialized b the scheduler,
local 10 by enter. *)
(*
PrtMem('EndOfMMprocs', (a7), 8)
*)
END; (* InitMMU *)
«eof»