diff options
| author | Jonas Bonn <jonas@southpole.se> | 2013-02-14 01:42:30 -0500 |
|---|---|---|
| committer | Jonas Bonn <jonas@southpole.se> | 2013-02-17 02:46:10 -0500 |
| commit | 8668480eb79f0cbd79d6b584a10604d743853062 (patch) | |
| tree | 2dfe1d8e3867b9bd3c474d7844423112d5ae16d0 | |
| parent | a81252d75e14cc2cf0ee45078ef143562a0bc279 (diff) | |
openrisc: update DTLB-miss handler last
The self-modifying code that updates the TLB handler at start-up has
a subtle ordering requirement: the DTLB handler must be the last thing
changed.
What I was seeing was the following:
i) The DTLB handler was updated
ii) The following printk caused a TLB miss and the look-up resulted
in the page containing itlb_vector (0xc0000a00) being bounced from
the TLB.
iii) The subsequent access to itlb_vector caused a TLB miss and reload
of the page containing itlb_vector from the page tables.
iv) But this reload of the page in iii) was being done by the "new"
DTLB-miss handler which resulted (correctly) in the page flags being
set to read-only; the subsequent write-access to itlb_vector thus
resulted in a page (access) fault.
This is easily remedied if we ensure that the boot-time DTLB-miss handler
continues running until the very last bit of self-modifying code has been
executed. This patch should ensure that the very last thing updated is the
DTLB-handler itself.
Signed-off-by: Jonas Bonn <jonas@southpole.se>
Acked-by: Julius Baxter <juliusbaxter@gmail.com>
Tested-by: Sebastian Macke <sebastian@macke.de>
| -rw-r--r-- | arch/openrisc/mm/init.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c index 79dea9740a3c..e7fdc50c4bf0 100644 --- a/arch/openrisc/mm/init.c +++ b/arch/openrisc/mm/init.c | |||
| @@ -167,15 +167,26 @@ void __init paging_init(void) | |||
| 167 | unsigned long *dtlb_vector = __va(0x900); | 167 | unsigned long *dtlb_vector = __va(0x900); |
| 168 | unsigned long *itlb_vector = __va(0xa00); | 168 | unsigned long *itlb_vector = __va(0xa00); |
| 169 | 169 | ||
| 170 | printk(KERN_INFO "itlb_miss_handler %p\n", &itlb_miss_handler); | ||
| 171 | *itlb_vector = ((unsigned long)&itlb_miss_handler - | ||
| 172 | (unsigned long)itlb_vector) >> 2; | ||
| 173 | |||
| 174 | /* Soft ordering constraint to ensure that dtlb_vector is | ||
| 175 | * the last thing updated | ||
| 176 | */ | ||
| 177 | barrier(); | ||
| 178 | |||
| 170 | printk(KERN_INFO "dtlb_miss_handler %p\n", &dtlb_miss_handler); | 179 | printk(KERN_INFO "dtlb_miss_handler %p\n", &dtlb_miss_handler); |
| 171 | *dtlb_vector = ((unsigned long)&dtlb_miss_handler - | 180 | *dtlb_vector = ((unsigned long)&dtlb_miss_handler - |
| 172 | (unsigned long)dtlb_vector) >> 2; | 181 | (unsigned long)dtlb_vector) >> 2; |
| 173 | 182 | ||
| 174 | printk(KERN_INFO "itlb_miss_handler %p\n", &itlb_miss_handler); | ||
| 175 | *itlb_vector = ((unsigned long)&itlb_miss_handler - | ||
| 176 | (unsigned long)itlb_vector) >> 2; | ||
| 177 | } | 183 | } |
| 178 | 184 | ||
| 185 | /* Soft ordering constraint to ensure that cache invalidation and | ||
| 186 | * TLB flush really happen _after_ code has been modified. | ||
| 187 | */ | ||
| 188 | barrier(); | ||
| 189 | |||
| 179 | /* Invalidate instruction caches after code modification */ | 190 | /* Invalidate instruction caches after code modification */ |
| 180 | mtspr(SPR_ICBIR, 0x900); | 191 | mtspr(SPR_ICBIR, 0x900); |
| 181 | mtspr(SPR_ICBIR, 0xa00); | 192 | mtspr(SPR_ICBIR, 0xa00); |
