;*************************************************************************
;** mmu.library                                                         **
;**                                                                     **
;** a system library for arbitration and control of the MC68K MMUs      **
;**                                                                     **
;** © 1998 THOR-Software, Thomas Richter                                **
;** No commercial use, reassembly, modification without prior, written  **
;** permission of the authors.                                          **
;** Including this library in any commercial software REQUIRES a        **
;** written permission and the payment of a small fee.                  **
;**                                                                     **
;** This is an internal header file, do not depend on anything here.    **
;** Use the official include files.                                     **
;** Distributed only for the mmu.library development group for private  **
;** use.                                                                **
;**                                                                     **
;**---------------------------------------------------------------------**
;** Block: The library base                                             **
;** Initializisation and basic jump vectors of the mmu.library          **
;*************************************************************************

;FOLD Includes
        include INC:macros.asm
        include mu_lib.i
        include mu_version.i
        include mu_alerts.i
        include mu_context.i

;we include just the offsets.
;I personally hate to write _LVO all the time, this is stripped
;in this file.
        include INC:exec_lib.asm
;ENDFOLD
;FOLD External References
        xref DetectMMUType
        xref AllocAligned
        xref MUCreatePool
        xref MUDeletePool
        xref AllocContext
        xref BuildDefaultTable
        xref LockContext
        xref UnlockContext
        xref AllocContextMem
        xref FreeContextMem

        xref Init851
        xref Init030
        xref Init040
        xref Init060
;ENDFOLD
;FOLD Defines
;I'm again too lazy to include the complete exec/execbase.i.
;Here just what I need:
AttnFlags       =       $128
;ENDFOLD

        section main_code,code

;FOLD DOS Entry
;*************************************************
;** DOS Entry                                   **
;** Since this is not supposed to be executable,**
;** we return -1. This is an indicator for the  **
;** shell not to execute it.                    **
;*************************************************
DosEntry:
        moveq #-1,d0
        rts
;ENDFOLD
;FOLD Resident
;*************************************************
;** Resident                                    **
;** the resident structure of this library      **
;** used for the autoinit function              **
;*************************************************
Resident:
        dc.w $4afc                      ;MatchWord
        dc.l Resident                   ;Back pointer
        dc.l 0                          ;no endskip
        dc.b $80                        ;add to the system, do not jump in
        dc.b Version                    ;version nummer
        dc.b NT_LIBRARY                 ;this is a library
        dc.b 0                          ;priority
        dc.l MMUName                    ;name of the library
        dc.l IDString                   ;ID string
        dc.l Init                       ;pointer to the init data

        section main_data,data          ;we continue in the data
                                        ;segment for consitency
Init:
        dc.l mulib_len                  ;size of the library
        dc.l FuncInit                   ;jump vector init data, below
        dc.l 0                          ;no structinit. I can't stand this mess
        dc.l LibInit                    ;library init vector
;ENDFOLD
;FOLD FuncInit
;*************************************************
;** FuncInit                                    **
;** Library jump vector inits                   **
;*************************************************
FuncInit:
        dc.l OpenMULib
        dc.l CloseMULib
        dc.l ExpungeMULib
        dc.l ExtFunc                    ;Extended function, unused

                                        ;Library functions follow here
        dc.l AllocAligned
        dc.l GetMapping
        dc.l ReleaseMapping
        dc.l GetPageSize
        dc.l GetMMUType

        dc.l GetMMUConfig
        dc.l ReleaseMMUConfig

        dc.l -1
;ENDFOLD

        section main_code,code

;FOLD Stub routines, reserved routines etc.
        opt c+
        xdef ___stub
___stub:
        opt c-
ExtFunc:
ReservedVector:
        moveq #0,d0
        rts
;ENDFOLD

;FOLD MUAlert
;*************************************************
;** Alert routine                               **
;** Alerts with the alert ID on the stack       **
;** this long word is removed automagically     **
;*************************************************
        xdef MUAlert
MUAlert:
        saveregs d0-d1/d7/a0-a1/a5-a6
        move.l $20(a7),d7                       ;get alert code
        move.l mulib_CurrentContext(a6),a5      ;this as parameter
        move.l mulib_SysBase(a6),a6
        jsr Alert(a6)
        loadregs
        move.l (a7)+,(a7)
        rts
;ENDFOLD

;FOLD LibInit
;*************************************************
;** LibInit                                     **
;** the Library Init vector                     **
;** we're called like this:                     **
;** Library base in d0, ExecBase in a6          **
;** BPTR segment in a0                          **
;**                                             **
;** We must return the initialized library base **
;** in d0, or NULL in case of a failure         **
;*************************************************
LibInit:
        saveregs d2/a4/a6

        move.l d0,a4

        move.l a6,mulib_SysBase(a4)             ;keep SysBase
        move.l a0,mulib_Segment(a4)
        move.b 1+AttnFlags(a6),mulib_AttnFlags(a4)  ;copy AttnFlags

        move.b #NT_LIBRARY,mulib_type(a4)       ;type is library
        move.b #(1<<lib_changed)!(1<<lib_sumused),mulib_flags(a4)       ;library flags
        move.l #MMUName,mulib_name(a4)
        move.l #IDString,mulib_idstring(a4)
        move.l #PackedVersion,mulib_version(a4) ;Version, Revision at once

        lea mulib_ContextList(a4),a0
        NewList a0                              ;initialize the context list    

                                                ;initialize the semaphores
        lea mulib_ContextSemaphore(a4),a0
        jsr InitSemaphore(a6)
        lea mulib_PoolSemaphore(a4),a0
        jsr InitSemaphore(a6)

        btst #AF_68040,mulib_AttnFlags(a4)      ;no need to bother ramlib
        beq.s .donttry

        lea MC68040Name,a1
        moveq #0,d0
        jsr OpenLibrary(a6)
        move.l d0,mulib_040Base(a4)

        lea MC68060Name,a1
        moveq #0,d0
        jsr OpenLibrary(a6)
        move.l d0,mulib_060Base(a4)

.donttry:
        lea ExpansionName,a1
        moveq #37,d0
        jsr OpenLibrary(a6)
        move.l d0,mulib_ExpansionBase(a4)
        beq .noexpansion

        lea UtilityName,a1
        moveq #37,d0                            ;Version 37 minimum
        jsr OpenLibrary(a6)
        move.l d0,mulib_UtilityBase(a4)
        beq .noutility                          ;exit on failure

        move.l a4,a6

        move.l #$1,d0                           ;MEMF_PUBLIC
        move.l #(map_len+4)*32,d1               ;puddle size related to mapping structures
        move.l #(map_len+4)*4,d2                ;puddle threshold
        bsr MUCreatePool                        ;create the memory pool
        move.l d0,mulib_ContextPool(a4)
        beq .nomemory

        bsr DetectMMUType                       ;read MMU type
        move.b d0,mulib_MMUType(a4)

        lea NOP(pc),a0
        lea mulib_Internals(a4),a1
        for.l #mulib_InternalVecs,d1
         move.w #$4ef9,(a1)+                    ;Jmp
         move.l a0,(a1)+                        ;to NOP
        next d1

        lea mulib_Internals(a4),a1
        move.l a4,a6
        lea Init851(pc),a0                      ;now initialize MMU specific stuff
        cmp.b #mutype_68851,d0
        beq.s .initme

        lea Init030(pc),a0
        cmp.b #mutype_68030,d0
        beq.s .initme

        lea Init040(pc),a0
        cmp.b #mutype_68040,d0
        beq.s .initme

        lea Init060(pc),a0
        cmp.b #mutype_68060,d0
        bne.s .nommu                            ;no known MMU here!
.initme:
        jsr (a0)                                ;jump to the init vector of this MMU
        tst.l d0                                ;did work?
        beq.s .alertnommu
.nommu:
        move.l mulib_SysBase(a4),a6
        jsr CacheClearU(a6)                     ;Flush the initialized vectors

        move.l a4,a6

        lea mulib_MMUConfig(a4),a0
        jsr mulib_ReadConfig(a6)                ;read MMU configuration, keep it for later

        lea mulib_MMUConfig(a4),a0
        jsr mulib_SetLibrary(a6)

        bsr AllocContext                        ;allocate a context structure for the global stuff
        move.l d0,mulib_DefaultContext(a4)      ;build default context
        beq.s .alertnocontext

        move.l d0,a0
        bsr BuildDefaultTable                   ;define default mapping
        tst.l d0
        beq.s .quitpool                         ;failure

        lea mulib_MMUConfig(a4),a1
        move.l mulib_DefaultContext(a4),a0
        jsr mulib_ParseMMU(a6)                  ;scan the MMU table
        tst.l d0
        beq.s .quitpool

        lea mulib_MMUConfig(a4),a1
        move.l mulib_DefaultContext(a4),a0
        jsr mulib_ParseTT(a6)                   ;scan the transparent translation
        tst.l d0
        beq.s .quitpool

        bra .exit                               ;initialization done
.alertnocontext:
        ;pea AN_NoContext
        ;bsr MUAlert
        bra.s .quitpool

.alertnommu:                                    ;no need to release the
        pea AN_MMUInit                          ;context. Done automatically
        bsr MUAlert

.quitpool:
        move.l mulib_ContextPool(a4),a0
        bsr MuDeletePool
        ;bra.s .closeutility

.nomemory:
        ;pea AN_NoPoolMem
        ;bsr MUAlert

.closeutility:
        move.l mulib_SysBase(a4),a6
        move.l mulib_UtilityBase(a4),a1
        jsr CloseLibrary(a6)
        clr.l mulib_UtilityBase(a4)
        bra.s .overu
.noutility:
        pea AN_NoUtility
        bsr MUAlert
.overu:
        move.l mulib_SysBase(a4),a6
        move.l mulib_ExpansionBase(a4),a1
        jsr CloseLibrary(a6)
        clr.l mulib_ExpansionBase(a4)
        bra.s .overe

.noexpansion:
        pea AN_NoExpansion
        bsr MUAlert
.overe:
        move.l mulib_SysBase(a4),a6
        move.l mulib_040Base(a4),d0
        beq.s .no040
        move.l d0,a1
        jsr CloseLibrary(a6)
.no040:
        move.l mulib_060Base(a4),d0
        beq.s .no060
        move.l d0,a1
        jsr CloseLibrary(a6)
.no060:

.failure:                                       ;in case of a failure,
                                                ;we've to cleanup ourselves
        move.l mulib_SysBase(a4),a6
        move.l a4,a1
        moveq #0,d0
        moveq #0,d1
        move.w mulib_negsize(a4),d0
        move.w mulib_possize(a4),d1
        sub.l d0,a1                             ;*Mem
        add.l d1,d0                             ;length
        jsr FreeMem(a6)                         ;release memory

        sub.l a4,a4                             ;tough luck
.exit:
        move.l a4,d0
        loadregs
        rts
NOP:
        moveq #0,d0
        rts
;ENDFOLD
;FOLD OpenMULib
;*************************************************
;** OpenMULib                                   **
;** Open the MMU library                        **
;*************************************************
OpenMULib:
        bclr #lib_delexp,mulib_flags(a6)        ;clear the delayed expunge flag
        addq.w #1,mulib_opencnt(a6)             ;increment the open counter
        move.l a6,d0                            ;that's it
        rts
;ENDFOLD
;FOLD CloseMULib
;*************************************************
;** CloseMULib                                  **
;** Close the MMU library again                 **
;*************************************************
CloseMULib:
        tst.w mulib_opencnt(a6)
        beq.s .ignore
        subq.w #1,mulib_opencnt(a6)             ;Decrement open counter
        btst #lib_delexp,mulib_flags(a6)        ;Delayed expunge active ?
        bne.s ExpungeMULib
.ignore:
        moveq #0,d0                             ;do not quit
        rts
;ENDFOLD
;FOLD ExpungeMULib
;*************************************************
;** ExpungeMULib                                **
;** Remove the MMU library from memory, if      **
;** possible                                    **
;*************************************************
ExpungeMULib:
        bset #lib_delexp,mulib_flags(a6)        ;delay at least
        moveq #0,d0                             ;do not flush
        tst.w mulib_opencnt(a6)                 ;still in use?
        bne .exit
        btstm mmuf1_contextopen,mulib_flags1(a6)        ;still an open context?
        beq.s .flush
                                                ;here yes. Something went extremly wrong
        pea AN_ContextOpen
        bsr MUAlert                             ;Create a guru
        moveq #0,d0                             ;do not quit
        bra.s .exit
.flush:
        saveregs a4
        move.l a6,a4
                                                ;restore the vector base

        move.l a6,a1
        Remove                                  ;Remove the library from the system list

        lea mulib_MMUConfig(a6),a0
        jsr mulib_WriteConfig(a6)               ;restore original MMU data

        move.l mulib_ContextPool(a6),a0
        bsr MUDeletePool                        ;release the memory pool. Releases the context as well and the context mapping

        move.l mulib_SysBase(a6),a6

        move.l mulib_UtilityBase(a4),d0
        beq.s .noutility
        move.l d0,a1
        jsr CloseLibrary(a6)
.noutility:
        move.l mulib_ExpansionBase(a4),d0
        beq.s .noexpansion
        move.l d0,a1
        jsr CloseLibrary(a6)
.noexpansion:
        move.l mulib_060Base(a4),d0
        beq.s .no60
        move.l d0,a1
        jsr CloseLibrary(a6)
.no60:
        move.l mulib_040Base(a4),d0
        beq.s .no40
        move.l d0,a1
        jsr CloseLibrary(a6)
.no40:

        move.l mulib_Segment(a4),-(a7)          ;Saveback the segment
        move.l a4,a1                            ;->Base Mem
        moveq #0,d0
        moveq #0,d1
        move.w mulib_negsize(a1),d0             ;NegSize->d0
        move.w mulib_possize(a1),d1             ;Possize->d1
        sub.l d0,a1                             ;*Mem
        add.l d1,d0                             ;mem total
        jsr FreeMem(a6)                         ;release

        move.l (a7)+,d0                         ;restore segment
        loadregs
.exit:
        rts
;ENDFOLD

;** Function entries

;FOLD GetMapping
;*************************************************
;** GetMapping                                  **
;** get for the ctx *a0 or the default ctx      **
;** if *a0==NULL the mapping. Lock the context  **
;*************************************************
GetMapping:
        move.l a0,d0
        bne.s .nodefault
        move.l mulib_DefaultContext(a6),a0
.nodefault:
        bsr LockContext

        lea ctx_Mapping(a0),a0
        move.l a0,d0
        rts
;ENDFOLD
;FOLD ReleaseMapping
;*************************************************
;** ReleaseMapping                              **
;** release the mapping of context *a0          **
;** or the default context if NULL              **
;*************************************************
ReleaseMapping:
        move.l a0,d0
        bne.s .nodefault
        move.l mulib_DefaultContext(a6),a0
.nodefault:
        bsr UnlockContext
        rts
;ENDFOLD
;FOLD GetPageSize
;*************************************************
;** GetPageSize                                 **
;** Return the page size of the MMU             **
;*************************************************
GetPageSize:
        move.l mulib_PageSize(a6),d0
        rts
;ENDFOLD
;FOLD GetMMUType
;*************************************************
;** GetMMUType                                  **
;** return the type of the MMU installed        **
;*************************************************
GetMMUType:
        moveq #0,d0
        move.b mulib_MMUType(a6),d0
        rts
;ENDFOLD
;FOLD GetMMUConfig
;*************************************************
;** GetMMUConfig                                **
;** read the MMU hardware registers.            **
;** should be handled with care                 **
;*************************************************
GetMMUConfig:
        move.l #mcf_len,d0
        bsr AllocContextMem             ;get memory for the configuration
        beq.s .exit

        move.l d0,-(a7)
        move.l d0,a0
        jsr mulib_ReadConfig(a6)        ;fill in the MMU configuration
        move.l (a7)+,d0
.exit:
        rts
;ENDFOLD
;FOLD ReleaseMMUConfig
;*************************************************
;** ReleaseMMUConfig                            **
;** release the MMU information                 **
;*************************************************
ReleaseMMUConfig:
        move.l a1,d0
        beq.s .noconfig
        bsr FreeContextMem
.noconfig:
        rts
;ENDFOLD



        section main_data,data
;FOLD Strings
        xdef MMUName
MMUName:        dc.b "mmu.library",0
UtilityName:    dc.b "utility.library",0
ExpansionName:  dc.b "expansion.library",0
MC68040Name:    dc.b "68040.library",0
MC68060Name:    dc.b "68060.library",0
                dc.b "$VER: "
IDString:       dc.b "mmu "
                TextVersion
                dc.b " "
                TextDate
                dc.b " (c) 1998 The MMU.lib development group, THOR",$0a,$0d,0

;ENDFOLD
;
