diff mbox

[v1,2/3] arm: fix the armv7m reset state

Message ID 1498728533-23160-3-git-send-email-frederic.konrad@adacore.com
State New
Headers show

Commit Message

KONRAD Frederic June 29, 2017, 9:28 a.m. UTC
This fixes an odd bug when a ROM is present somewhere and an alias @0x00000000
is pointing to the ROM. The "if (rom)" test fails and we don't get a valid reset
state. QEMU later crashes with an exception because the ARMv7-M starts with the
ARM instruction set. (eg: PC & 0x01 is 0).

This patch uses memory_region_get_offset_within_address_space introduced before
to check if an alias doesn't point to a flash somewhere.

Signed-off-by: KONRAD Frederic <frederic.konrad@adacore.com>
---
 target/arm/cpu.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

Comments

Peter Maydell June 29, 2017, 3:14 p.m. UTC | #1
On 29 June 2017 at 10:28, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
> This fixes an odd bug when a ROM is present somewhere and an alias @0x00000000
> is pointing to the ROM. The "if (rom)" test fails and we don't get a valid reset
> state. QEMU later crashes with an exception because the ARMv7-M starts with the
> ARM instruction set. (eg: PC & 0x01 is 0).
>
> This patch uses memory_region_get_offset_within_address_space introduced before
> to check if an alias doesn't point to a flash somewhere.
>
> Signed-off-by: KONRAD Frederic <frederic.konrad@adacore.com>

This is awkward, because in the "we have a ROM but it's not been
copied into memory yet" case, the only thing we have is the
rom->addr, which is the address which the user's ROM blob said
it ought to be loaded in at. If the user didn't actually provide
a ROM blob that loads at 0 that seems a bit like a user error,
and I don't think this patch will catch all the cases of that
sort of mistake. For instance if address 0 is real flash and the
high address alias is modelled by having the high address be the
alias, then if the user passes us an ELF file saying "load to
the high address" then this change won't catch that I think
(because doing the memory_region_find/get_offset_within_address_space
will return 0, which has already been tried). You'd need to
somehow have a way to say "find all the addresses within this
AS where this MR is mapped" and try them all...

thanks
-- PMM
KONRAD Frederic June 29, 2017, 4:41 p.m. UTC | #2
On 06/29/2017 05:14 PM, Peter Maydell wrote:
> On 29 June 2017 at 10:28, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
>> This fixes an odd bug when a ROM is present somewhere and an alias @0x00000000
>> is pointing to the ROM. The "if (rom)" test fails and we don't get a valid reset
>> state. QEMU later crashes with an exception because the ARMv7-M starts with the
>> ARM instruction set. (eg: PC & 0x01 is 0).
>>
>> This patch uses memory_region_get_offset_within_address_space introduced before
>> to check if an alias doesn't point to a flash somewhere.
>>
>> Signed-off-by: KONRAD Frederic <frederic.konrad@adacore.com>
> 
> This is awkward, because in the "we have a ROM but it's not been
> copied into memory yet" case, the only thing we have is the
> rom->addr, which is the address which the user's ROM blob said
> it ought to be loaded in at. If the user didn't actually provide
> a ROM blob that loads at 0 that seems a bit like a user error,
> and I don't think this patch will catch all the cases of that
> sort of mistake.

I don't think it's really a user mistake because on the real HW
the alias is configurable.. at least in my case.

There is a "jumper" setting to mirror either the Flash or the
SRAM, etc. So the binaries isn't located at 0 but at the flash
address 0x8000000 or some such. That's the case with u-boot and
the precompiled examples I found for this stm32fxxxx board.

  For instance if address 0 is real flash and the
> high address alias is modelled by having the high address be the
> alias, then if the user passes us an ELF file saying "load to
> the high address" then this change won't catch that I think
> (because doing the memory_region_find/get_offset_within_address_space
> will return 0, which has already been tried). You'd need to
> somehow have a way to say "find all the addresses within this
> AS where this MR is mapped" and try them all...

This is more likely to be a user error :). Maybe we can load
the ROM before the reset but that seems a lot more invasive..

BTW isn't there a trick with the ELF entry somewhere? Or is that
for the Cortex-A?

Thanks,
Fred

> 
> thanks
> -- PMM
>
Peter Maydell June 29, 2017, 4:45 p.m. UTC | #3
On 29 June 2017 at 17:41, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
> On 06/29/2017 05:14 PM, Peter Maydell wrote:
>> This is awkward, because in the "we have a ROM but it's not been
>> copied into memory yet" case, the only thing we have is the
>> rom->addr, which is the address which the user's ROM blob said
>> it ought to be loaded in at. If the user didn't actually provide
>> a ROM blob that loads at 0 that seems a bit like a user error,
>> and I don't think this patch will catch all the cases of that
>> sort of mistake.
>
>
> I don't think it's really a user mistake because on the real HW
> the alias is configurable.. at least in my case.
>
> There is a "jumper" setting to mirror either the Flash or the
> SRAM, etc. So the binaries isn't located at 0 but at the flash
> address 0x8000000 or some such. That's the case with u-boot and
> the precompiled examples I found for this stm32fxxxx board.
>
>>  For instance if address 0 is real flash and the
>> high address alias is modelled by having the high address be the
>> alias, then if the user passes us an ELF file saying "load to
>> the high address" then this change won't catch that I think
>> (because doing the memory_region_find/get_offset_within_address_space
>> will return 0, which has already been tried). You'd need to
>> somehow have a way to say "find all the addresses within this
>> AS where this MR is mapped" and try them all...
>
>
> This is more likely to be a user error :). Maybe we can load
> the ROM before the reset but that seems a lot more invasive..

It's the same thing, though, right? If the user's ELF file
says "vector table is at 0x8000000" then we should either
(a) say that's a user error, or
(b) handle it right, whether we implemented the QEMU model with
the flash at 0 and the alias at 0x8000000, or with the flash
at 0x8000000 and the alias at 0.

> BTW isn't there a trick with the ELF entry somewhere? Or is that
> for the Cortex-A?

We don't honour the ELF entry point on M profile (arguably
a bug) -- armv7m_load_kernel() ignores the entry point
returned by load_elf() in the 'entry' variable.

thanks
-- PMM
KONRAD Frederic June 30, 2017, 8:24 a.m. UTC | #4
On 06/29/2017 06:45 PM, Peter Maydell wrote:
> On 29 June 2017 at 17:41, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
>> On 06/29/2017 05:14 PM, Peter Maydell wrote:
>>> This is awkward, because in the "we have a ROM but it's not been
>>> copied into memory yet" case, the only thing we have is the
>>> rom->addr, which is the address which the user's ROM blob said
>>> it ought to be loaded in at. If the user didn't actually provide
>>> a ROM blob that loads at 0 that seems a bit like a user error,
>>> and I don't think this patch will catch all the cases of that
>>> sort of mistake.
>>
>>
>> I don't think it's really a user mistake because on the real HW
>> the alias is configurable.. at least in my case.
>>
>> There is a "jumper" setting to mirror either the Flash or the
>> SRAM, etc. So the binaries isn't located at 0 but at the flash
>> address 0x8000000 or some such. That's the case with u-boot and
>> the precompiled examples I found for this stm32fxxxx board.
>>
>>>   For instance if address 0 is real flash and the
>>> high address alias is modelled by having the high address be the
>>> alias, then if the user passes us an ELF file saying "load to
>>> the high address" then this change won't catch that I think
>>> (because doing the memory_region_find/get_offset_within_address_space
>>> will return 0, which has already been tried). You'd need to
>>> somehow have a way to say "find all the addresses within this
>>> AS where this MR is mapped" and try them all...
>>
>>
>> This is more likely to be a user error :). Maybe we can load
>> the ROM before the reset but that seems a lot more invasive..
> 
> It's the same thing, though, right? If the user's ELF file
> says "vector table is at 0x8000000" then we should either
> (a) say that's a user error, or
> (b) handle it right, whether we implemented the QEMU model with
> the flash at 0 and the alias at 0x8000000, or with the flash
> at 0x8000000 and the alias at 0.

Hi Peter,

Fondamentaly yes, it is the same.. but it seems really strange to
me to load the elf in the alias.

If I choose (a) I'll need to objcpy all the elf to 0 or modify
the build script which should work on the real board.. This seems
not really a good option to me.

If I choose (b) I won't be able to load it to SRAM and it is
basically the same result I'll need to move or modify the config.

Thanks,
Fred

> 
>> BTW isn't there a trick with the ELF entry somewhere? Or is that
>> for the Cortex-A?
> 
> We don't honour the ELF entry point on M profile (arguably
> a bug) -- armv7m_load_kernel() ignores the entry point
> returned by load_elf() in the 'entry' variable.
> 
> thanks
> -- PMM
>
Peter Maydell June 30, 2017, 9:06 a.m. UTC | #5
On 30 June 2017 at 09:24, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
> On 06/29/2017 06:45 PM, Peter Maydell wrote:
>> It's the same thing, though, right? If the user's ELF file
>> says "vector table is at 0x8000000" then we should either
>> (a) say that's a user error, or
>> (b) handle it right, whether we implemented the QEMU model with
>> the flash at 0 and the alias at 0x8000000, or with the flash
>> at 0x8000000 and the alias at 0.

> Fondamentaly yes, it is the same.. but it seems really strange to
> me to load the elf in the alias.

The user creating the ELF file has no idea whether we
modelled the flash at 0 and the alias at highmem or
the other way around -- that is an implementation detail
that should be completely invisible to the user.
My two suggestions are based on that point -- either we
should treat "ELF loaded at highmem" as always wrong, or
we should always support it.

> If I choose (a) I'll need to objcpy all the elf to 0 or modify
> the build script which should work on the real board.. This seems
> not really a good option to me.

I agree that I don't like this.

> If I choose (b) I won't be able to load it to SRAM and it is
> basically the same result I'll need to move or modify the config.

I don't understand this, though. Option (b) is probably painful
to implement (I don't have a good idea of how to do it) but
it ought to mean that the ELF files that work on the board
also work for QEMU (regardless of how the board model
implemented the aliased flash).

thanks
-- PMM
KONRAD Frederic July 3, 2017, 7:31 a.m. UTC | #6
On 06/30/2017 11:06 AM, Peter Maydell wrote:
> On 30 June 2017 at 09:24, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
>> On 06/29/2017 06:45 PM, Peter Maydell wrote:
>>> It's the same thing, though, right? If the user's ELF file
>>> says "vector table is at 0x8000000" then we should either
>>> (a) say that's a user error, or
>>> (b) handle it right, whether we implemented the QEMU model with
>>> the flash at 0 and the alias at 0x8000000, or with the flash
>>> at 0x8000000 and the alias at 0.
> 
>> Fondamentaly yes, it is the same.. but it seems really strange to
>> me to load the elf in the alias.
> 
> The user creating the ELF file has no idea whether we
> modelled the flash at 0 and the alias at highmem or
> the other way around -- that is an implementation detail
> that should be completely invisible to the user.
> My two suggestions are based on that point -- either we
> should treat "ELF loaded at highmem" as always wrong, or
> we should always support it.
> 
>> If I choose (a) I'll need to objcpy all the elf to 0 or modify
>> the build script which should work on the real board.. This seems
>> not really a good option to me.
> 
> I agree that I don't like this.
> 
>> If I choose (b) I won't be able to load it to SRAM and it is
>> basically the same result I'll need to move or modify the config.
> 
> I don't understand this, though. Option (b) is probably painful
> to implement (I don't have a good idea of how to do it) but
> it ought to mean that the ELF files that work on the board
> also work for QEMU (regardless of how the board model
> implemented the aliased flash).
> 

Yes that's exactly what I want.

Basically the 0x00000000 alias can point to the SRAM or the ROM
during the reset depending on some boot config. The ELF is
directly loaded in the ROM or in the SRAM and my patch allows to
fetch the two first words in the reset handler to make it work
for any boot config.

For example this devices p69:
www.st.com/resource/en/reference_manual/DM00031020.pdf

Thanks,
Fred

> thanks
> -- PMM
>
Peter Maydell July 3, 2017, 8:51 a.m. UTC | #7
On 3 July 2017 at 08:31, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
> On 06/30/2017 11:06 AM, Peter Maydell wrote:
>> On 30 June 2017 at 09:24, KONRAD Frederic <frederic.konrad@adacore.com>
>> wrote:
>>> If I choose (b) I won't be able to load it to SRAM and it is
>>> basically the same result I'll need to move or modify the config.
>>
>>
>> I don't understand this, though. Option (b) is probably painful
>> to implement (I don't have a good idea of how to do it) but
>> it ought to mean that the ELF files that work on the board
>> also work for QEMU (regardless of how the board model
>> implemented the aliased flash).
>>
>
> Yes that's exactly what I want.
>
> Basically the 0x00000000 alias can point to the SRAM or the ROM
> during the reset depending on some boot config. The ELF is
> directly loaded in the ROM or in the SRAM and my patch allows to
> fetch the two first words in the reset handler to make it work
> for any boot config.

Yes, but it only works if you implemented it that way
round, and not for board implementations which put the
real device at 0 and the alias at high memory. I'd like a fix
which deals with all of this, not just with the particular
arrangement your board implementation has.

thanks
-- PMM
KONRAD Frederic July 3, 2017, 9:04 a.m. UTC | #8
On 07/03/2017 10:51 AM, Peter Maydell wrote:
> On 3 July 2017 at 08:31, KONRAD Frederic <frederic.konrad@adacore.com> wrote:
>> On 06/30/2017 11:06 AM, Peter Maydell wrote:
>>> On 30 June 2017 at 09:24, KONRAD Frederic <frederic.konrad@adacore.com>
>>> wrote:
>>>> If I choose (b) I won't be able to load it to SRAM and it is
>>>> basically the same result I'll need to move or modify the config.
>>>
>>>
>>> I don't understand this, though. Option (b) is probably painful
>>> to implement (I don't have a good idea of how to do it) but
>>> it ought to mean that the ELF files that work on the board
>>> also work for QEMU (regardless of how the board model
>>> implemented the aliased flash).
>>>
>>
>> Yes that's exactly what I want.
>>
>> Basically the 0x00000000 alias can point to the SRAM or the ROM
>> during the reset depending on some boot config. The ELF is
>> directly loaded in the ROM or in the SRAM and my patch allows to
>> fetch the two first words in the reset handler to make it work
>> for any boot config.
> 
> Yes, but it only works if you implemented it that way
> round, and not for board implementations which put the
> real device at 0 and the alias at high memory. I'd like a fix
> which deals with all of this, not just with the particular
> arrangement your board implementation has.

Ok got it, I'll check if I can do something clean which can
handle both ways.

Fred

> 
> thanks
> -- PMM
>
diff mbox

Patch

diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 28a9141..b8afd97 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -201,6 +201,20 @@  static void arm_cpu_reset(CPUState *s)
 
         /* Load the initial SP and PC from the vector table at address 0 */
         rom = rom_ptr(0);
+
+        if (!rom) {
+            /* Sometimes address 0x00000000 is an alias to a flash which
+             * actually have a ROM.
+             */
+            MemoryRegionSection section;
+            hwaddr offset = 0;
+
+            section = memory_region_find(s->as->root, 0, 8);
+            offset = memory_region_get_offset_within_address_space(section.mr);
+            memory_region_unref(section.mr);
+            rom = rom_ptr(offset);
+        }
+
         if (rom) {
             /* Address zero is covered by ROM which hasn't yet been
              * copied into physical memory.