[Top] [All Lists]

Re: tlb magic

Subject: Re: tlb magic
From: Ralf Baechle <>
Date: Tue, 14 Jun 2005 18:18:49 +0100
In-reply-to: <>
Original-recipient: rfc822;
References: <> <>
User-agent: Mutt/1.4.1i
On Tue, Jun 14, 2005 at 06:00:26PM +0200, wrote:

> yes, I'm reading "See MIPS Run". So thanks for the online support that comes
> with it. Now, if I got it correctly, the exception routing described in
> section 6.7 uses per-process mappings for kseg2, i.e. that e.g. the first
> 2MB of (each) kseg2 are used  as page table of the corresponding process and
> maybe another few kb for process related stuff. Provided the page tables are
> continuously at the same address ( e.g. KSEG2_BASE ) a change of ASID in
> EntryHi would indeed make a change of the kseg2 pointer in Context
> unnecessary ( it always points to KSEG2_BASE ). The mapping of kseg2 would
> automatically change as the global bit is set to zero. 
> Using the standard page table approach I would now need an additional page
> table for each process in order to map those 2+x MB in kseg2 which I could
> put in kseg0/1 or in kseg2 with 'wired' TLB entries.
> If that's the way to go - why is it only used in early BSD ports of like
> 1987 ? Are there any troubles with it or have other mechanisms turned out to
> be better for any reason ?

I don't know the details of how it was used in BSD.  But this is how very
early Linux/MIPS kernels were doing it on R4000 class processors:

 - the entire 4MB of pagetables are mapped into KSEG2 at 0xe4000000
 - Linux likes to think of pagetables as 2-level trees (simplifying
   things a little here).
 - So at 4kB pagesize and 4 byte entries for each page the root of the tree
   will end up at

    root = (base + (base >> (12 - 2))

   where base is 0xe4000000; 12 the log2 of the pagesize and 2 the log2 of 4.
   So root compute to 0xe4390000.

Now let's see how we handle a pagefault in this scheme:

 - we take an exception and go to the reload handler at 0x80000000.
 - The CPU tries to help us [1] by with the value in the context register
   which with a little munging (see [1]) we use to index the 4MB of
   pagetables and load the right pagetable entry, then eret.  That's the
   fast path.

Now for the slow path.  We enter it if indexing the mapped pagetable
array at 0xe4000000 results in a TLB miss exception.  But we're already
in a TLB exception handler running with the EXL flag in the status
register set:

 - we jump to 0x80000180
 - we see it's a TLB exception, so branch to the TLB exception handler
 - The TLB exception handler figures out what kind of work it has to do.
   I only cover the TLB reload case here.
 - By now we know it must have been an access to the pagetable mapping
   that has failed.
 - We start all over by first indexing the 4kB of the root at 0xe439000
   with the upper 10 bits of the virtual address and loading the entry
   found there into the TLB.
   At this point we can guarantee that if we resume execution will take
   an exception again but we'll only use the fast path part of the handlers.

So I guess by this point you're asking why this magic address for the
TLB root.  As mentioned previously Linux consideres pagetables a two
level tree and the root of that tree (the first level) data structure
happens to be suitable as the pagetable to map the 4MB of second level

So on a context switch all that's needed is swapping the content of this
one wired entry holding the root pointer and ASID and voilla, we've
magically changed the mappings for the entire 4MB of pagetables.

I eventually removed that code because it was resulting in cache aliases
and felt that fixing them would eleminate the performance advantage of this
relativly complicated scheme.  It certainly was too funky for an early
stage OS and we may reconsider.


[1] but doesn't really succeed because for 4-byte pagetable entries the
    values in the context and xcontext registers are not formed the way we'd
    prefer them ...

<Prev in Thread] Current Thread [Next in Thread>