Implement hrfid and make MSR[HV] always 1

Implementations without hypervisor/LPAR support are permitted by the
architecture, but should have MSR[HV] forced to be 1 at all times, not
0, and should implement various instructions and registers that are
only accessible in hypervisor mode.

This commit implements MSR[HV] as a constant 1 bit and adds the hrfid
instruction, which behaves exactly the same as rfid except that it
reads HSRR0/1 instead of SRR0/1.  We already have HSRR0/1 and HSPRG0/1
implemented.

When HV=1, Linux expects external interrupts to arrive as hypervisor
interrupts, so this adds support for hypervisor interrupts (i.e.,
those that set HSRR0/1) and makes the external interrupt be a
hypervisor interrupt.  (If we had an LPCR register, the LPES bit would
control this, but we don't.)  The xics test is updated to read HSRR0/1
after an external interrupt.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
pull/434/head
Paul Mackerras 1 year ago
parent 6ef9395f10
commit 12a3d76217

@ -12,6 +12,7 @@ package common is


-- MSR bit numbers -- MSR bit numbers
constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode
constant MSR_HV : integer := (63 - 3); -- Hypervisor mode (always 1)
constant MSR_EE : integer := (63 - 48); -- External interrupt Enable constant MSR_EE : integer := (63 - 48); -- External interrupt Enable
constant MSR_PR : integer := (63 - 49); -- PRoblem state constant MSR_PR : integer := (63 - 49); -- PRoblem state
constant MSR_FP : integer := (63 - 50); -- Floating Point available constant MSR_FP : integer := (63 - 50); -- Floating Point available
@ -662,6 +663,7 @@ package common is
write_xerc_enable : std_ulogic; write_xerc_enable : std_ulogic;
xerc : xer_common_t; xerc : xer_common_t;
interrupt : std_ulogic; interrupt : std_ulogic;
hv_intr : std_ulogic;
intr_vec : intr_vector_t; intr_vec : intr_vector_t;
redirect: std_ulogic; redirect: std_ulogic;
redir_mode: std_ulogic_vector(3 downto 0); redir_mode: std_ulogic_vector(3 downto 0);
@ -678,7 +680,8 @@ package common is
write_xerc_enable => '0', xerc => xerc_init, write_xerc_enable => '0', xerc => xerc_init,
write_data => (others => '0'), write_cr_mask => (others => '0'), write_data => (others => '0'), write_cr_mask => (others => '0'),
write_cr_data => (others => '0'), write_reg => (others => '0'), write_cr_data => (others => '0'), write_reg => (others => '0'),
interrupt => '0', intr_vec => 0, redirect => '0', redir_mode => "0000", interrupt => '0', hv_intr => '0', intr_vec => 0,
redirect => '0', redir_mode => "0000",
last_nia => (others => '0'), last_nia => (others => '0'),
br_last => '0', br_taken => '0', abs_br => '0', br_last => '0', br_taken => '0', abs_br => '0',
srr1 => (others => '0'), msr => (others => '0')); srr1 => (others => '0'), msr => (others => '0'));
@ -795,8 +798,9 @@ package common is
write_cr_data => (others => '0')); write_cr_data => (others => '0'));


type WritebackToExecute1Type is record type WritebackToExecute1Type is record
intr : std_ulogic; intr : std_ulogic;
srr1 : std_ulogic_vector(15 downto 0); hv_intr : std_ulogic;
srr1 : std_ulogic_vector(15 downto 0);
end record; end record;


type WritebackEventType is record type WritebackEventType is record

@ -539,8 +539,15 @@ begin
v.e.ramspr_write_odd := d_in.ram_spr.valid and d_in.ram_spr.isodd; v.e.ramspr_write_odd := d_in.ram_spr.valid and d_in.ram_spr.isodd;
v.e.spr_is_ram := d_in.ram_spr.valid; v.e.spr_is_ram := d_in.ram_spr.valid;
when OP_RFID => when OP_RFID =>
v.e.ramspr_even_rdaddr := RAMSPR_SRR0; if d_in.insn(9) = '0' then
v.e.ramspr_odd_rdaddr := RAMSPR_SRR1; -- rfid
v.e.ramspr_even_rdaddr := RAMSPR_SRR0;
v.e.ramspr_odd_rdaddr := RAMSPR_SRR1;
else
-- hrfid
v.e.ramspr_even_rdaddr := RAMSPR_HSRR0;
v.e.ramspr_odd_rdaddr := RAMSPR_HSRR1;
end if;
sprs_busy := '1'; sprs_busy := '1';
when others => when others =>
end case; end case;

@ -322,6 +322,7 @@ architecture behaviour of execute1 is
-- 48:63, and partial function MSR bits lie in the range -- 48:63, and partial function MSR bits lie in the range
-- 33:36 and 42:47. (Note this is IBM bit numbering). -- 33:36 and 42:47. (Note this is IBM bit numbering).
msr_out := (others => '0'); msr_out := (others => '0');
msr_out(MSR_HV) := '1'; -- HV is always set
msr_out(63 downto 31) := msr(63 downto 31); msr_out(63 downto 31) := msr(63 downto 31);
msr_out(26 downto 22) := msr(26 downto 22); msr_out(26 downto 22) := msr(26 downto 22);
msr_out(15 downto 0) := msr(15 downto 0); msr_out(15 downto 0) := msr(15 downto 0);
@ -332,6 +333,9 @@ architecture behaviour of execute1 is
return std_ulogic_vector is return std_ulogic_vector is
variable srr1: std_ulogic_vector(63 downto 0); variable srr1: std_ulogic_vector(63 downto 0);
begin begin
srr1(63 downto 61) := msr(63 downto 61);
srr1(MSR_HV) := '1';
srr1(59 downto 31) := msr(59 downto 31);
srr1(63 downto 31) := msr(63 downto 31); srr1(63 downto 31) := msr(63 downto 31);
srr1(30 downto 27) := flags(14 downto 11); srr1(30 downto 27) := flags(14 downto 11);
srr1(26 downto 22) := msr(26 downto 22); srr1(26 downto 22) := msr(26 downto 22);
@ -533,7 +537,11 @@ begin
even_wr_enab := (ex1.se.ramspr_write_even and doit) or interrupt_in.intr; even_wr_enab := (ex1.se.ramspr_write_even and doit) or interrupt_in.intr;
odd_wr_enab := (ex1.se.ramspr_write_odd and doit) or interrupt_in.intr; odd_wr_enab := (ex1.se.ramspr_write_odd and doit) or interrupt_in.intr;
if interrupt_in.intr = '1' then if interrupt_in.intr = '1' then
wr_addr := RAMSPR_SRR0; if interrupt_in.hv_intr = '0' then
wr_addr := RAMSPR_SRR0;
else
wr_addr := RAMSPR_HSRR0;
end if;
else else
wr_addr := ex1.ramspr_wraddr; wr_addr := ex1.ramspr_wraddr;
end if; end if;
@ -610,8 +618,8 @@ begin
ex1 <= reg_stage1_type_init; ex1 <= reg_stage1_type_init;
ex2 <= reg_stage2_type_init; ex2 <= reg_stage2_type_init;
ctrl <= ctrl_t_init; ctrl <= ctrl_t_init;
ctrl.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0'); ctrl.msr <= (MSR_SF => '1', MSR_HV => '1', MSR_LE => '1', others => '0');
ex1.msr <= (MSR_SF => '1', MSR_LE => '1', others => '0'); ex1.msr <= (MSR_SF => '1', MSR_HV => '1', MSR_LE => '1', others => '0');
else else
ex1 <= ex1in; ex1 <= ex1in;
ex2 <= ex2in; ex2 <= ex2in;
@ -1166,7 +1174,9 @@ begin
not srr1(MSR_LE) & not srr1(MSR_SF); not srr1(MSR_LE) & not srr1(MSR_SF);
-- Can't use msr_copy here because the partial function MSR -- Can't use msr_copy here because the partial function MSR
-- bits should be left unchanged, not zeroed. -- bits should be left unchanged, not zeroed.
v.new_msr(63 downto 31) := srr1(63 downto 31); v.new_msr(63 downto 61) := srr1(63 downto 61);
v.new_msr(MSR_HV) := '1';
v.new_msr(59 downto 31) := srr1(59 downto 31);
v.new_msr(26 downto 22) := srr1(26 downto 22); v.new_msr(26 downto 22) := srr1(26 downto 22);
v.new_msr(15 downto 0) := srr1(15 downto 0); v.new_msr(15 downto 0) := srr1(15 downto 0);
if srr1(MSR_PR) = '1' then if srr1(MSR_PR) = '1' then
@ -1474,6 +1484,7 @@ begin
v.e.intr_vec := 16#500#; v.e.intr_vec := 16#500#;
report "IRQ valid: External"; report "IRQ valid: External";
v.ext_interrupt := '1'; v.ext_interrupt := '1';
v.e.hv_intr := '1';
end if; end if;
v.e.srr1 := (others => '0'); v.e.srr1 := (others => '0');
exception := '1'; exception := '1';

@ -447,6 +447,7 @@ architecture behaviour of predecoder is
2#1_00100_11110# => INSN_isync, 2#1_00100_11110# => INSN_isync,
2#1_00000_10000# => INSN_mcrf, 2#1_00000_10000# => INSN_mcrf,
2#1_00000_11010# => INSN_rfid, 2#1_00000_11010# => INSN_rfid,
2#1_01000_11010# => INSN_rfid, -- hrfid


-- Major opcode 59 -- Major opcode 59
-- Address bits are 1, insn(10..6), 1, 0, insn(3..1) -- Address bits are 1, insn(10..6), 1, 0, insn(3..1)

@ -7,6 +7,7 @@
#define MSR_LE 0x1 #define MSR_LE 0x1
#define MSR_DR 0x10 #define MSR_DR 0x10
#define MSR_IR 0x20 #define MSR_IR 0x20
#define MSR_HV 0x1000000000000000ul
#define MSR_SF 0x8000000000000000ul #define MSR_SF 0x8000000000000000ul


extern int test_read(long *addr, long *ret, long init); extern int test_read(long *addr, long *ret, long init);
@ -450,11 +451,11 @@ int mmu_test_11(void)
unsigned long ptr = 0x523000; unsigned long ptr = 0x523000;


/* this should fail */ /* this should fail */
if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != (long) ptr || if (mfspr(SRR0) != (long) ptr ||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
return 2; return 2;
return 0; return 0;
} }
@ -468,12 +469,12 @@ int mmu_test_12(void)
/* create PTE */ /* create PTE */
map((void *)ptr, (void *)mem, PERM_EX | REF); map((void *)ptr, (void *)mem, PERM_EX | REF);
/* this should succeed and be a cache miss */ /* this should succeed and be a cache miss */
if (!test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) if (!test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* create a second PTE */ /* create a second PTE */
map((void *)ptr2, (void *)mem, PERM_EX | REF); map((void *)ptr2, (void *)mem, PERM_EX | REF);
/* this should succeed and be a cache hit */ /* this should succeed and be a cache hit */
if (!test_exec(0, ptr2, MSR_SF | MSR_IR | MSR_LE)) if (!test_exec(0, ptr2, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 2; return 2;
return 0; return 0;
} }
@ -487,18 +488,18 @@ int mmu_test_13(void)
/* create a PTE */ /* create a PTE */
map((void *)ptr, (void *)mem, PERM_EX | REF); map((void *)ptr, (void *)mem, PERM_EX | REF);
/* this should succeed */ /* this should succeed */
if (!test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE)) if (!test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* invalidate the PTE */ /* invalidate the PTE */
unmap((void *)ptr); unmap((void *)ptr);
/* install a second PTE */ /* install a second PTE */
map((void *)ptr2, (void *)mem, PERM_EX | REF); map((void *)ptr2, (void *)mem, PERM_EX | REF);
/* this should fail */ /* this should fail */
if (test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(1, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 2; return 2;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != (long) ptr || if (mfspr(SRR0) != (long) ptr ||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
return 3; return 3;
return 0; return 0;
} }
@ -513,16 +514,16 @@ int mmu_test_14(void)
/* create a PTE */ /* create a PTE */
map((void *)ptr, (void *)mem, PERM_EX | REF); map((void *)ptr, (void *)mem, PERM_EX | REF);
/* this should fail due to second page not being mapped */ /* this should fail due to second page not being mapped */
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != ptr2 || if (mfspr(SRR0) != ptr2 ||
mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x40000000 | MSR_IR | MSR_LE))
return 2; return 2;
/* create a PTE for the second page */ /* create a PTE for the second page */
map((void *)ptr2, (void *)mem2, PERM_EX | REF); map((void *)ptr2, (void *)mem2, PERM_EX | REF);
/* this should succeed */ /* this should succeed */
if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 3; return 3;
return 0; return 0;
} }
@ -535,11 +536,11 @@ int mmu_test_15(void)
/* create a PTE without execute permission */ /* create a PTE without execute permission */
map((void *)ptr, (void *)mem, DFLT_PERM); map((void *)ptr, (void *)mem, DFLT_PERM);
/* this should fail */ /* this should fail */
if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(0, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != ptr || if (mfspr(SRR0) != ptr ||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
return 2; return 2;
return 0; return 0;
} }
@ -556,16 +557,16 @@ int mmu_test_16(void)
/* create a PTE for the second page without execute permission */ /* create a PTE for the second page without execute permission */
map((void *)ptr2, (void *)mem2, PERM_RD | REF); map((void *)ptr2, (void *)mem2, PERM_RD | REF);
/* this should fail due to second page being no-execute */ /* this should fail due to second page being no-execute */
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != ptr2 || if (mfspr(SRR0) != ptr2 ||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
return 2; return 2;
/* create a PTE for the second page with execute permission */ /* create a PTE for the second page with execute permission */
map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF); map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF);
/* this should succeed */ /* this should succeed */
if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (!test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 3; return 3;
return 0; return 0;
} }
@ -578,22 +579,22 @@ int mmu_test_17(void)
/* create a PTE without the ref bit set */ /* create a PTE without the ref bit set */
map((void *)ptr, (void *)mem, PERM_EX); map((void *)ptr, (void *)mem, PERM_EX);
/* this should fail */ /* this should fail */
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
if (mfspr(SRR0) != (long) ptr || if (mfspr(SRR0) != (long) ptr ||
mfspr(SRR1) != (MSR_SF | 0x00040000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x00040000 | MSR_IR | MSR_LE))
return 2; return 2;
/* create a PTE without ref or execute permission */ /* create a PTE without ref or execute permission */
unmap((void *)ptr); unmap((void *)ptr);
map((void *)ptr, (void *)mem, 0); map((void *)ptr, (void *)mem, 0);
/* this should fail */ /* this should fail */
if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) if (test_exec(2, ptr, MSR_SF | MSR_HV | MSR_IR | MSR_LE))
return 1; return 1;
/* SRR0 and SRR1 should be set correctly */ /* SRR0 and SRR1 should be set correctly */
/* RC update fail bit should not be set */ /* RC update fail bit should not be set */
if (mfspr(SRR0) != (long) ptr || if (mfspr(SRR0) != (long) ptr ||
mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) mfspr(SRR1) != (MSR_SF | MSR_HV | 0x10000000 | MSR_IR | MSR_LE))
return 2; return 2;
return 0; return 0;
} }

@ -7,6 +7,7 @@
#define MSR_LE 0x1 #define MSR_LE 0x1
#define MSR_DR 0x10 #define MSR_DR 0x10
#define MSR_IR 0x20 #define MSR_IR 0x20
#define MSR_HV 0x1000000000000000ul
#define MSR_SF 0x8000000000000000ul #define MSR_SF 0x8000000000000000ul


#define DSISR 18 #define DSISR 18
@ -103,7 +104,7 @@ long int prefix_test_2(void)
return 1; return 1;
if (mfspr(SRR0) != (unsigned long)&test_paddi_mis + 8) if (mfspr(SRR0) != (unsigned long)&test_paddi_mis + 8)
return 2; return 2;
if (mfspr(SRR1) != (MSR_SF | MSR_LE | (1ul << (63 - 35)) | (1ul << (63 - 34)))) if (mfspr(SRR1) != (MSR_SF | MSR_HV | MSR_LE | (1ul << (63 - 35)) | (1ul << (63 - 34))))
return 3; return 3;


ret = trapit((long)&x, test_plfd); ret = trapit((long)&x, test_plfd);
@ -111,7 +112,7 @@ long int prefix_test_2(void)
return ret; return ret;
if (mfspr(SRR0) != (unsigned long)&test_plfd + 8) if (mfspr(SRR0) != (unsigned long)&test_plfd + 8)
return 6; return 6;
if (mfspr(SRR1) != (MSR_SF | MSR_LE | (1ul << (63 - 34)))) if (mfspr(SRR1) != (MSR_SF | MSR_HV | MSR_LE | (1ul << (63 - 34))))
return 7; return 7;
return 0; return 0;
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -115,7 +115,7 @@ __isr:
std %r29, 29*8(%r1) std %r29, 29*8(%r1)
std %r30, 30*8(%r1) std %r30, 30*8(%r1)
std %r31, 31*8(%r1) std %r31, 31*8(%r1)
mfsrr0 %r0 mfhsrr0 %r0
std %r0, SAVE_NIA*8(%r1) std %r0, SAVE_NIA*8(%r1)
mflr %r0 mflr %r0
std %r0, SAVE_LR*8(%r1) std %r0, SAVE_LR*8(%r1)
@ -123,7 +123,7 @@ __isr:
std %r0, SAVE_CTR*8(%r1) std %r0, SAVE_CTR*8(%r1)
mfcr %r0 mfcr %r0
std %r0, SAVE_CR*8(%r1) std %r0, SAVE_CR*8(%r1)
mfsrr1 %r0 mfhsrr1 %r0
std %r0, SAVE_SRR1*8(%r1) std %r0, SAVE_SRR1*8(%r1)


stdu %r1,-STACK_FRAME_C_MINIMAL(%r1) stdu %r1,-STACK_FRAME_C_MINIMAL(%r1)

@ -72,11 +72,13 @@ begin
variable vec : integer range 0 to 16#fff#; variable vec : integer range 0 to 16#fff#;
variable srr1 : std_ulogic_vector(15 downto 0); variable srr1 : std_ulogic_vector(15 downto 0);
variable intr : std_ulogic; variable intr : std_ulogic;
variable hvi : std_ulogic;
begin begin
w_out <= WritebackToRegisterFileInit; w_out <= WritebackToRegisterFileInit;
c_out <= WritebackToCrFileInit; c_out <= WritebackToCrFileInit;
f := WritebackToFetch1Init; f := WritebackToFetch1Init;
vec := 0; vec := 0;
hvi := '0';


complete_out <= instr_tag_init; complete_out <= instr_tag_init;
if e_in.valid = '1' then if e_in.valid = '1' then
@ -96,6 +98,7 @@ begin
if e_in.interrupt = '1' then if e_in.interrupt = '1' then
vec := e_in.intr_vec; vec := e_in.intr_vec;
srr1 := e_in.srr1; srr1 := e_in.srr1;
hvi := e_in.hv_intr;
elsif l_in.interrupt = '1' then elsif l_in.interrupt = '1' then
vec := l_in.intr_vec; vec := l_in.intr_vec;
srr1 := l_in.srr1; srr1 := l_in.srr1;
@ -103,6 +106,7 @@ begin
vec := fp_in.intr_vec; vec := fp_in.intr_vec;
srr1 := fp_in.srr1; srr1 := fp_in.srr1;
end if; end if;
interrupt_out.hv_intr <= hvi;
interrupt_out.srr1 <= srr1; interrupt_out.srr1 <= srr1;


if intr = '0' then if intr = '0' then

Loading…
Cancel
Save