Re: framebuffer corruption due to overlapping stp instructions on arm64

Ard Biesheuvel
2018-08-03T17:33:27Z

(- libc-alpha)

On 3 August 2018 at 19:09, Mikulas Patocka <mpatocka@redhat.com> wrote:
>
>
> On Fri, 3 Aug 2018, Will Deacon wrote:
>
>> On Fri, Aug 03, 2018 at 09:16:39AM +0200, Ard Biesheuvel wrote:
>> > On 3 August 2018 at 08:35, Mikulas Patocka <mpatocka@redhat.com> wrote:
>> > >
>> > >
>> > > On Thu, 2 Aug 2018, Matt Sealey wrote:
>> > >
>> > >> The easiest explanation for this would be that the memory isn?t mapped
>> > >> correctly. You can?t use PCIe memory spaces with anything other than
>> > >> Device-nGnRE or stricter mappings. That?s just differences between the
>> > >> AMBA and PCIe (posted/unposted) memory models.
>> >
>> > Whoa hold on there.
>> >
>> > Are you saying we cannot have PCIe BAR windows with memory semantics on ARM?
>> >
>> > Most accelerated graphics drivers rely heavily on the ability to map
>> > the VRAM normal-non-cacheable (ioremap_wc, basically), and treat it as
>> > ordinary memory.
>>
>> Yeah, I'd expect framebuffers to be mapped as normal NC. That should be
>> fine for prefetchable BARs, no?
>>
>> Will
>
> So - why does it corrupt data then? I've created this program that
> reproduces the data corruption quicky. If I run it on /dev/fb0, I get an
> instant failure. Sometimes a few bytes are not written, sometimes a few
> bytes are written with a value that should be 16 bytes apart.
>

Are we still talking about overlapping unaligned accesses here? Or do
you see other failures as well?

> I tried to run it on system RAM mapped with the NC attribute and I didn't
> get any corruption - that suggests the the bug may be in the PCIE
> subsystem.
>
> Jingoo Han and Joao Pinto are maintainers for the designware PCIE
> controllers. Could you suggest why does the controller corrupt data when
> writing to videoram? Are there any tricks that could be tried to work
> around the corruption?
>
> Mikulas
>
>
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <fcntl.h>
> #include <unistd.h>
> #include <sys/mman.h>
>
> #define LEN 256
> #define PRINT_STRIDE 0x20
>
> static unsigned char data[LEN];
> static unsigned char val = 0;
>
> static unsigned char prev_data[LEN];
>
> static unsigned char map_copy[LEN];
>
> int main(int argc, char *argv[])
> {
> unsigned long n = 0;
> int h;
> unsigned char *map;
> unsigned start, end, i;
>
> if (argc < 2) fprintf(stderr, "argc\n"), exit(1);
> if (argc >= 4) srandom(atoll(argv[3]));
> h = open(argv[1], O_RDWR | O_DSYNC);
> if (h == -1) perror("open"), exit(1);
> map = mmap(NULL, LEN, PROT_READ | PROT_WRITE, MAP_SHARED, h, argc >= 3 ? strtoull(argv[2], NULL, 16) : 0);
> if (map == MAP_FAILED) perror("mmap"), exit(1);
>
> memset(data, 0, LEN);
> memset(prev_data, 0, LEN);
> memset(map, 0, LEN);
>
> sleep(1);
>
> while (1) {
> start = (unsigned)random() % (LEN + 1);
> end = (unsigned)random() % (LEN + 1);
> if (start > end)
> continue;
> for (i = start; i < end; i++)
> data[i] = val++;
> memcpy(map + start, data + start, end - start);
> if (memcmp(map, data, LEN)) {
> unsigned j;
> memcpy(map_copy, map, LEN);
> fprintf(stderr, "mismatch after %lu loops!\n", n);
> fprintf(stderr, "last copied range: 0x%x - 0x%x (0x%x)\n", start, end, (unsigned)(end - start));
> for (j = 0; j < LEN; j += PRINT_STRIDE) {
> fprintf(stderr, "p[%03x]", j);
> for (i = j; i < j + PRINT_STRIDE && i < LEN; i++)
> fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", prev_data[i]);
> fprintf(stderr, "\n");
> fprintf(stderr, "d[%03x]", j);
> for (i = j; i < j + PRINT_STRIDE && i < LEN; i++)
> fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", data[i]);
> fprintf(stderr, "\n");
> fprintf(stderr, "m[%03x]", j);
> for (i = j; i < j + PRINT_STRIDE && i < LEN; i++)
> fprintf(stderr, " %s%s%02x\e[0m", !(i % 4) ? " " : "", data[i] != map_copy[i] ? "\e[31m" : "", map_copy[i]);
> fprintf(stderr, "\n\n");
> }
> exit(1);
> }
> memcpy(prev_data, data, LEN);
> n++;
> }
> }