| From f4142cba4e4065a416e78ade905bea29ff3930e6 Mon Sep 17 00:00:00 2001 |
| From: "David S. Miller" <davem@davemloft.net> |
| Date: Thu, 29 Sep 2011 12:18:59 -0700 |
| Subject: sparc64: Force the execute bit in OpenFirmware's translation entries. |
| Status: RO |
| Content-Length: 1822 |
| Lines: 48 |
| |
| From: "David S. Miller" <davem@davemloft.net> |
| |
| In the OF 'translations' property, the template TTEs in the mappings |
| never specify the executable bit. This is the case even though some |
| of these mappings are for OF's code segment. |
| |
| Therefore, we need to force the execute bit on in every mapping. |
| |
| This problem can only really trigger on Niagara/sun4v machines and the |
| history behind this is a little complicated. |
| |
| Previous to sun4v, the sun4u TTE entries lacked a hardware execute |
| permission bit. So OF didn't have to ever worry about setting |
| anything to handle executable pages. Any valid TTE loaded into the |
| I-TLB would be respected by the chip. |
| |
| But sun4v Niagara chips have a real hardware enforced executable bit |
| in their TTEs. So it has to be set or else the I-TLB throws an |
| instruction access exception with type code 6 (protection violation). |
| |
| We've been extremely fortunate to not get bitten by this in the past. |
| |
| The best I can tell is that the OF's mappings for it's executable code |
| were mapped using permanent locked mappings on sun4v in the past. |
| Therefore, the fact that we didn't have the exec bit set in the OF |
| translations we would use did not matter in practice. |
| |
| Thanks to Greg Onufer for helping me track this down. |
| |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/sparc/mm/init_64.c | 5 +++++ |
| 1 file changed, 5 insertions(+) |
| |
| --- a/arch/sparc/mm/init_64.c |
| +++ b/arch/sparc/mm/init_64.c |
| @@ -511,6 +511,11 @@ static void __init read_obp_translations |
| for (i = 0; i < prom_trans_ents; i++) |
| prom_trans[i].data &= ~0x0003fe0000000000UL; |
| } |
| + |
| + /* Force execute bit on. */ |
| + for (i = 0; i < prom_trans_ents; i++) |
| + prom_trans[i].data |= (tlb_type == hypervisor ? |
| + _PAGE_EXEC_4V : _PAGE_EXEC_4U); |
| } |
| |
| static void __init hypervisor_tlb_lock(unsigned long vaddr, |