FreeBSD's armstub8-gic.bin or armstub8.bin is bigger than the reserve area is it loaded to; later part ends up overwritten

Mark Millard marklmi at yahoo.com
Wed Feb 12 02:18:08 UTC 2020


Using FreeBSD's armstub8-gic.bin as the example that
applies to my test context: It has something like 0x15bc
bytes to the end of its last instruction. (I looked at
the .elf from a build that I did.)

Doing an experiment to make the PSCI version request
also report where it sees its _start,
el3_exception_vectors, and loop addresses showed
(my summary):

_start at 0x0
el3_exception_vectors at 0x800
loop at 0x100c
(given my code additions that made the size 0x15c8
instead of 0x15bc).

So: loaded to Address 0x0. I confirmed in ddb that
I see the code sequence starting at 0x0.

In my context boot -v was reporting the below.
Compare and contrast the reserved size starting
at 0x0 to the size of armstub8-gic's code
span:

                   Type     Physical      Virtual   #Pages Attr
               Reserved 000000000000            0 00000001 WB 
     ConventionalMemory 000000001000         1000 00007ef1 WB 
. . .
Physical memory chunk(s):
  0x00001000 - 0x39f48fff,   927 MB ( 237384 pages)
  0x39f50000 - 0x39f50fff,     0 MB (      1 pages)
. . .
Excluded memory regions:
  0x00000000 - 0x00000fff,     0 MB (      1 pages) NoAlloc 
  0x32000000 - 0x33773fff,    23 MB (   6004 pages) NoAlloc 

Using ddb I confirmed that starting at 0x1000
armstub8-gic.bin 's content had been replaced.
That includes swap32, memmove, and fixup_dt_blob.

It looks to me like fixup_dt_blob needs to take
into account the span of the armstub8* material
and reserve at least 1 more page (past the page
holding its self-observed start address) than is
now reserved. (Wording avoids assuming that all
aarch64 RPi*'s would use address 0x0.)

I do not claim to know that such a change would
be sufficient. But the above seems to be a
fragile structure.


Detailed evidence techniques:

I adjusted a copy of sysutils/rpi-firmware 's armstub8
code to have the pSCI version request also fill in
the address of _start, el3_exception_vectors, and loop:

psci_version:
        /* Return v0.2 */
        adr     x3, loop
        adr     x2, el3_exception_vectors
        adr     x1, _start
        mov     x0, #0x00000002
        eret

I then added a direct use of arm_smccc_smc in a place
early enough that I'd never seen the resulting version
number to be wrong:

        uma_startup2();
 
//HACK!!!
#ifdef __aarch64__
        struct arm_smccc_res result;
        int psci_version= arm_smccc_smc(0x84000000,0,0,0,0,0,0,0,&result);
        printf("psci_version+: %x %lx %lx %lx %lx\n", psci_version, result.a0, result.a1, result.a2, result.a3);
#endif
}

I added the printf in order find what address range over
which the armstub80-gic code would see itself span for my
RPi4B based test context. The result was:

psci_version+: 2 2 0 800 100c

So:

(minor) version 2 (twice)
_start at 0x0
el3_exception_vectors at 0x800
loop at 0x100c (given my code additions).

I'll note that this investigative hack was enough of
a change that the RPi4B made it to a login prompt
and I logged in. There were problems, but I could
do some stuff. The failure mechanism for the
"extra" cores (APs) was different, reporting
very early on:

Starting CPU 1 (1)
Failed to start CPU 1 (1)
Starting CPU 2 (2)
Failed to start CPU 2 (2)
Starting CPU 3 (3)
Failed to start CPU 3 (3)



===
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)



More information about the freebsd-arm mailing list