MMU: Implement a vestigial partition table
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 17 Jun 2021 10:01:32 +0000 (20:01 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 17 Jun 2021 12:19:23 +0000 (22:19 +1000)
This implements a 1-entry partition table, so that instead of getting
the process table base address from the PRTBL SPR, the MMU now reads
the doubleword pointed to by the PTCR register plus 8 to get the
process table base address.  The partition table entry is cached.

Having the PTCR and the vestigial partition table reduces the amount
of software change required in Linux for Microwatt support.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
14 files changed:
common.vhdl
decode1.vhdl
loadstore1.vhdl
mmu.vhdl
tests/mmu/mmu.c
tests/modes/modes.c
tests/privileged/privileged.c
tests/reservation/reservation.c
tests/spr_read/spr_read.c
tests/test_mmu.bin
tests/test_modes.bin
tests/test_privileged.bin
tests/test_spr_read.bin
tests/test_spr_read.console_out

index 69dde308d8d2c579830d41972ca74ed09d117535..b18a271754955389ad84be826f8d57ae4094390c 100644 (file)
@@ -51,7 +51,7 @@ package common is
     constant SPR_HSPRG0 : spr_num_t := 304;
     constant SPR_HSPRG1 : spr_num_t := 305;
     constant SPR_PID    : spr_num_t := 48;
-    constant SPR_PRTBL  : spr_num_t := 720;
+    constant SPR_PTCR   : spr_num_t := 464;
     constant SPR_PVR   : spr_num_t := 287;
 
     -- GPR indices in the register file (GPR only)
index 2869c3911b2b61a919529e6da0f8f9eb300a0616..5d0bdcb94dd10958fe7efd763c4f6505b9514de7 100644 (file)
@@ -609,7 +609,7 @@ begin
                     vi.force_single := '1';
                     -- send MMU-related SPRs to loadstore1
                     case sprn is
-                        when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PRTBL =>
+                        when SPR_DAR | SPR_DSISR | SPR_PID | SPR_PTCR =>
                             vi.override_decode.unit := LDST;
                             vi.override_unit := '1';
                         when others =>
index 33286170c2167a6fbee1c731dc1b8a7cf2a0976f..822cc1955346d1ba2e1c168f8b2ec8b161e49f88 100644 (file)
@@ -477,7 +477,7 @@ begin
                 v.read_spr := '1';
             when OP_MTSPR =>
                 v.write_spr := '1';
-                v.mmu_op := sprn(9) or sprn(5);
+                v.mmu_op := sprn(8) or sprn(5);
             when OP_FETCH_FAILED =>
                 -- send it to the MMU to do the radix walk
                 v.instr_fault := '1';
@@ -732,7 +732,7 @@ begin
                 write_enable := '1';
                 -- partial decode on SPR number should be adequate given
                 -- the restricted set that get sent down this path
-                if r2.req.sprn(9) = '0' and r2.req.sprn(5) = '0' then
+                if r2.req.sprn(8) = '0' and r2.req.sprn(5) = '0' then
                     if r2.req.sprn(0) = '0' then
                         sprval := x"00000000" & r3.dsisr;
                     else
index 623c2c9313077c2ffa8a44fbefef56ac4e3eae1b..d80caf449ce8a00bbc80ab25d97736e7c123ae7b 100644 (file)
--- a/mmu.vhdl
+++ b/mmu.vhdl
@@ -29,6 +29,9 @@ architecture behave of mmu is
     type state_t is (IDLE,
                      DO_TLBIE,
                      TLB_WAIT,
+                     PART_TBL_READ,
+                     PART_TBL_WAIT,
+                     PART_TBL_DONE,
                      PROC_TBL_READ,
                      PROC_TBL_WAIT,
                      SEGMENT_CHECK,
@@ -47,12 +50,14 @@ architecture behave of mmu is
         addr      : std_ulogic_vector(63 downto 0);
         inval_all : std_ulogic;
         -- config SPRs
-        prtbl     : std_ulogic_vector(63 downto 0);
+        ptcr      : std_ulogic_vector(63 downto 0);
         pid       : std_ulogic_vector(31 downto 0);
         -- internal state
         state     : state_t;
         done      : std_ulogic;
         err       : std_ulogic;
+        prtbl     : std_ulogic_vector(63 downto 0);
+        ptb_valid : std_ulogic;
         pgtbl0    : std_ulogic_vector(63 downto 0);
         pt0_valid : std_ulogic;
         pgtbl3    : std_ulogic_vector(63 downto 0);
@@ -77,7 +82,7 @@ architecture behave of mmu is
 begin
     -- Multiplex internal SPR values back to loadstore1, selected
     -- by l_in.sprn.
-    l_out.sprval <= r.prtbl when l_in.sprn(9) = '1' else x"00000000" & r.pid;
+    l_out.sprval <= r.ptcr when l_in.sprn(8) = '1' else x"00000000" & r.pid;
 
     mmu_0: process(clk)
     begin
@@ -85,9 +90,10 @@ begin
             if rst = '1' then
                 r.state <= IDLE;
                 r.valid <= '0';
+                r.ptb_valid <= '0';
                 r.pt0_valid <= '0';
                 r.pt3_valid <= '0';
-                r.prtbl <= (others => '0');
+                r.ptcr <= (others => '0');
                 r.pid <= (others => '0');
             else
                 if rin.valid = '1' then
@@ -185,6 +191,7 @@ begin
         variable tlb_load : std_ulogic;
         variable itlb_load : std_ulogic;
         variable tlbie_req : std_ulogic;
+        variable ptbl_rd : std_ulogic;
         variable prtbl_rd : std_ulogic;
         variable pt_valid : std_ulogic;
         variable effpid : std_ulogic_vector(31 downto 0);
@@ -215,6 +222,7 @@ begin
         itlb_load := '0';
         tlbie_req := '0';
         v.inval_all := '0';
+        ptbl_rd := '0';
         prtbl_rd := '0';
 
         -- Radix tree data structures in memory are big-endian,
@@ -256,11 +264,15 @@ begin
                     if l_in.sprn(3) = '1' then
                         v.pt0_valid := '0';
                         v.pt3_valid := '0';
+                        v.ptb_valid := '0';
                     end if;
                     v.state := DO_TLBIE;
                 else
                     v.valid := '1';
-                    if pt_valid = '0' then
+                    if r.ptb_valid = '0' then
+                        -- need to fetch process table base from partition table
+                        v.state := PART_TBL_READ;
+                    elsif pt_valid = '0' then
                         -- need to fetch process table entry
                         -- set v.shift so we can use finalmask for generating
                         -- the process table entry address
@@ -277,13 +289,14 @@ begin
             end if;
             if l_in.mtspr = '1' then
                 -- Move to PID needs to invalidate L1 TLBs and cached
-                -- pgtbl0 value.  Move to PRTBL does that plus
-                -- invalidating the cached pgtbl3 value as well.
-                if l_in.sprn(9) = '0' then
+                -- pgtbl0 value.  Move to PTCR does that plus
+                -- invalidating the cached pgtbl3 and prtbl values as well.
+                if l_in.sprn(8) = '0' then
                     v.pid := l_in.rs(31 downto 0);
                 else
-                    v.prtbl := l_in.rs;
+                    v.ptcr := l_in.rs;
                     v.pt3_valid := '0';
+                    v.ptb_valid := '0';
                 end if;
                 v.pt0_valid := '0';
                 v.inval_all := '1';
@@ -300,6 +313,22 @@ begin
                 v.state := RADIX_FINISH;
             end if;
 
+        when PART_TBL_READ =>
+            dcreq := '1';
+            ptbl_rd := '1';
+            v.state := PART_TBL_WAIT;
+
+        when PART_TBL_WAIT =>
+            if d_in.done = '1' then
+                v.prtbl := data;
+                v.ptb_valid := '1';
+                v.state := PART_TBL_DONE;
+            end if;
+
+        when PART_TBL_DONE =>
+            v.shift := unsigned('0' & r.prtbl(4 downto 0));
+            v.state := PROC_TBL_READ;
+
         when PROC_TBL_READ =>
             dcreq := '1';
             prtbl_rd := '1';
@@ -449,6 +478,9 @@ begin
         elsif tlb_load = '1' then
             addr := r.addr(63 downto 12) & x"000";
             tlb_data := pte;
+        elsif ptbl_rd = '1' then
+            addr := x"00" & r.ptcr(55 downto 12) & x"008";
+            tlb_data := (others => '0');
         elsif prtbl_rd = '1' then
             addr := prtable_addr;
             tlb_data := (others => '0');
index ef00824a8482ca1f17712a028031ee0dc8afedab..64afa4423350b37c72e6326d5ff25a4655b47929 100644 (file)
@@ -24,7 +24,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
 #define SRR0   26
 #define SRR1   27
 #define PID    48
-#define PRTBL  720
+#define PTCR   464
 
 static inline unsigned long mfspr(int sprnum)
 {
@@ -115,15 +115,18 @@ void zero_memory(void *ptr, unsigned long nbytes)
  */
 unsigned long *pgdir = (unsigned long *) 0x10000;
 unsigned long *proc_tbl = (unsigned long *) 0x12000;
-unsigned long free_ptr = 0x13000;
+unsigned long *part_tbl = (unsigned long *) 0x13000;
+unsigned long free_ptr = 0x14000;
 void *eas_mapped[4];
 int neas_mapped;
 
 void init_mmu(void)
 {
+       /* set up partition table */
+       store_pte(&part_tbl[1], (unsigned long)proc_tbl);
        /* set up process table */
        zero_memory(proc_tbl, 512 * sizeof(unsigned long));
-       mtspr(PRTBL, (unsigned long)proc_tbl);
+       mtspr(PTCR, (unsigned long)part_tbl);
        mtspr(PID, 1);
        zero_memory(pgdir, 1024 * sizeof(unsigned long));
        /* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
index c8ec9cee7d9b5c762c9ad1f430e81b8fba22b916..b94bb47a2118bac36737c8692af4e7eb19a71ce7 100644 (file)
@@ -33,7 +33,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
 #define SPRG0  272
 #define SPRG1  273
 #define SPRG3  275
-#define PRTBL  720
+#define PTCR   464
 
 static inline unsigned long mfspr(int sprnum)
 {
@@ -121,15 +121,18 @@ void zero_memory(void *ptr, unsigned long nbytes)
  * Set up an MMU translation tree using memory starting at the 64k point.
  * We use 3 levels, mapping 512GB, with 4kB PGD/PMD/PTE pages.
  */
-unsigned long *proc_tbl = (unsigned long *) 0x10000;
-unsigned long *pgdir = (unsigned long *) 0x11000;
-unsigned long free_ptr = 0x12000;
+unsigned long *part_tbl = (unsigned long *) 0x10000;
+unsigned long *proc_tbl = (unsigned long *) 0x11000;
+unsigned long *pgdir = (unsigned long *) 0x12000;
+unsigned long free_ptr = 0x13000;
 
 void init_mmu(void)
 {
+       /* set up partition table */
+       store_pte(&part_tbl[1], (unsigned long)proc_tbl);
        /* set up process table */
        zero_memory(proc_tbl, 512 * sizeof(unsigned long));
-       mtspr(PRTBL, (unsigned long)proc_tbl);
+       mtspr(PTCR, (unsigned long)part_tbl);
        mtspr(PID, 1);
        zero_memory(pgdir, 512 * sizeof(unsigned long));
        /* RTS = 8 (512GB address space), RPDS = 9 (512-entry top level) */
index 68e30bcd4eadb70cd98c96f042b0e989b9054cb9..fc6b23dd189ddd8e510a22c0e319533728843691 100644 (file)
@@ -14,7 +14,7 @@ extern int call_with_msr(unsigned long arg, int (*fn)(unsigned long), unsigned l
 #define SRR0   26
 #define SRR1   27
 #define PID    48
-#define PRTBL  720
+#define PTCR   464
 #define PVR    287
 
 static inline unsigned long mfspr(int sprnum)
@@ -106,15 +106,18 @@ void zero_memory(void *ptr, unsigned long nbytes)
  */
 unsigned long *pgdir = (unsigned long *) 0x10000;
 unsigned long *proc_tbl = (unsigned long *) 0x12000;
-unsigned long free_ptr = 0x13000;
+unsigned long *part_tbl = (unsigned long *) 0x13000;
+unsigned long free_ptr = 0x14000;
 
 void init_mmu(void)
 {
+       /* set up partition table */
+       store_pte(&part_tbl[1], (unsigned long)proc_tbl);
        /* set up process table */
        zero_memory(proc_tbl, 512 * sizeof(unsigned long));
        /* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
        store_pte(&proc_tbl[2 * 1], (unsigned long) pgdir | 10);
-       mtspr(PRTBL, (unsigned long)proc_tbl);
+       mtspr(PTCR, (unsigned long)part_tbl);
        mtspr(PID, 1);
        zero_memory(pgdir, 1024 * sizeof(unsigned long));
 }
index 4df4511c99b88919154ef113459189334f32ba19..a3d5a7a17246792444c87f5cb9b75467dadd4429 100644 (file)
@@ -18,7 +18,6 @@ extern unsigned long do_stqcx(unsigned long dst, unsigned long regs);
 #define PID    48
 #define SPRG0  272
 #define SPRG1  273
-#define PRTBL  720
 
 static inline unsigned long mfspr(int sprnum)
 {
index fa41154fca939dd1a9d2a56e8c88d4564e904334..6d2859e557307d77b0f6dc72f8c5213aea02605b 100644 (file)
@@ -38,7 +38,7 @@ void print_test(char *str)
 #define SPR_HSPRG0     304
 #define SPR_HSPRG1     305
 #define SPR_PID                48
-#define SPR_PRTBL      720
+#define SPR_PTCR       464
 #define SPR_PVR                287
 
 #define __stringify_1(x...)    #x
@@ -83,7 +83,7 @@ int main(void)
        DO_ONE(SPR_HSPRG0);
        DO_ONE(SPR_HSPRG1);
        DO_ONE(SPR_PID);
-       DO_ONE(SPR_PRTBL);
+       DO_ONE(SPR_PTCR);
        DO_ONE(SPR_PVR);
 
        puts(PASS);
index 7f87578a8479b4001d9aec97edf42bde0e9eabd7..1ade44ee74b94b62ae2714ae7a476a7d6bf9ed58 100755 (executable)
Binary files a/tests/test_mmu.bin and b/tests/test_mmu.bin differ
index edbe0c85e906b1d2e51257604fa9ca1687263265..7e6b8f5d03126023a7ce4e75f157bd289d1e387c 100755 (executable)
Binary files a/tests/test_modes.bin and b/tests/test_modes.bin differ
index d89b34d424e2c74ef0392d5f4e76085a134daec0..cd7f38345dde61267ec5704e0008c90d6e0c9dd2 100755 (executable)
Binary files a/tests/test_privileged.bin and b/tests/test_privileged.bin differ
index 66a546a96cfa919818a5ed73f0cf4ab3f5a80d07..68f6cd8f1d40ad5c59a98ccb0b2b2ceeeb6f7472 100755 (executable)
Binary files a/tests/test_spr_read.bin and b/tests/test_spr_read.bin differ
index 1ccac56ca609d6925d3d170ab94dcf37506f94e7..8a032d40cae4650f1a27b5c07e000f0479755023 100644 (file)
@@ -20,6 +20,6 @@ Test SPR_SPRG3U:PASS
 Test SPR_HSPRG0:PASS\r
 Test SPR_HSPRG1:PASS\r
 Test SPR_PID:PASS\r
-Test SPR_PRTBL:PASS\r
+Test SPR_PTCR:PASS\r
 Test SPR_PVR:PASS\r
 PASS\r