diff mbox

[U-Boot,1/9] arm926ej-s: Invalidate instruction cache in flush_cache

Message ID 1300391223-11879-2-git-send-email-mspang@csclub.uwaterloo.ca
State Rejected
Delegated to: Albert ARIBAUD
Headers show

Commit Message

Michael Spang March 17, 2011, 7:46 p.m. UTC
If U-Boot is loaded from RAM and the OS is loaded into an overlapping
region, the instruction cache is not coherent when that OS is started.
We must therefore invalidate the instruction cache in addition to
cleaning the data cache.

Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
---
 arch/arm/lib/cache.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

Comments

arden jay March 20, 2011, 2:30 a.m. UTC | #1
Hi Michael,
Curiously, have any idea how to test cache stuff?

2011/3/18 Michael Spang <mspang@csclub.uwaterloo.ca>:
> If U-Boot is loaded from RAM and the OS is loaded into an overlapping
> region, the instruction cache is not coherent when that OS is started.
> We must therefore invalidate the instruction cache in addition to
> cleaning the data cache.
>
> Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
> ---
>  arch/arm/lib/cache.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
> index 30686fe..047786a 100644
> --- a/arch/arm/lib/cache.c
> +++ b/arch/arm/lib/cache.c
> @@ -37,6 +37,8 @@ void  flush_cache (unsigned long dummy1, unsigned long dummy2)
>        asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory");
>        /* disable write buffer as well (page 2-22) */
>        asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
> +       /* invalidate icache for coherence with cleaned dcache */
> +       asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
>  #endif
>  #ifdef CONFIG_OMAP34XX
>        void v7_flush_cache_all(void);
> --
> 1.7.2.3
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Michael Spang March 20, 2011, 3:44 a.m. UTC | #2
On 3/19/11, arden jay <arden.jay@gmail.com> wrote:
> Hi Michael,
> Curiously, have any idea how to test cache stuff?

I don't have any good suggestions for testing cache stuff in general,
but this one is pretty easy to test if you have the board in question.
Because U-Boot is loaded *as if it were linux* by the manufacturer's
bootloader, the initial location of U-Boot is the same as where we
ultimately load the Linux kernel. Without this patch the symptom is
the failure of Linux to start from U-Boot.

Michael
arden jay March 20, 2011, 5:36 a.m. UTC | #3
Hi Michael,

I still have question. :)

When ARM fetch instruction, it firstly try cache.
It then should have cache miss, and forces to reload the instruction
from memory?

Why it will have problem while U-boot & Kernel at the same memory location?

2011/3/20 Michael Spang <mspang@csclub.uwaterloo.ca>:
> On 3/19/11, arden jay <arden.jay@gmail.com> wrote:
>> Hi Michael,
>> Curiously, have any idea how to test cache stuff?
>
> I don't have any good suggestions for testing cache stuff in general,
> but this one is pretty easy to test if you have the board in question.
> Because U-Boot is loaded *as if it were linux* by the manufacturer's
> bootloader, the initial location of U-Boot is the same as where we
> ultimately load the Linux kernel. Without this patch the symptom is
> the failure of Linux to start from U-Boot.
>
> Michael
>
Albert ARIBAUD March 20, 2011, 8:18 a.m. UTC | #4
Le 03/20/11 06:36, arden jay a écrit :
> Hi Michael,
>
> I still have question. :)
>
> When ARM fetch instruction, it firstly try cache.
> It then should have cache miss, and forces to reload the instruction
> from memory?
> Why it will have problem while U-boot&  Kernel at the same memory location?

The error in your assumption is the "it then should have cache miss". A 
cache won't have a cache miss if it has already been fetched and not yet 
been invalidated, and the i-cache won't magically invalidate just 
because you do data writes at the location where the i-cache was fetched 
from; you end up with an i-cache that pretends to be valid but no longer 
matches the main memory content.

Amicalement,
arden jay March 20, 2011, 2:14 p.m. UTC | #5
Hi Albert,

I got it, thanks your explaination.

2011/3/20 Albert ARIBAUD <albert.aribaud@free.fr>:
> Le 03/20/11 06:36, arden jay a écrit :
>>
>> Hi Michael,
>>
>> I still have question. :)
>>
>> When ARM fetch instruction, it firstly try cache.
>> It then should have cache miss, and forces to reload the instruction
>> from memory?
>> Why it will have problem while U-boot&  Kernel at the same memory
>> location?
>
> The error in your assumption is the "it then should have cache miss". A
> cache won't have a cache miss if it has already been fetched and not yet
> been invalidated, and the i-cache won't magically invalidate just because
> you do data writes at the location where the i-cache was fetched from; you
> end up with an i-cache that pretends to be valid but no longer matches the
> main memory content.
>
> Amicalement,
> --
> Albert.
>
Michael Spang March 20, 2011, 6:26 p.m. UTC | #6
On 3/20/11, arden jay <arden.jay@gmail.com> wrote:
> Hi Michael,
>
> I still have question. :)
>
> When ARM fetch instruction, it firstly try cache.
> It then should have cache miss, and forces to reload the instruction
> from memory?
>
> Why it will have problem while U-boot & Kernel at the same memory location?

If the instruction fetch misses the cache, then it works fine. That's
why invalidating solves the problem. The problem is that it hits, but
returns the wrong instructions. The code from U-Boot is loaded into
the icache when U-Boot is started (before it is relocated) and some of
it is still in the icache when we execute linux. So the CPU ends up
fetching the wrong instructions.

On ARM if code is stored to RAM, then the modified addresses must be
manually invalidated in the instruction cache. The hardware does not
do this for us.

Michael
Aneesh V March 21, 2011, 5:44 a.m. UTC | #7
Hi Arden,

On Sunday 20 March 2011 08:00 AM, arden jay wrote:
> Hi Michael,
> Curiously, have any idea how to test cache stuff?

Recently I did some cache testing. Here is the technique I used for
data-cache:

To test flush:
* Write a known pattern to a region of memory
* Flush the region
* Invalidate the region
* Read back the region and see if you get the original pattern. If the
flush was effective you will see the original data.

To test Invalidate:
* Write a known pattern to a region of memory
* Invalidate the region immediately
* Read back the region and see if you get the original pattern. You
should *not* be seeing the expected pattern for the entire region if
the invalidate was successful.

Similar tests can be done for the I-cache, but maybe a little more
tedious.

I agree that these tests may not be 100% fool-proof - for instance what
if both invalidate and flush didn't work in the first case. But these
should at least catch very obvious errors and can be used in
combination with other techniques to make sure that your cache
operations are indeed working.

Additionally, there was a JTAG debugger technique that I found quite
useful. If your processor supports a technique called DAP(Debug Access
Port or Dual Access Port, I am not sure) then a debugger like
Lauterbach can view memory in two modes, one the normal or CPU mode and
the other DAP mode. In normal mode the memory is dumped as if it is
viewed from the CPU, so it goes through the cache and you see the cache
contents if the area in question is in cache. In DAP mode the
real memory contents are dumped. Comparing these two you can see
whether cache and memory are coherent for a given area. It worked quite
well with Lauterbach and OMAP4.

br,
Aneesh

>
> 2011/3/18 Michael Spang<mspang@csclub.uwaterloo.ca>:
>> If U-Boot is loaded from RAM and the OS is loaded into an overlapping
>> region, the instruction cache is not coherent when that OS is started.
>> We must therefore invalidate the instruction cache in addition to
>> cleaning the data cache.
>>
>> Signed-off-by: Michael Spang<mspang@csclub.uwaterloo.ca>
>> ---
>>   arch/arm/lib/cache.c |    2 ++
>>   1 files changed, 2 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
>> index 30686fe..047786a 100644
>> --- a/arch/arm/lib/cache.c
>> +++ b/arch/arm/lib/cache.c
>> @@ -37,6 +37,8 @@ void  flush_cache (unsigned long dummy1, unsigned long dummy2)
>>         asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory");
>>         /* disable write buffer as well (page 2-22) */
>>         asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
>> +       /* invalidate icache for coherence with cleaned dcache */
>> +       asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
>>   #endif
>>   #ifdef CONFIG_OMAP34XX
>>         void v7_flush_cache_all(void);
>> --
>> 1.7.2.3
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot@lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot
>>
>
>
>
arden jay March 21, 2011, 2:14 p.m. UTC | #8
Hi Michael,
Thanks, it is the key point:
"The problem is that it hits, but returns the wrong instructions."

Hi Aneesh,
Thanks for your sharing, it makes sense to check that way.

2011/3/21 Aneesh V <aneesh@ti.com>:
> Hi Arden,
>
> On Sunday 20 March 2011 08:00 AM, arden jay wrote:
>>
>> Hi Michael,
>> Curiously, have any idea how to test cache stuff?
>
> Recently I did some cache testing. Here is the technique I used for
> data-cache:
>
> To test flush:
> * Write a known pattern to a region of memory
> * Flush the region
> * Invalidate the region
> * Read back the region and see if you get the original pattern. If the
> flush was effective you will see the original data.
>
> To test Invalidate:
> * Write a known pattern to a region of memory
> * Invalidate the region immediately
> * Read back the region and see if you get the original pattern. You
> should *not* be seeing the expected pattern for the entire region if
> the invalidate was successful.
>
> Similar tests can be done for the I-cache, but maybe a little more
> tedious.
>
> I agree that these tests may not be 100% fool-proof - for instance what
> if both invalidate and flush didn't work in the first case. But these
> should at least catch very obvious errors and can be used in
> combination with other techniques to make sure that your cache
> operations are indeed working.
>
> Additionally, there was a JTAG debugger technique that I found quite
> useful. If your processor supports a technique called DAP(Debug Access
> Port or Dual Access Port, I am not sure) then a debugger like
> Lauterbach can view memory in two modes, one the normal or CPU mode and
> the other DAP mode. In normal mode the memory is dumped as if it is
> viewed from the CPU, so it goes through the cache and you see the cache
> contents if the area in question is in cache. In DAP mode the
> real memory contents are dumped. Comparing these two you can see
> whether cache and memory are coherent for a given area. It worked quite
> well with Lauterbach and OMAP4.
>
> br,
> Aneesh
>
>>
>> 2011/3/18 Michael Spang<mspang@csclub.uwaterloo.ca>:
>>>
>>> If U-Boot is loaded from RAM and the OS is loaded into an overlapping
>>> region, the instruction cache is not coherent when that OS is started.
>>> We must therefore invalidate the instruction cache in addition to
>>> cleaning the data cache.
>>>
>>> Signed-off-by: Michael Spang<mspang@csclub.uwaterloo.ca>
>>> ---
>>>  arch/arm/lib/cache.c |    2 ++
>>>  1 files changed, 2 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
>>> index 30686fe..047786a 100644
>>> --- a/arch/arm/lib/cache.c
>>> +++ b/arch/arm/lib/cache.c
>>> @@ -37,6 +37,8 @@ void  flush_cache (unsigned long dummy1, unsigned long
>>> dummy2)
>>>        asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : :
>>> "memory");
>>>        /* disable write buffer as well (page 2-22) */
>>>        asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
>>> +       /* invalidate icache for coherence with cleaned dcache */
>>> +       asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
>>>  #endif
>>>  #ifdef CONFIG_OMAP34XX
>>>        void v7_flush_cache_all(void);
>>> --
>>> 1.7.2.3
>>>
>>> _______________________________________________
>>> U-Boot mailing list
>>> U-Boot@lists.denx.de
>>> http://lists.denx.de/mailman/listinfo/u-boot
>>>
>>
>>
>>
>
Albert ARIBAUD July 29, 2013, 7:19 a.m. UTC | #9
(although this patch is more than two *years* old, it never got properly
answered to. I am doing so here to make sure future readers know why it
was not applied and won't be.)

Hi Michael,

On Thu, 17 Mar 2011 15:46:55 -0400, Michael Spang
<mspang@csclub.uwaterloo.ca> wrote:

> If U-Boot is loaded from RAM and the OS is loaded into an overlapping
> region, the instruction cache is not coherent when that OS is started.
> We must therefore invalidate the instruction cache in addition to
> cleaning the data cache.
> 
> Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
> ---
>  arch/arm/lib/cache.c |    2 ++
>  1 files changed, 2 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
> index 30686fe..047786a 100644
> --- a/arch/arm/lib/cache.c
> +++ b/arch/arm/lib/cache.c
> @@ -37,6 +37,8 @@ void  flush_cache (unsigned long dummy1, unsigned long dummy2)
>  	asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory");
>  	/* disable write buffer as well (page 2-22) */
>  	asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
> +	/* invalidate icache for coherence with cleaned dcache */
> +	asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
>  #endif
>  #ifdef CONFIG_OMAP34XX
>  	void v7_flush_cache_all(void);

This patch has obviously not been applied, and won't be, because of
two reasons: i) overwriting part of U-Boot when loading the kernel
is a bug which should not be papered over, and ii) if we had to do this
anyway, the right place to do it would have been where the issue might
occur, that is, in the OS boot sequence, not in the cache handling
functions.

Apologies for not properly answering in due time.

Amicalement,
Michael Spang July 29, 2013, 12:57 p.m. UTC | #10
Albert,

That's not a correct characterization of the bug.

The incoherent cache lines are from before the relocation stage. If
U-Boot is relocating from RAM, and later copies the OS there without
invalidating those lines, then that's a bug in U-Boot.

Michael

On Mon, Jul 29, 2013 at 3:19 AM, Albert ARIBAUD
<albert.u.boot@aribaud.net> wrote:
> (although this patch is more than two *years* old, it never got properly
> answered to. I am doing so here to make sure future readers know why it
> was not applied and won't be.)
>
> Hi Michael,
>
> On Thu, 17 Mar 2011 15:46:55 -0400, Michael Spang
> <mspang@csclub.uwaterloo.ca> wrote:
>
>> If U-Boot is loaded from RAM and the OS is loaded into an overlapping
>> region, the instruction cache is not coherent when that OS is started.
>> We must therefore invalidate the instruction cache in addition to
>> cleaning the data cache.
>>
>> Signed-off-by: Michael Spang <mspang@csclub.uwaterloo.ca>
>> ---
>>  arch/arm/lib/cache.c |    2 ++
>>  1 files changed, 2 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
>> index 30686fe..047786a 100644
>> --- a/arch/arm/lib/cache.c
>> +++ b/arch/arm/lib/cache.c
>> @@ -37,6 +37,8 @@ void  flush_cache (unsigned long dummy1, unsigned long dummy2)
>>       asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory");
>>       /* disable write buffer as well (page 2-22) */
>>       asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
>> +     /* invalidate icache for coherence with cleaned dcache */
>> +     asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
>>  #endif
>>  #ifdef CONFIG_OMAP34XX
>>       void v7_flush_cache_all(void);
>
> This patch has obviously not been applied, and won't be, because of
> two reasons: i) overwriting part of U-Boot when loading the kernel
> is a bug which should not be papered over, and ii) if we had to do this
> anyway, the right place to do it would have been where the issue might
> occur, that is, in the OS boot sequence, not in the cache handling
> functions.
>
> Apologies for not properly answering in due time.
>
> Amicalement,
> --
> Albert.
Albert ARIBAUD July 29, 2013, 2:09 p.m. UTC | #11
Hi Michael,

On Mon, 29 Jul 2013 08:57:53 -0400, Michael Spang
<mspang@csclub.uwaterloo.ca> wrote:

> Albert,
> 
> That's not a correct characterization of the bug.
> 
> The incoherent cache lines are from before the relocation stage. If
> U-Boot is relocating from RAM, and later copies the OS there without
> invalidating those lines, then that's a bug in U-Boot.

Thanks for this pointing out this scenario, which is correct, although
it was not raised in the original bug description.

I begs however the question whether anything from re-relocation can
survive in the icache from between the moment the relocation starts and
the moment the OS is given transfer to. IOW, was this issue actually
met?

Anyway I stand by my statement that even if there is an issue to fix,
this patch fixes it in the wrong place.

> Michael

Amicalement,
Michael Spang July 29, 2013, 2:22 p.m. UTC | #12
On Mon, Jul 29, 2013 at 10:09 AM, Albert ARIBAUD
<albert.u.boot@aribaud.net> wrote:
> Hi Michael,
>
> On Mon, 29 Jul 2013 08:57:53 -0400, Michael Spang
> <mspang@csclub.uwaterloo.ca> wrote:
>
>> Albert,
>>
>> That's not a correct characterization of the bug.
>>
>> The incoherent cache lines are from before the relocation stage. If
>> U-Boot is relocating from RAM, and later copies the OS there without
>> invalidating those lines, then that's a bug in U-Boot.
>
> Thanks for this pointing out this scenario, which is correct, although
> it was not raised in the original bug description.
>
> I begs however the question whether anything from re-relocation can
> survive in the icache from between the moment the relocation starts and
> the moment the OS is given transfer to. IOW, was this issue actually
> met?

Yes, I had boot failures without this patch on the device I was
porting to (TS-7800). It happened consistently.

>
> Anyway I stand by my statement that even if there is an issue to fix,
> this patch fixes it in the wrong place.

Ok, that's fair. I was hoping to repost this series someday and will
take that into account.

Michael
diff mbox

Patch

diff --git a/arch/arm/lib/cache.c b/arch/arm/lib/cache.c
index 30686fe..047786a 100644
--- a/arch/arm/lib/cache.c
+++ b/arch/arm/lib/cache.c
@@ -37,6 +37,8 @@  void  flush_cache (unsigned long dummy1, unsigned long dummy2)
 	asm("0: mrc p15, 0, r15, c7, c10, 3\n\t" "bne 0b\n" : : : "memory");
 	/* disable write buffer as well (page 2-22) */
 	asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
+	/* invalidate icache for coherence with cleaned dcache */
+	asm("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
 #endif
 #ifdef CONFIG_OMAP34XX
 	void v7_flush_cache_all(void);