Re: framebuffer corruption due to overlapping stp instructions on arm64

Mikulas Patocka
2018-08-03T18:25:43Z

On Fri, 3 Aug 2018, Ard Biesheuvel wrote:

> (- 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?

Yes - it is caused by overlapping unaligned accesses inside memcpy. When I
put "dmb sy" between the overlapping accesses in
glibc/sysdeps/aarch64/memcpy.S, this program doesn't detect any memory
corruption.

> > 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++;
> > }
> > }
>