home *** CD-ROM | disk | FTP | other *** search
- E X C E P T I O N - H A N D L E R D E T A I L S
- ------------------------------------------------------------------------------
- Abstract:
- This document defines the exception handler mechanism of the mmu.library
- and how to make use of it.
- Please study it carefully before you try to implement an mmu.lib
- exception handler.
-
- For details about the concepts of a "context", read the mmu.doc.
- ------------------------------------------------------------------------------
- What is a bus error exception:
-
- A bus error can be understood as a sort-of "interrupt" which is triggered
- by either a software fault or a hardware signal related to acessing memory
- or external devices in an unsupported fashion, like accessing a non-available
- memory location or writing to a write-protected memory region.
-
- All bus errors are re-directed to the MMU.library, but some of them remain
- unhandled and are passed over to the exec.library. Some of the remaining
- errors are handled automatically by the library, and those that remain
- will cause your "context hooks" to be called, as installed by the
- "AddContextHook" and "AddMessageHook" vectors of the mmu.library.
-
-
- The members of the MC680x0 family generate so called "bus error" for the
- following situations:
-
- - True physical bus errors:
-
- The CPU tried to access an external device, but this request was aborted
- by pulling the "bus error input" control line (TEA) of the CPU low.
- These bus errors are generated by an external bus control logic, avail-
- able for some Amiga models, on access of non-available memory.
-
- - Access errors:
-
- These errors are generated by the MMU for a non-valid access of
- a memory "page". As far as the MMU is concerned, complete memory is
- split into adjacent pages of a fixed size, usually of size 1K or 4K,
- and the MMU holds access rules, the so called "properties" for each
- of these pages. If these rules are violated, an access error is
- generated. The following violations may arise:
-
- The CPU tried to access a page of memory marked by the MMU as
- "non-resident", or tried to write to a memory block which is write-
- protected, or tried to access a memory block in user mode which is
- marked as "supervisor only" access.
-
- Of all of these bus errors, the mmu.library handles only the part which it
- is "interested in". True physical bus errors are not handled by the
- MMU.library and passed thru to the exec exception handler - which again, calls
- the exception handler of the task that caused the exception. Additionally,
- the MMU.library does not try to fix bus errors caused by so called "locked
- transfers", i.e. the instructions "TAS","CAS" and "CAS2". These instructions
- are only useful for multi-processor machines and not supported by the Amiga
- hardware architecture anyways. A legal Amiga program *must not* use them.
-
- Furthermore, the "MOVE16" instruction accesses of the 040 and 060 processors
- are not handled, too, for the same reason. All these errors are passed thru
- to exec, and remain unhandled. They will usually force a fatal software
- failure.
-
- An additional special case - which might be interesting for the experts -
- is writing to memory by "instruction function code". This is only possibly
- by loading this function code to the "dfc" register and then using the
- privileged "moves" instruction to write instruction data. This is unsupported,
- too. Just write instructions with "move", then flush the cache. This is, too,
- what the dos.library does when loading code.
-
-
- All remaining accesses are handled by the MMU library, and are first filtered
- again. The MMU library distinguishes:
-
- - User mode and supervisor mode accesses.
-
- All exec tasks MUST run in user mode, and this is the "default" situation.
- The user mode exceptions are handled according to the "MMU context" they
- are generated by, or, equivalently, the context the current task is attached
- to. All supervisor mode accesses are managed by one single context, the
- "supervisor context".
-
- - Data vs. instruction accesses.
-
- Whether the bus error happened due to faulted access of data, or whether
- the CPU tried to fetch instructions, and this instruction fetch faulted.
- Instruction write accesses, as they might have been generated by a "moves",
- might or might not be handled, this is implementation specific. The CPU
- itself never generates these accesses when fetching code, the only
- possibility is a "moves" instruction.
-
- - Read vs. write accesses.
-
- Whether data was about to be read by the CPU, or the CPU tried to write
- out data. Instruction accesses by the CPU are always of reads.
- Accesses to the stack, as for subroutine calls or "link" instructions
- are regarded as data accesses, too. (Read about special caveats about
- the stack, below!)
-
- Amongst all these types, the MMU library handles certain special cases
- automatically. You never see these faults from your context hooks, they
- are completely transparent and handled by the library as a special service.
-
- - AbsExecBase reads.
-
- To be able to mark the first memory page as "invalid", the MMU library
- filters out accesses to AbsExecBase itself in the first stage of the exception
- handler, to emulate them as fast as possible. The library will try to emulate
- the most popular instructions in software, for optimal performance. However,
- still try to avoid reading AbsExecBase in your code. Make a copy to a static
- library base on startup, and then use this backup copy whenever possible.
- Most modern C compilers do that automatically anyways, but assembly language
- authors should keep this in mind.
-
- DON'T (slow!) DO (fast)
-
- move.l AbsExecBase,a6 move.l mn_SysBase(a4),a6
-
-
- In case the special threatment of AbsExecBase is not desired, set the
- MCXTAG_EXECBASE tag value of the CreateMMUContext() call to FALSE. This might
- be interesting for emulators, for example.
-
- Remember that interrupt code is handled by the supervisor context, AND NOT
- BY YOUR USER CONTEXT. Hence, accessing AbsExecBase from within interrupts is
- always valid, simply because the supervisor context is always build by the
- library itself, and this flag is always set on creation of this context.
- DO NOT touch the supervisor context unless you know precisely what you're
- doing.
-
-
- - Accesses above 0x0400 in the first memory page.
-
- The mmu.library emulates accesses above addresses 0x0400 to the first
- page in memory. This is again to allow setting the first page to "invalid"
- for tracing access errors in the autovector region. Accesses to addresses
- above and including 0x400 in the first page are therefore always legal.
- This feature can be disabled again with the MCXTAG_EXECBASE flag, see above.
-
- AVOID THESE ACCESSES, THEY ARE EMULATED IN SOFTWARE AND VERY SLOW.
-
- Starting with Os 3.0, exec tries to help these MMU programs by starting
- chip memory at 0x1000, not at 0x0400 as usual, if a 040 or 060 CPU is
- available. This means that for page sizes of 4K for the 040 and 060, and
- for page sizes of 1K for the 030 and 68851/020 MMU, no accesses need to
- be emulated. Please keep this in mind when using the MMU because THE
- EMULATION CODE IS SLOW. Try to use these "natural" page sizes whenever
- possible.
-
- If not possible, try to relolate the libraries and buffers in this memory
- region, usually some graphics.library buffers, the expansion library base,
- and - possibly - the exec library.
-
- Trying to execute code in this memory region does work, but is really, really
- slow. Each instruction access has to go thru the mmu.library exception
- handler, so feel prepared that your computer runs in "slo-mo mode" if you
- don't follow these rules.
-
-
- - Writes to MAPP_ROM pages.
-
- The mmu.library tries to cancel writes to pages marked as "ROM". Writes
- to these pages will generate an access error, which is "ignored" by
- the mmu.library. Hence, memory regions marked as "ROM" will get an
- effective "silent" write protection. However, keep in mind that a write
- to "ROM" area is still slow because it includes running the exception handler.
- This goes even more for the 060 CPU because it includes copying the "ROM"
- to a dummy writable backup page into which the write is then redirected.
-
- Special care must be taken for "misaligned" writes, i.e. writes that hit
- the "border" of a ROM region and go partially into valid RAM, and partially
- into "ROM" regions. The MMU.library DOES NOT guarantee that the valid part
- of the access is performed! It might abort the complete write!
-
- This shouldn't be much of a problem because writes to ROM should only happen
- due to faulty software, and it should only do good to abort these writes
- completely.
-
-
- To say that again: All the cases above are handled by the library trans-
- parently, you don't see them from your context hook. However, the following
- cases ARE seen from your hook function:
-
-
- - Access to MAPP_SWAPPED pages.
-
- If a read or write hits a page marked as swapped, the library calls all
- hooks in its "swapped" hook list. For details what happens then, see below.
-
- Again, special care must be taken if the access is "misaligned", i.e. hits
- more than one page at once. In this case, the library checks if both accesses
- are allowed, i.e. go either to valid pages, or to swapped pages. In case
- any of the accesses is invalid, the "segmentation fault" hook list, see
- below, is called.
-
-
- - Any other access,
-
- as there are accesses to "MAPP_INVALID" pages or to supervisor only pages
- in user mode, or write accesses to write protected pages are passed over
- to the "segmentation fault" hook list.
-
-
- How your hook function is called:
- ---------------------------------
-
- The mmu.library keeps two priority sorted lists for each MMU context, one
- for the "swapped" hook list for pages currently "swapped out", and another
- for the "segmentation fault" hook lists. The mmu library first determinates
- which list has to be used to handle the access, and then tries to find the
- right handler. The following algorithm is used:
-
- - Try the handler of higher priorities first;
- - Check whether this hook is activated or not, skip it if it is
- deactivated;
- - Check whether the hook is "task specific", i.e. whether the
- MADTAG_TASK tag was given at the time the hook was added with
- AddContextHook().
- If the hook is task specific, check whether the faulty task
- is identical to the task handled by the hook and skip the
- handler if this is not the case.
- - As soon as a match has been found, call the routine at the
- address provided by the MADTAG_CODE tag. This should be an
- assembly routine, mainly for speed reasons. Furthermore,
- parameters are passed in registers, similar to the exec.library
- interrupts, and return values have to be provided in the d0
- register and in the "Z" bit of the processor.
-
- You're called like this:
-
- Register a0 contains a pointer the exception data structure,
- discussed below.
-
- Registers a1 and a4 contain the data provided by the MADTAG_DATA
- tag on creation.
-
- Register a6 contains the pointer to the mmu.library base.
-
- Register a5 contains the pointer to your code.
-
- You may alter registers d0-d1, a0-a1 and a4-a5. They will be restored by the
- library automatically. All other registers MUST BE preserved.
-
- In case you want make use of the exception data structure, please keep in
- mind that it is only valid as long as your exception hook executes. That
- means that you possibly have to make a copy of it for later use.
-
- Remember, too, that you're called in supervisor mode, with all interrupts
- disabled. DO NOT ACCESS ABSEXECBASE IN YOUR CODE, use either a private
- copy, or the copy in the ExceptionData structure below. Accessing
- AbsExecBase MIGHT BE FATAL!
- Additionally, THERE IS NO DIRECT ACCESS to the CPU specific exception
- stack frame. Exception hooks are - and that's the great point about the
- mmu library - CPU indepentent. All data you need is provided in the
- exception data structure, DO NOT MAKE ANY ASSUMPTIONS which CPU you're
- running at, or how the stack frame looks like. This is the matter of the
- library.
-
-
- On return, you should set d0 to 0 and set the zero flag to indicate that
- your exception handler was able to handle the fault and return to the
- library with a plain "RTS". In that case, the library will no longer look
- for more handlers.
- If you haven't been able to handle the fault, return 1 in d0 and clear
- the zero flag (i.e. return a "ne" condition in the CCR register).
-
- In case the library did not find any hook that claimed to be able to
- repair the fault, it will redirect control back to the exec exception
- handler (which will, by default, run the GURU).
-
- BE WARNED! Another bus error within the bus error handler IS FATAL AND WILL
- CAUSE A GURU! Within the exception handler, YOU MUST ENSURE that all memory
- accesses are valid or you're lost. The library function GetPagePropertiesA()
- is ideal for this purpose: First, it is safe to get called within interrupts
- and bus errors, it is rather optimized and you find all information required
- to call it in the ExceptionData structure.
-
- The ExceptionData structure
- ---------------------------
-
- This structure is the key to the powers of the MMU. Your handler is called
- with a pointer in *a0 to this structure:
-
- struct ExceptionData {
- struct Task *exd_Task;
- struct MMUContext *exd_Context;
- ULONG *exd_Descriptor;
- ULONG *exd_NextDescriptor;
- APTR exd_FaultAddress;
- APTR exd_NextFaultAddress;
- ULONG exd_UserData;
- ULONG exd_NextUserData;
- ULONG exd_Data;
- APTR exd_ReturnPC;
- ULONG exd_Flags;
- ULONG exd_Properties;
- ULONG exd_NextProperties;
- UBYTE exd_internal;
- UBYTE exd_FunctionCode;
- UBYTE exd_Level;
- UBYTE exd_NextLevel;
- ULONG exd_DataRegs[8];
- ULONG exd_AddrRegs[7];
- UWORD *exd_SSP;
- UWORD *exd_USP;
- struct ExecBase *exd_SysBase;
- struct MMUBase *exd_MMUBase;
- };
-
- Let's discuss the fields in this structure:
-
- exd_Task contains the pointer to the task structure of the task
- that caused the exception.
- If this hook was added to the supervisor context, this
- field is meaning less and must be left alone.
-
- exd_Context contains the ID of the MMU context responsible for the
- fault. This is always the context the hook was added to.
-
- exd_Descriptor contains a pointer to the true hardware MMU descriptor which
- handles the fault. This is usually of less interest except
- for special purposes.
- In case of an indirect descriptor, this points NOT to the
- final page descriptor, but to the indirect descriptor.
-
- WARNING! In case you read this descriptor or write a new
- one, you *MUST* call CacheClearE() to make sure that the
- descriptor is really written out. The library will always
- flush descriptors correctly.
-
- exd_NextDescriptor In case of a misalgined access, i.e. an access that
- spawns two pages because it hit a page boundary, this is the
- descriptor for the end address of the access, and
- exd_Descriptor is the descriptor for the first address
- of the access. If the access is aligned, both pointers are
- identically.
- NOTE THAT THIS DESCRIPTOR NEED NOT TO POINT TO A HIGHER
- ADDRESS. An example for a "backwards" misaligned access is
- the "movem.l regs,-(ax)" instruction.
-
- WARNING! In case you read this descriptor or write a new
- one, you *MUST* call CacheClearE() to make sure that the
- descriptor is really written out. The library will always
- flush descriptors correctly.
-
- exd_FaultAddress
- The address that faulted, the start address of the access.
-
- exd_NextFaultAddress
- The end address of the access that faulted, inclusive.
- For a long word access, this would be exd_FaultAdress + 3,
- for a byte access, this would be identically to
- exd_FaultAdress.
- Note that it may well be that exd_NextFaultAddress is a
- SMALLER address than exd_FaultAdress. This might, for example,
- happen for a movem with pre-decrement addressing mode, i.e.
- a "movem.l d0-d7/a0-a6,-(a7)". Exception handlers must be
- aware of this special situation.
-
- exd_UserData The user data provided for invalid and swapped pages, as
- defined by SetPropertiesA() and SetPagePropertiesA().
- This will be NULL in case no user data is available.
-
- exd_NextUserData
- In case of a misalgined access, the user data of the
- second page that was involved in the exception. If the
- access was aligned, this is identical to exd_UserData.
-
- exd_Data If the access was a write access and the
- EXDF_WRITEDATAUNKNOWN flag (see below) is cleared, then
- this long word will contain the data the CPU tried to
- write out. The data is right-justified in this field, i.e.
- bytes will use bits 7..0, words will use bits 15..0 and
- long word accesses will use the complete field.
- The size is available by subtracting the exd_FaultAddress and
- exd_NextFaultAddress fields.
- On movem faults, the complete write data is unfortunately
- not available. You may see movem faults as a series of
- long word writes on some CPUs, while this instruction is
- atomic on other CPUs. There's nothing the MMU library can
- do for you here.
- This data should be used only for debugging purposes and
- "Enforcer like" applications, and for applications where you
- can guarantee that movems do not occur, i.e. emulators that
- threat "computer hardware" by the MMU and might read the
- data written to the emulated hardware right here.
-
- To allow the MMU library to fetch write data, you *MUST*
- set the "MAPP_REPAIRABLE" bit of pages you want write data
- for. In all other cases, you *might* get write data, but
- this is a matter of "good luck". (Or, in other words, I don't
- want to document the messy details.)
- Please do only set this bit in case you really need the
- write data because it means much more work for the library
- and much "higher magic" to get it, especially for the 060
- CPU.
-
- In case you want to allow the CPU to continue execution and
- you somehow managed to write out the data itself (or you
- want to ignore the faulty access), set the
- EXDF_WRITECOMPLETE bit of the flags field below.
-
- In case you do not set this bit, the CPU will attempt to
- re-run the faulty instruction. In case you haven't been able
- to repair the fault using some other techinque (as for
- example by swapping in the faulty page), your exception
- handler will be called again.
-
- In case of a read fault, you may place the data to be
- read back in this field and set the EXDF_READBACK flag
- in the flags value below. The MMU library will then
- attempt to place this value in the input pipe of the CPU
- and to repair the faulty access by providing this dummy
- data. The data has to be placed right-justified in this
- field again.
-
- Certain restrictions arise, again:
-
- First, a movem might show up as several exceptions, hence
- you might be able to provide data for each register loaded,
- or it might show up as one single exception. In this case,
- all registers will be loaded with the same value. (It was
- hard enough to emulate this, so please don't complain...)
-
- Instruction faults can't be repaired like this. (I would
- have been able to provide this exclusively for the 030 and
- the 020, but I choose not to do so for orthogonality).
- Don't try it, the mmu.library will call the exec exception
- handler directly in case you attempt this.
-
- exd_ReturnPC The program counter of the instruction that caused the
- fault. This is only an approximate value due to the
- instruction prefetch feature of all CPUs of the 680x0
- family. In case a branch was performed after the faulty
- instruction was loaded, and before it was detected, this
- PC might be completely useless. However, the program
- is guaranteed to continue "at the right place".
-
- In case you set the EXDF_CALL flag, this field contains
- the address of a small procedure which will be called in
- user mode, in the context of the task that caused the
- exception. This routine could, for example, send a message
- out to a "daemon" to get the fault repaired and could run
- into a WaitPort() to get an answer from the daemon.
- The user routine has access to all registers of the faulty
- program, and must therefore preserve all registers unless
- it attempts to alter them "on purpose". The exception data
- IS NO LONGER AVAILABLE, neither in the mmu library base
- nor in any register. If you want to make use of it, make a
- copy of it in the exception handler to a private place and
- access it in this user routine.
-
- Alternatively, use the "message hook" mechanism of the
- library which provides all this for you already if you don't
- want to get a headache.
-
- The user routine should then return with a "RTS" to the
- library code (note that the stacked PC points to some code
- in the library, not to the faulty code itself! It's truely
- deep magic to restore all this information) which will then
- rerun the faulty instruction.
-
- If you haven't been able to repair the cause of the fault,
- the exception hook will be called again!
-
- exd_Flags A combined input/output flags long word. Amongst private
- flags you'd better not care about, the following input
- flags are available:
-
- EXDF_WRITE a write fault if set. If reset, a read fault.
- EXDF_INSTRUCTION a fault on fetching an instruction.
- As a special case, this *could* be a write fault
- if someone tried to write out instruction data
- with an instruction function code using the
- "moves" instruction. This is actually unsupported
- by the library and should not be tried.
- EXDF_WRITEPROTECTED failed due to write protection of the destination.
- EXDF_SUPERVISOR failed due to supervisor only protection of the
- source/destination.
- EXDF_WRITEDATAUNKNOWN the write data was lost, exd_Data is invalid.
- Remember that you MUST set the MAPP_REPAIRABLE
- property flag for those pages you want write data
- for, and you should only set this bit if you really
- really want them. It means quite a lot of trouble
- for the library to provide the write data, hence
- things are not getting faster with it.
- EXDF_MISALIGNED The access was misaligned, i.e. more than one
- page was involved in the access. Prepare to
- swap in more than one page, for example.
-
- The following flags can be set by your code to let the
- library know what to do about the fault:
-
- EXDF_READBACK abort a faulty read and provide the exd_Data word
- as input for the CPU. Do not try to rerun the access.
- EXDF_WRITECOMPLETE abort a faulty write, do not try to rerun it.
- EXDF_CALL call routine whose address is in exd_ReturnPC in
- user mode in the context of the task that caused
- the exception. This routine will be run as "sub-
- routine" of the task that faulted, and might be
- used to sent out a message and wait for its reply
- to get the missing page fixed by another supervisor
- task.
- THIS FUNCTION IS NOT AVAILABLE for the supervisor
- context. The mmu.library will guru in case you try
- to.
- Especially, the message hook mechanism described
- below uses this flag.
- Note that the library does not check for you whether
- Wait()-ing is useful here, as for example if the task
- is in Forbid state. It's the matter of the exception
- hook to check this.
- The library message hook exception does
- this, for example.
-
- exd_Properties The property flags of the page that was responsible for
- the fault.
-
- exd_NextProperties In case of a misaligned access, the flags of the second
- page involved in the access.
-
- exd_internal Leave this alone.
-
- exd_FunctionCode The function code of the access. The following values
- should be expected:
-
- For the user context hooks:
- 1 User data access
- 2 User code access
-
- For the one and only supervisor context and its hooks:
- 5 Supervisor data access
- 6 Supervisor code access
-
- All remaining function codes relate to physical bus errors
- and should not be passed thru to your context hook.
-
- exd_Level The level of the MMU tree at which the access fault happend
- and at which the MMU descriptor resides.
- This NEED NOT to be the "page level" for early termination
- descriptors or invalid descriptors at a higher level.
- Experts should note that this is not even guaranteed for
- the 040 or 060!
- Furthermore, in case of an indirect descriptor, this is the
- level of the pointer pointing to the final page descriptor,
- not the level of the real page descriptor.
-
- This is advanced information you usually should not care
- about.
-
- Level A of the MMU tree is encoded as "0", level B as "1"
- and so on. Note that this numbering is different from the
- MC680x0 internal counting.
-
-
- exd_NextLevel In case of a misaligned access, the level of the second
- descriptor involved in the fault.
-
- exd_DataRegs A copy of the data registers at the time the fault happened.
- These images are copied back as soon as the exception
- terminates, hence a "higher magic" exception handler could
- alter these...
-
- exd_AddrRegs A copy of the adress registers, but without the stack
- pointer.
-
- exd_SSP The supervisor stack pointer. This points directly to the
- processor specific exception stack frame. The first UWORD
- of this stack frame is the copy of the status register at
- the time of the fault.
- BE WARNED! Everything else is processor specific, the
- mmu.library might also want to modify this exception stack
- frame, so hands off!
-
- exd_USP The user stack pointer.
-
- exd_SysBase A pointer to the library base of the "exec.library". DO NOT
- ACCESS ABSEXECBASE within the exception handler. Use either
- a private copy, or this pointer.
- NOT FOLLOWING THIS RULE MIGHT BE FATAL!
-
- exd_MMUBase A pointer to the library base of the mmu.library, also in
- register a6.
-
- Additional notes about the exception handlers
- ---------------------------------------------
-
- In case you're going to write an automatic stack extension program, you
- should keep in mind that the EXDF_CALL - and therefore the message hook -
- mechanism requires about 300 bytes of user stack space. Similar, task
- switching takes some user stack, too. To be able to swap in stack in case
- of a stack overflow, a message hook alone WON'T DO GOOD for this reason.
-
- Use the following mechanism:
-
- - Add a high-level exception hook that extends the user stack in super-
- visor mode with a "Last Chance" backup page you must have preallocated.
- Note that calling AllocMem() in supervisor mode is not permitted!
-
- Return with d0 not equal zero to allow the library to call all other hooks.
-
-
- - Add a low-level message hook that captures the underflow and utilizes
- the stack you prepared in the high-level handler.
-
-
- For the same reason, you might have to add "Switch" and "Launch" handlers
- to allow execbase to store the user registers safely. Unfortunately, this
- is done with supervisor accessed going to the user stack, and not with a
- "moves".
-
-
- Additional wierdos to watch out for
- -----------------------------------
- There are unfortunately a number of "features" of each CPU which should not
- go unmentioned:
-
- The 68020/68851 and 68030:
-
- Execution of instructions in a access-protected "zero page" is really,
- really slow. Please keep this in mind!
- "moves" to instruction space is unsupported (goes for all other CPUs
- as well).
-
- The FPU and exceptions: This is a dark chapter in exception handling.
- Of a faulty fmove, only the first two long words are checked by the
- 68030 and therefore at most two hits get reported, all others go
- unnoticed. Of a faulty fmovem, only the first two long words hits get
- reported, too. The CPU will ignore all other hits and continue
- execution.
- This means specifically that a Debugger tool might not be able to see
- all hits that happened on these instructions, and you will not be
- able to capture them for private use.
- VM systems shouldn't have much problems with that, though, since the
- invalid page should have been swapped in and each access can hit at
- most two pages at once if it is misaligned. However, you must be
- prepared that the mmu.library will not be able to set the "misaligned"
- flag correctly in this case.
-
- The 68040:
-
- Movem writeback data is not always available, and certain movems can't
- be continued safely. In case a movem read or write goes to an invalid
- page other than at level 2 or 3, the mmu library has to abort the movem
- completely. There's nothing I can do against it. To avoid this situation
- in case you really need the movem data, set the MAPP_REPAIRABLE property.
-
- Movems to a register included in the register list itself cannot be
- rerun safely in all circumstances. Avoid them.
-
- Readback data is only available for all destination registers at once.
-
- The FPU and exceptions: Even more problems than with the 030.
- If a fmove or fmovem moves more than two long words, for example a
- fmove.x or any fmovem, the processor will only notice the first
- access of a faulty page. If the instruction would catch more than
- one hit, the processor restarts the instruction completely from the
- beginning. This means for debugging tools that you will *not* be
- able to fix a faulty instruction of this kind at all, the processor
- will loop forever. Note that even disassembling the instruction at
- the PC will not help because the PC might point to an FPU instruction
- even if the hit was caused by the instruction before. Hence, the
- following two instructions
-
- move.l d0,(a3)
- fmovem.x fp0,(a3)
-
- with a3 pointing to an invalid page, will both invoke the exception
- handler with the same PC value, namely the address of the fmovem.
-
- This might be a problem for VMM systems as well: Because there's no
- single flag that tells whether the hit was caused by an FPU instruction
- or not, the processor might re-run a FPU instruction as mentioned
- above again, possibly accessing the two different pages. If the VMM
- system would have swapped in the second page by the first hit, and
- removed the first page accessed by this instruction from memory,
- re-running this instruction will cause another VMM hit, this time
- from the first page. It is therefore important that a VMM system
- *MUST NOT* swap out a page previously swapped in. At least two pages
- must be available at once.
-
-
- The 68060:
-
- The library handles branch cache flushes transparently, no need to
- worry about them. So much for the good point.
-
- Writeback data is usually not available unless the library emulates
- this with some heavy magic and is told to do so with the MAPP_REPAIRABLE
- flag. Things are getting even worse if no exception handler wants to
- make use of the writeback data and returns with the EXDF_WRITEBACK flag
- cleared. In this case, the mmu.library tries to rerun the faulty
- instruction again, even though it already executed. It tries to rebuild
- all the registers (except for the FPU registers and the supervisor model
- and the SSP) and then returns to the PC of the faulty instruction.
- Whether this mechanism is reliable or not has to be proven.
-
- Except that, all 040 restrictions regarding movems apply here again, see
- above.
-
- In case of a non-locked read-modify-write access, as for example a
- addq.l #1,(ax), the library will call the context hooks twice, once
- with the read data, and then again with the write data. However, things
- are getting rather nasty in case of a misaligned RMW access of which
- one part of the access is valid and the other part is not. The 060
- manual states that these accesses can't be rerun safely because parts
- of the data might have been written back already, and rerunning the
- instruction might cause this wrong data to be re-used again. I can't
- comment on that feature because I haven't tried to reproduce it yet,
- but it may reduce reliability of the 060 for virtual memory appli-
- cations.
-
- ------------------------------------------------------------------------------
-
- About the page access exception:
-
-
- This is not a true exception, but is installed and handled the like. It is
- setup with AddContextHook(MADTAG_TYPE,MMUEH_PAGEACCESS,....) as all other
- exception handlers. The page access hook "hooks in" between the high level
- functions SetProperties/GetProperties/RebuildTree and the low level functions
- SetPageProperties/GetPageProperties at the other side. It provides a method
- to modify the MMU tree on the low level transparently to the high level
- functions.
-
- The page access handlers are called whenever RebuildTree() tries to re-
- install a page descriptor with the MAPP_SINGLE property bit set. If so, your
- handler is allowed to modify this page descriptor. However, you should
- remember that the high-level functions are not aware of this modification,
- so this feature should be used carefully.
-
- A possible application would be a "Guardian Angel" type program: The idea
- is here to mark "free" memory as MAPP_INVALID to be able to detect illegal
- memory accesses. Since an AllocMem() has to mark the memory valid it
- allocated, the MMU tables have to be adjusted for each allocation. Similary,
- released memory has to be made unavailable on a FreeMem(). On the
- other hand, AllocMem() is not allowed to break a Forbid() and is hence not
- able to call the high-level functions - which might do so. It *has* to use
- the low level SetPageProperties(). Since the low level functions do not
- inform the higher level about the modification, a program adjusting the
- MMU descriptor with the high-level functions will un-do the modifications
- made by AllocMem() before. The solution here is to install a page access
- handler that checks whether the higher level is going to re-install one
- of the modified page descriptors, to intercept here and to set the
- MAPP_INVALID flag correctly, by testing whether the addressed memory page is
- "free" or not.
-
-
-
- Your handler is called with the page access data structure - see below - in
- a0, with the provided user data from MADTAD_DATA in a1 and a4 and the
- library pointer in a6. Registers d0-d1/a0-a1/a4-a5 are scratch registers,
- a6 IS NOT. In case your handler returns with the Z flag set, the library
- aborts calling other handlers of lower priority.
-
- Remember that you're called in supervisor mode with all interrupts dis-
- abled, as for all other exception handlers. Your code should better be
- fast!
-
-
- Now for the structure:
-
- struct PageAccessData {
- ULONG pgad_Level;
- void *pgad_Address;
- ULONG *pgad_Destination;
- struct MMUContext *pgad_Context;
- struct MMUBase *pgad_MMUBase;
- ULONG pgad_Properties;
- ULONG pgad_UserData;
- };
-
-
- pgad_Level: The level at which the MMU descriptor has to be build
- for. This is zero for level A, one for level B and so
- on. Note that this numbering is different from the
- internal MC68K scheme.
- Since this handler is only called for MAPP_SINGLE
- descriptors, this will always be the page level of the
- MMU tree. However, what the page level *is* is up to
- the depth of the MMU tree and may vary.
-
- pgad_Address: The logical address the descriptor to be build will
- handle. Hence, this gives the address that is to be
- translated or mapped.
-
- pgad_Destination: The address the true hardware descriptor will be written
- to. There's little reason to make use of this entry.
-
- pgad_Context: The context the MMU tree being rebuild belongs to. This
- is the context you installed the page access handler in.
-
- pgad_MMUBase: The library base address.
-
- pgad_Properties: The page properties, defined in mmu/context.h. This
- defines which kind of hardware descriptor the library
- will build for you.
-
- pgad_UserData: This field will be used for MAPP_SWAPPED, MAPP_INVALID,
- MAPP_REMAPPED, MAPP_BUNDLED and MAPP_INDIRECT
- descriptors. It will contain user specific information
- like a hard disk position for MAPP_SWAPPED or
- MAPP_INVALID pages, the destination address for
- MAPP_REMAPPED and MAPP_BUNDLED pages, and the destination
- descriptor for MAPP_INDIRECT. It is not available if the
- MAPP_REPAIRABLE bit is set. In case you modify the
- properties, you possibly need to correct this field, too.
-
-