diff options
| author | Alejandro Soto <alejandro@34project.org> | 2022-12-11 17:28:03 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2022-12-16 16:29:09 -0600 |
| commit | d006be2e89aa493237f212811ee880ed8b54241b (patch) | |
| tree | b8b9c25536c6f3b42920d3f9666610396e8f2404 /rtl/core/mmu | |
| parent | ff71bcd0c5425c168f111b8f4a92d0a90a6c9c31 (diff) | |
Implement MMU access checks
Diffstat (limited to '')
| -rw-r--r-- | rtl/core/mmu/fault.sv | 59 | ||||
| -rw-r--r-- | rtl/core/mmu/format.sv | 34 | ||||
| -rw-r--r-- | rtl/core/mmu/mmu.sv | 68 | ||||
| -rw-r--r-- | rtl/core/mmu/pagewalk.sv | 161 |
4 files changed, 249 insertions, 73 deletions
diff --git a/rtl/core/mmu/fault.sv b/rtl/core/mmu/fault.sv new file mode 100644 index 0000000..e922284 --- /dev/null +++ b/rtl/core/mmu/fault.sv @@ -0,0 +1,59 @@ +`include "core/mmu/format.sv" +`include "core/uarch.sv" + +module core_mmu_fault +( + input logic valid_entry, + skip_perms, + input word mmu_dac, + input mmu_domain domain, + input logic[1:0] ap, + + output logic fault, + output mmu_fault_type fault_type +); + + mmu_domain_ctrl domain_ctrl; + + always_comb begin + unique case(domain) + 4'h0: domain_ctrl = mmu_dac[1:0]; + 4'h1: domain_ctrl = mmu_dac[3:2]; + 4'h2: domain_ctrl = mmu_dac[5:4]; + 4'h3: domain_ctrl = mmu_dac[7:6]; + 4'h4: domain_ctrl = mmu_dac[9:8]; + 4'h5: domain_ctrl = mmu_dac[11:10]; + 4'h6: domain_ctrl = mmu_dac[13:12]; + 4'h7: domain_ctrl = mmu_dac[15:14]; + 4'h8: domain_ctrl = mmu_dac[17:16]; + 4'h9: domain_ctrl = mmu_dac[19:18]; + 4'ha: domain_ctrl = mmu_dac[21:20]; + 4'hb: domain_ctrl = mmu_dac[23:22]; + 4'hc: domain_ctrl = mmu_dac[25:24]; + 4'hd: domain_ctrl = mmu_dac[27:26]; + 4'he: domain_ctrl = mmu_dac[29:28]; + 4'hf: domain_ctrl = mmu_dac[31:30]; + endcase + + fault = 0; + fault_type = `MMU_FAULT_ACCESS; + + if(!valid_entry) begin + fault = 1; + fault_type = `MMU_FAULT_WALK; + end else if(!skip_perms) begin + if(!domain_ctrl.allowed) begin + fault = 1; + fault_type = `MMU_FAULT_DOMAIN; + end else if(!domain_ctrl.manager) + unique case(ap) + 2'b00: + fault = 1; + + //TODO: los demás solo se tienen efecto para unprivileged + default: ; + endcase + end + end + +endmodule diff --git a/rtl/core/mmu/format.sv b/rtl/core/mmu/format.sv index 83ca3eb..3029b83 100644 --- a/rtl/core/mmu/format.sv +++ b/rtl/core/mmu/format.sv @@ -2,6 +2,7 @@ `define CORE_MMU_FORMAT_SV typedef logic[17:0] mmu_base; +typedef logic[3:0] mmu_domain; `define MMU_L1_INDEX [29:18] `define MMU_L1_FAULT 2'b00 @@ -10,6 +11,16 @@ typedef logic[17:0] mmu_base; typedef struct packed { + logic[31:10] field10; + logic[9:9] imp; + logic[8:5] domain; + logic[4:4] sbz; + logic[3:2] field2; + logic[1:0] typ; +} mmu_l1_entry; + +typedef struct packed +{ logic[31:10] base; logic[9:9] imp; logic[8:5] domain; @@ -65,9 +76,30 @@ typedef struct packed logic[1:0] typ; } mmu_l2_small; -//TODO: struct mmu_l2_smallext +typedef struct packed +{ + logic[31:12] base; + logic[11:9] sbz; + logic[8:6] tex; + logic[5:4] ap; + logic[3:3] c; + logic[2:2] b; + logic[1:0] typ; +} mmu_l2_smallext; `define MMU_LARGE_INDEX [13:0] `define MMU_SMALL_INDEX [9:0] +typedef logic[1:0] mmu_fault_type; + +`define MMU_FAULT_WALK 2'b01 +`define MMU_FAULT_DOMAIN 2'b10 +`define MMU_FAULT_ACCESS 2'b11 + +typedef struct packed +{ + logic manager, + allowed; +} mmu_domain_ctrl; + `endif diff --git a/rtl/core/mmu/mmu.sv b/rtl/core/mmu/mmu.sv index 91986db..17f1e98 100644 --- a/rtl/core/mmu/mmu.sv +++ b/rtl/core/mmu/mmu.sv @@ -3,35 +3,39 @@ module core_mmu ( - input logic clk, - rst_n, - - input logic mmu_enable /*verilator public*/, - input mmu_base mmu_ttbr /*verilator public*/, - - input logic bus_ready, - input word bus_data_rd, - data_data_wr, - input ptr insn_addr, - data_addr, - input logic insn_start, - data_start, - data_write, - input logic[3:0] data_data_be, - - output word bus_data_wr, - output logic[3:0] bus_data_be, - output ptr bus_addr, - output logic bus_start, - bus_write, - insn_ready, - data_ready, - data_fault, - output word insn_data_rd, - data_data_rd, - - output logic fault_register, - output ptr fault_addr + input logic clk, + rst_n, + + input logic mmu_enable /*verilator public*/, + input mmu_base mmu_ttbr /*verilator public*/, + input word mmu_dac, + + input logic bus_ready, + input word bus_data_rd, + data_data_wr, + input ptr insn_addr, + data_addr, + input logic insn_start, + data_start, + data_write, + input logic[3:0] data_data_be, + + output word bus_data_wr, + output logic[3:0] bus_data_be, + output ptr bus_addr, + output logic bus_start, + bus_write, + insn_ready, + data_ready, + data_fault, + output word insn_data_rd, + data_data_rd, + + output logic fault_register, + fault_page, + output ptr fault_addr, + output mmu_fault_type fault_type, + output mmu_domain fault_domain ); ptr iphys_addr, dphys_addr; @@ -52,6 +56,9 @@ module core_mmu .core_data_be(0), .core_data_rd(insn_data_rd), .core_fault_addr(), + .core_fault_page(), + .core_fault_type(), + .core_fault_domain(), .bus_addr(iphys_addr), .bus_start(iphys_start), @@ -75,6 +82,9 @@ module core_mmu .core_data_be(data_data_be), .core_data_rd(data_data_rd), .core_fault_addr(fault_addr), + .core_fault_page(fault_page), + .core_fault_type(fault_type), + .core_fault_domain(fault_domain), .bus_addr(dphys_addr), .bus_start(dphys_start), diff --git a/rtl/core/mmu/pagewalk.sv b/rtl/core/mmu/pagewalk.sv index be4aa8b..c6d51c0 100644 --- a/rtl/core/mmu/pagewalk.sv +++ b/rtl/core/mmu/pagewalk.sv @@ -3,31 +3,35 @@ module core_mmu_pagewalk ( - input logic clk, - rst_n, - - input logic mmu_enable, - input mmu_base mmu_ttbr, - - input logic bus_ready, - input word bus_data_rd, - - input ptr core_addr, - input word core_data_wr, - input logic[3:0] core_data_be, - input logic core_start, - core_write, - - output ptr bus_addr, - output word bus_data_wr, - output logic[3:0] bus_data_be, - output logic bus_start, - bus_write, - - output logic core_ready, - core_fault, - output word core_data_rd, - output ptr core_fault_addr + input logic clk, + rst_n, + + input logic mmu_enable, + input mmu_base mmu_ttbr, + input word mmu_dac, + + input logic bus_ready, + input word bus_data_rd, + + input ptr core_addr, + input word core_data_wr, + input logic[3:0] core_data_be, + input logic core_start, + core_write, + + output ptr bus_addr, + output word bus_data_wr, + output logic[3:0] bus_data_be, + output logic bus_start, + bus_write, + + output word core_data_rd, + output logic core_ready, + core_fault, + core_fault_page, + output ptr core_fault_addr, + output mmu_fault_type core_fault_type, + output mmu_domain core_fault_domain ); enum int unsigned @@ -39,6 +43,25 @@ module core_mmu_pagewalk FAULT } state; + logic access_fault, valid_entry, skip_perms; + logic[1:0] ap, entry_type; + mmu_domain domain, entry_domain; + mmu_fault_type access_fault_type; + + assign entry_type = bus_data_rd[1:0]; + assign core_fault_domain = domain; + + core_mmu_fault access_check + ( + .fault(access_fault), + .domain(entry_domain), + .fault_type(access_fault_type), + .* + ); + + mmu_l1_entry l1; + assign l1 = bus_data_rd; + mmu_l1_pagetable pagetable; assign pagetable = bus_data_rd; @@ -51,16 +74,64 @@ module core_mmu_pagewalk mmu_l2_small ptentry_small; assign ptentry_small = bus_data_rd; + mmu_l2_smallext ptentry_smallext; + assign ptentry_smallext = bus_data_rd; + ptr target; word hold_data; + logic hold_write; logic[3:0] hold_be; - logic hold_write; + always_comb begin + ap = 2'bxx; + skip_perms = 0; + valid_entry = 1; + entry_domain = domain; + + unique case(state) + L1: + unique case(entry_type) + `MMU_L1_PAGETABLE: begin + ap = 2'bxx; + skip_perms = 1; + end + + `MMU_L1_SECTION: begin + ap = section.ap; + entry_domain = l1.domain; + end + + // Tiny (1KiB wtf?) pages and supersections not supported + default: + valid_entry = 0; + endcase + + L2: + unique case(entry_type) + `MMU_L2_FAULT: + valid_entry = 0; + + `MMU_L2_LARGE: + //TODO: ap3-ap2 (también en L2_SMALL) + ap = ptentry_large.ap0; + + `MMU_L2_SMALL: + ap = ptentry_small.ap0; + + `MMU_L2_SMALLEXT: + ap = ptentry_smallext.ap; + endcase + + default: + valid_entry = 1'bx; + endcase + end always @(posedge clk or negedge rst_n) if(!rst_n) begin state <= IDLE; target <= 0; + domain <= 0; hold_be <= 0; hold_data <= 0; @@ -75,7 +146,9 @@ module core_mmu_pagewalk core_ready <= 0; core_fault <= 0; core_data_rd <= 0; + core_fault_page <= 0; core_fault_addr <= 0; + core_fault_type <= 0; end else begin if(bus_start) bus_start <= 0; @@ -109,28 +182,26 @@ module core_mmu_pagewalk end L1: - if(bus_ready) - unique case(bus_data_rd[1:0]) + if(bus_ready) begin + domain <= l1.domain; + + unique case(entry_type) `MMU_L1_PAGETABLE: begin state <= L2; bus_addr <= {pagetable.base, target `MMU_L2_INDEX}; - bus_start <= 1; end `MMU_L1_SECTION: begin state <= DATA; - bus_addr <= {section.base, target `MMU_SECTION_INDEX}; - bus_start <= 1; bus_write <= hold_write; bus_data_wr <= hold_data; bus_data_be <= hold_be; end - // Tiny (1KiB wtf?) pages and supersections not supported - default: - state <= FAULT; + default: ; endcase + end L2: if(bus_ready) begin @@ -140,19 +211,14 @@ module core_mmu_pagewalk bus_data_wr <= hold_data; bus_data_be <= hold_be; - unique case(bus_data_rd[1:0]) - `MMU_L2_FAULT: - state <= FAULT; + unique case(entry_type) + `MMU_L2_FAULT: ; - `MMU_L2_LARGE: begin + `MMU_L2_LARGE: bus_addr <= {ptentry_large.base, target `MMU_LARGE_INDEX}; - bus_start <= 1; - end - `MMU_L2_SMALL, `MMU_L2_SMALLEXT: begin + `MMU_L2_SMALL, `MMU_L2_SMALLEXT: bus_addr <= {ptentry_small.base, target `MMU_SMALL_INDEX}; - bus_start <= 1; - end endcase end @@ -171,6 +237,15 @@ module core_mmu_pagewalk core_fault_addr <= target; end endcase + + if((state == L1 || state == L2) && bus_ready) begin + if(access_fault) begin + state <= FAULT; + core_fault_type <= access_fault_type; + core_fault_page <= state == L2; + end else + bus_start <= 1; + end end endmodule |
