mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
MMU: Implement a vestigial partition table
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>
This commit is contained in:
parent
84473eda1b
commit
18120f153d
@ -51,7 +51,7 @@ package common is
|
|||||||
constant SPR_HSPRG0 : spr_num_t := 304;
|
constant SPR_HSPRG0 : spr_num_t := 304;
|
||||||
constant SPR_HSPRG1 : spr_num_t := 305;
|
constant SPR_HSPRG1 : spr_num_t := 305;
|
||||||
constant SPR_PID : spr_num_t := 48;
|
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;
|
constant SPR_PVR : spr_num_t := 287;
|
||||||
|
|
||||||
-- GPR indices in the register file (GPR only)
|
-- GPR indices in the register file (GPR only)
|
||||||
|
|||||||
@ -609,7 +609,7 @@ begin
|
|||||||
vi.force_single := '1';
|
vi.force_single := '1';
|
||||||
-- send MMU-related SPRs to loadstore1
|
-- send MMU-related SPRs to loadstore1
|
||||||
case sprn is
|
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_decode.unit := LDST;
|
||||||
vi.override_unit := '1';
|
vi.override_unit := '1';
|
||||||
when others =>
|
when others =>
|
||||||
|
|||||||
@ -477,7 +477,7 @@ begin
|
|||||||
v.read_spr := '1';
|
v.read_spr := '1';
|
||||||
when OP_MTSPR =>
|
when OP_MTSPR =>
|
||||||
v.write_spr := '1';
|
v.write_spr := '1';
|
||||||
v.mmu_op := sprn(9) or sprn(5);
|
v.mmu_op := sprn(8) or sprn(5);
|
||||||
when OP_FETCH_FAILED =>
|
when OP_FETCH_FAILED =>
|
||||||
-- send it to the MMU to do the radix walk
|
-- send it to the MMU to do the radix walk
|
||||||
v.instr_fault := '1';
|
v.instr_fault := '1';
|
||||||
@ -732,7 +732,7 @@ begin
|
|||||||
write_enable := '1';
|
write_enable := '1';
|
||||||
-- partial decode on SPR number should be adequate given
|
-- partial decode on SPR number should be adequate given
|
||||||
-- the restricted set that get sent down this path
|
-- 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
|
if r2.req.sprn(0) = '0' then
|
||||||
sprval := x"00000000" & r3.dsisr;
|
sprval := x"00000000" & r3.dsisr;
|
||||||
else
|
else
|
||||||
|
|||||||
48
mmu.vhdl
48
mmu.vhdl
@ -29,6 +29,9 @@ architecture behave of mmu is
|
|||||||
type state_t is (IDLE,
|
type state_t is (IDLE,
|
||||||
DO_TLBIE,
|
DO_TLBIE,
|
||||||
TLB_WAIT,
|
TLB_WAIT,
|
||||||
|
PART_TBL_READ,
|
||||||
|
PART_TBL_WAIT,
|
||||||
|
PART_TBL_DONE,
|
||||||
PROC_TBL_READ,
|
PROC_TBL_READ,
|
||||||
PROC_TBL_WAIT,
|
PROC_TBL_WAIT,
|
||||||
SEGMENT_CHECK,
|
SEGMENT_CHECK,
|
||||||
@ -47,12 +50,14 @@ architecture behave of mmu is
|
|||||||
addr : std_ulogic_vector(63 downto 0);
|
addr : std_ulogic_vector(63 downto 0);
|
||||||
inval_all : std_ulogic;
|
inval_all : std_ulogic;
|
||||||
-- config SPRs
|
-- config SPRs
|
||||||
prtbl : std_ulogic_vector(63 downto 0);
|
ptcr : std_ulogic_vector(63 downto 0);
|
||||||
pid : std_ulogic_vector(31 downto 0);
|
pid : std_ulogic_vector(31 downto 0);
|
||||||
-- internal state
|
-- internal state
|
||||||
state : state_t;
|
state : state_t;
|
||||||
done : std_ulogic;
|
done : std_ulogic;
|
||||||
err : std_ulogic;
|
err : std_ulogic;
|
||||||
|
prtbl : std_ulogic_vector(63 downto 0);
|
||||||
|
ptb_valid : std_ulogic;
|
||||||
pgtbl0 : std_ulogic_vector(63 downto 0);
|
pgtbl0 : std_ulogic_vector(63 downto 0);
|
||||||
pt0_valid : std_ulogic;
|
pt0_valid : std_ulogic;
|
||||||
pgtbl3 : std_ulogic_vector(63 downto 0);
|
pgtbl3 : std_ulogic_vector(63 downto 0);
|
||||||
@ -77,7 +82,7 @@ architecture behave of mmu is
|
|||||||
begin
|
begin
|
||||||
-- Multiplex internal SPR values back to loadstore1, selected
|
-- Multiplex internal SPR values back to loadstore1, selected
|
||||||
-- by l_in.sprn.
|
-- 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)
|
mmu_0: process(clk)
|
||||||
begin
|
begin
|
||||||
@ -85,9 +90,10 @@ begin
|
|||||||
if rst = '1' then
|
if rst = '1' then
|
||||||
r.state <= IDLE;
|
r.state <= IDLE;
|
||||||
r.valid <= '0';
|
r.valid <= '0';
|
||||||
|
r.ptb_valid <= '0';
|
||||||
r.pt0_valid <= '0';
|
r.pt0_valid <= '0';
|
||||||
r.pt3_valid <= '0';
|
r.pt3_valid <= '0';
|
||||||
r.prtbl <= (others => '0');
|
r.ptcr <= (others => '0');
|
||||||
r.pid <= (others => '0');
|
r.pid <= (others => '0');
|
||||||
else
|
else
|
||||||
if rin.valid = '1' then
|
if rin.valid = '1' then
|
||||||
@ -185,6 +191,7 @@ begin
|
|||||||
variable tlb_load : std_ulogic;
|
variable tlb_load : std_ulogic;
|
||||||
variable itlb_load : std_ulogic;
|
variable itlb_load : std_ulogic;
|
||||||
variable tlbie_req : std_ulogic;
|
variable tlbie_req : std_ulogic;
|
||||||
|
variable ptbl_rd : std_ulogic;
|
||||||
variable prtbl_rd : std_ulogic;
|
variable prtbl_rd : std_ulogic;
|
||||||
variable pt_valid : std_ulogic;
|
variable pt_valid : std_ulogic;
|
||||||
variable effpid : std_ulogic_vector(31 downto 0);
|
variable effpid : std_ulogic_vector(31 downto 0);
|
||||||
@ -215,6 +222,7 @@ begin
|
|||||||
itlb_load := '0';
|
itlb_load := '0';
|
||||||
tlbie_req := '0';
|
tlbie_req := '0';
|
||||||
v.inval_all := '0';
|
v.inval_all := '0';
|
||||||
|
ptbl_rd := '0';
|
||||||
prtbl_rd := '0';
|
prtbl_rd := '0';
|
||||||
|
|
||||||
-- Radix tree data structures in memory are big-endian,
|
-- Radix tree data structures in memory are big-endian,
|
||||||
@ -256,11 +264,15 @@ begin
|
|||||||
if l_in.sprn(3) = '1' then
|
if l_in.sprn(3) = '1' then
|
||||||
v.pt0_valid := '0';
|
v.pt0_valid := '0';
|
||||||
v.pt3_valid := '0';
|
v.pt3_valid := '0';
|
||||||
|
v.ptb_valid := '0';
|
||||||
end if;
|
end if;
|
||||||
v.state := DO_TLBIE;
|
v.state := DO_TLBIE;
|
||||||
else
|
else
|
||||||
v.valid := '1';
|
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
|
-- need to fetch process table entry
|
||||||
-- set v.shift so we can use finalmask for generating
|
-- set v.shift so we can use finalmask for generating
|
||||||
-- the process table entry address
|
-- the process table entry address
|
||||||
@ -277,13 +289,14 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
if l_in.mtspr = '1' then
|
if l_in.mtspr = '1' then
|
||||||
-- Move to PID needs to invalidate L1 TLBs and cached
|
-- Move to PID needs to invalidate L1 TLBs and cached
|
||||||
-- pgtbl0 value. Move to PRTBL does that plus
|
-- pgtbl0 value. Move to PTCR does that plus
|
||||||
-- invalidating the cached pgtbl3 value as well.
|
-- invalidating the cached pgtbl3 and prtbl values as well.
|
||||||
if l_in.sprn(9) = '0' then
|
if l_in.sprn(8) = '0' then
|
||||||
v.pid := l_in.rs(31 downto 0);
|
v.pid := l_in.rs(31 downto 0);
|
||||||
else
|
else
|
||||||
v.prtbl := l_in.rs;
|
v.ptcr := l_in.rs;
|
||||||
v.pt3_valid := '0';
|
v.pt3_valid := '0';
|
||||||
|
v.ptb_valid := '0';
|
||||||
end if;
|
end if;
|
||||||
v.pt0_valid := '0';
|
v.pt0_valid := '0';
|
||||||
v.inval_all := '1';
|
v.inval_all := '1';
|
||||||
@ -300,6 +313,22 @@ begin
|
|||||||
v.state := RADIX_FINISH;
|
v.state := RADIX_FINISH;
|
||||||
end if;
|
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 =>
|
when PROC_TBL_READ =>
|
||||||
dcreq := '1';
|
dcreq := '1';
|
||||||
prtbl_rd := '1';
|
prtbl_rd := '1';
|
||||||
@ -449,6 +478,9 @@ begin
|
|||||||
elsif tlb_load = '1' then
|
elsif tlb_load = '1' then
|
||||||
addr := r.addr(63 downto 12) & x"000";
|
addr := r.addr(63 downto 12) & x"000";
|
||||||
tlb_data := pte;
|
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
|
elsif prtbl_rd = '1' then
|
||||||
addr := prtable_addr;
|
addr := prtable_addr;
|
||||||
tlb_data := (others => '0');
|
tlb_data := (others => '0');
|
||||||
|
|||||||
@ -24,7 +24,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
|||||||
#define SRR0 26
|
#define SRR0 26
|
||||||
#define SRR1 27
|
#define SRR1 27
|
||||||
#define PID 48
|
#define PID 48
|
||||||
#define PRTBL 720
|
#define PTCR 464
|
||||||
|
|
||||||
static inline unsigned long mfspr(int sprnum)
|
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 *pgdir = (unsigned long *) 0x10000;
|
||||||
unsigned long *proc_tbl = (unsigned long *) 0x12000;
|
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];
|
void *eas_mapped[4];
|
||||||
int neas_mapped;
|
int neas_mapped;
|
||||||
|
|
||||||
void init_mmu(void)
|
void init_mmu(void)
|
||||||
{
|
{
|
||||||
|
/* set up partition table */
|
||||||
|
store_pte(&part_tbl[1], (unsigned long)proc_tbl);
|
||||||
/* set up process table */
|
/* set up process table */
|
||||||
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
||||||
mtspr(PRTBL, (unsigned long)proc_tbl);
|
mtspr(PTCR, (unsigned long)part_tbl);
|
||||||
mtspr(PID, 1);
|
mtspr(PID, 1);
|
||||||
zero_memory(pgdir, 1024 * sizeof(unsigned long));
|
zero_memory(pgdir, 1024 * sizeof(unsigned long));
|
||||||
/* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
|
/* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
|
||||||
|
|||||||
@ -33,7 +33,7 @@ static inline void do_tlbie(unsigned long rb, unsigned long rs)
|
|||||||
#define SPRG0 272
|
#define SPRG0 272
|
||||||
#define SPRG1 273
|
#define SPRG1 273
|
||||||
#define SPRG3 275
|
#define SPRG3 275
|
||||||
#define PRTBL 720
|
#define PTCR 464
|
||||||
|
|
||||||
static inline unsigned long mfspr(int sprnum)
|
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.
|
* 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.
|
* We use 3 levels, mapping 512GB, with 4kB PGD/PMD/PTE pages.
|
||||||
*/
|
*/
|
||||||
unsigned long *proc_tbl = (unsigned long *) 0x10000;
|
unsigned long *part_tbl = (unsigned long *) 0x10000;
|
||||||
unsigned long *pgdir = (unsigned long *) 0x11000;
|
unsigned long *proc_tbl = (unsigned long *) 0x11000;
|
||||||
unsigned long free_ptr = 0x12000;
|
unsigned long *pgdir = (unsigned long *) 0x12000;
|
||||||
|
unsigned long free_ptr = 0x13000;
|
||||||
|
|
||||||
void init_mmu(void)
|
void init_mmu(void)
|
||||||
{
|
{
|
||||||
|
/* set up partition table */
|
||||||
|
store_pte(&part_tbl[1], (unsigned long)proc_tbl);
|
||||||
/* set up process table */
|
/* set up process table */
|
||||||
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
||||||
mtspr(PRTBL, (unsigned long)proc_tbl);
|
mtspr(PTCR, (unsigned long)part_tbl);
|
||||||
mtspr(PID, 1);
|
mtspr(PID, 1);
|
||||||
zero_memory(pgdir, 512 * sizeof(unsigned long));
|
zero_memory(pgdir, 512 * sizeof(unsigned long));
|
||||||
/* RTS = 8 (512GB address space), RPDS = 9 (512-entry top level) */
|
/* RTS = 8 (512GB address space), RPDS = 9 (512-entry top level) */
|
||||||
|
|||||||
@ -14,7 +14,7 @@ extern int call_with_msr(unsigned long arg, int (*fn)(unsigned long), unsigned l
|
|||||||
#define SRR0 26
|
#define SRR0 26
|
||||||
#define SRR1 27
|
#define SRR1 27
|
||||||
#define PID 48
|
#define PID 48
|
||||||
#define PRTBL 720
|
#define PTCR 464
|
||||||
#define PVR 287
|
#define PVR 287
|
||||||
|
|
||||||
static inline unsigned long mfspr(int sprnum)
|
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 *pgdir = (unsigned long *) 0x10000;
|
||||||
unsigned long *proc_tbl = (unsigned long *) 0x12000;
|
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)
|
void init_mmu(void)
|
||||||
{
|
{
|
||||||
|
/* set up partition table */
|
||||||
|
store_pte(&part_tbl[1], (unsigned long)proc_tbl);
|
||||||
/* set up process table */
|
/* set up process table */
|
||||||
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
zero_memory(proc_tbl, 512 * sizeof(unsigned long));
|
||||||
/* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
|
/* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
|
||||||
store_pte(&proc_tbl[2 * 1], (unsigned long) pgdir | 10);
|
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);
|
mtspr(PID, 1);
|
||||||
zero_memory(pgdir, 1024 * sizeof(unsigned long));
|
zero_memory(pgdir, 1024 * sizeof(unsigned long));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,6 @@ extern unsigned long do_stqcx(unsigned long dst, unsigned long regs);
|
|||||||
#define PID 48
|
#define PID 48
|
||||||
#define SPRG0 272
|
#define SPRG0 272
|
||||||
#define SPRG1 273
|
#define SPRG1 273
|
||||||
#define PRTBL 720
|
|
||||||
|
|
||||||
static inline unsigned long mfspr(int sprnum)
|
static inline unsigned long mfspr(int sprnum)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -38,7 +38,7 @@ void print_test(char *str)
|
|||||||
#define SPR_HSPRG0 304
|
#define SPR_HSPRG0 304
|
||||||
#define SPR_HSPRG1 305
|
#define SPR_HSPRG1 305
|
||||||
#define SPR_PID 48
|
#define SPR_PID 48
|
||||||
#define SPR_PRTBL 720
|
#define SPR_PTCR 464
|
||||||
#define SPR_PVR 287
|
#define SPR_PVR 287
|
||||||
|
|
||||||
#define __stringify_1(x...) #x
|
#define __stringify_1(x...) #x
|
||||||
@ -83,7 +83,7 @@ int main(void)
|
|||||||
DO_ONE(SPR_HSPRG0);
|
DO_ONE(SPR_HSPRG0);
|
||||||
DO_ONE(SPR_HSPRG1);
|
DO_ONE(SPR_HSPRG1);
|
||||||
DO_ONE(SPR_PID);
|
DO_ONE(SPR_PID);
|
||||||
DO_ONE(SPR_PRTBL);
|
DO_ONE(SPR_PTCR);
|
||||||
DO_ONE(SPR_PVR);
|
DO_ONE(SPR_PVR);
|
||||||
|
|
||||||
puts(PASS);
|
puts(PASS);
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -20,6 +20,6 @@ Test SPR_SPRG3U:PASS
|
|||||||
Test SPR_HSPRG0:PASS
|
Test SPR_HSPRG0:PASS
|
||||||
Test SPR_HSPRG1:PASS
|
Test SPR_HSPRG1:PASS
|
||||||
Test SPR_PID:PASS
|
Test SPR_PID:PASS
|
||||||
Test SPR_PRTBL:PASS
|
Test SPR_PTCR:PASS
|
||||||
Test SPR_PVR:PASS
|
Test SPR_PVR:PASS
|
||||||
PASS
|
PASS
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user