Sat Mar 10 03:44:43 2018 UTC ()
Replace bus_dmamap_sync(9) op with a newer one taken from m68k/bus_dma.c.

This could fix memory corruption issue caused by PREREAD ops with regions
whose boundaries are not aligned at cacheline size.


(tsutsui)
diff -r1.59 -r1.60 src/sys/arch/atari/atari/bus.c

cvs diff -r1.59 -r1.60 src/sys/arch/atari/atari/bus.c (expand / switch to unified diff)

--- src/sys/arch/atari/atari/bus.c 2018/01/20 17:37:15 1.59
+++ src/sys/arch/atari/atari/bus.c 2018/03/10 03:44:43 1.60
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: bus.c,v 1.59 2018/01/20 17:37:15 tsutsui Exp $ */ 1/* $NetBSD: bus.c,v 1.60 2018/03/10 03:44:43 tsutsui Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center and by Chris G. Demetriou. 9 * NASA Ames Research Center and by Chris G. Demetriou.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -23,27 +23,27 @@ @@ -23,27 +23,27 @@
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE. 30 * POSSIBILITY OF SUCH DAMAGE.
31 */ 31 */
32 32
33#include "opt_m68k_arch.h" 33#include "opt_m68k_arch.h"
34 34
35#include <sys/cdefs.h> 35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.59 2018/01/20 17:37:15 tsutsui Exp $"); 36__KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.60 2018/03/10 03:44:43 tsutsui Exp $");
37 37
38#include <sys/param.h> 38#include <sys/param.h>
39#include <sys/systm.h> 39#include <sys/systm.h>
40#include <sys/extent.h> 40#include <sys/extent.h>
41#include <sys/malloc.h> 41#include <sys/malloc.h>
42#include <sys/mbuf.h> 42#include <sys/mbuf.h>
43#include <sys/proc.h> 43#include <sys/proc.h>
44 44
45#include <uvm/uvm.h> 45#include <uvm/uvm.h>
46 46
47#include <machine/cpu.h> 47#include <machine/cpu.h>
48#include <m68k/cacheops.h> 48#include <m68k/cacheops.h>
49#define _ATARI_BUS_DMA_PRIVATE 49#define _ATARI_BUS_DMA_PRIVATE
@@ -538,66 +538,223 @@ _bus_dmamap_unload(bus_dma_tag_t t, bus_ @@ -538,66 +538,223 @@ _bus_dmamap_unload(bus_dma_tag_t t, bus_
538 * No resources to free; just mark the mappings as 538 * No resources to free; just mark the mappings as
539 * invalid. 539 * invalid.
540 */ 540 */
541 map->dm_maxsegsz = map->_dm_maxmaxsegsz; 541 map->dm_maxsegsz = map->_dm_maxmaxsegsz;
542 map->dm_mapsize = 0; 542 map->dm_mapsize = 0;
543 map->dm_nsegs = 0; 543 map->dm_nsegs = 0;
544} 544}
545 545
546/* 546/*
547 * Common function for DMA map synchronization. May be called 547 * Common function for DMA map synchronization. May be called
548 * by bus-specific DMA map synchronization functions. 548 * by bus-specific DMA map synchronization functions.
549 */ 549 */
550void 550void
551_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t off, 551_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
552 bus_size_t len, int ops) 552 bus_size_t len, int ops)
553{ 553{
554#if defined(M68040) || defined(M68060) 554#if defined(M68040) || defined(M68060)
555 int i, pa_off, inc, seglen; 555 bus_addr_t p, e, ps, pe;
556 u_long pa, end_pa; 556 bus_size_t seglen;
 557 bus_dma_segment_t *seg;
 558 int i;
 559#endif
557 560
558 pa_off = t->_displacement; 561#if defined(M68020) || defined(M68030)
 562#if defined(M68040) || defined(M68060)
 563 if (cputype == CPU_68020 || cputype == CPU_68030)
 564#endif
 565 /* assume no L2 physical cache */
 566 return;
 567#endif
559 568
560 /* Flush granularity */ 569#if defined(M68040) || defined(M68060)
561 inc = (len > 1024) ? PAGE_SIZE : 16; 570 /* If the whole DMA map is uncached, do nothing. */
 571 if ((map->_dm_flags & BUS_DMA_COHERENT) != 0)
 572 return;
 573
 574 /* Short-circuit for unsupported `ops' */
 575 if ((ops & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) == 0)
 576 return;
562 577
563 for (i = 0; i < map->dm_nsegs && len > 0; i++) { 578 /*
564 if (map->dm_segs[i].ds_len <= off) { 579 * flush/purge the cache.
 580 */
 581 for (i = 0; i < map->dm_nsegs && len != 0; i++) {
 582 seg = &map->dm_segs[i];
 583 if (seg->ds_len <= offset) {
565 /* Segment irrelevant - before requested offset */ 584 /* Segment irrelevant - before requested offset */
566 off -= map->dm_segs[i].ds_len; 585 offset -= seg->ds_len;
567 continue; 586 continue;
568 } 587 }
569 seglen = map->dm_segs[i].ds_len - off; 588
 589 /*
 590 * Now at the first segment to sync; nail
 591 * each segment until we have exhausted the
 592 * length.
 593 */
 594 seglen = seg->ds_len - offset;
570 if (seglen > len) 595 if (seglen > len)
571 seglen = len; 596 seglen = len;
572 len -= seglen; 
573 pa = map->dm_segs[i].ds_addr + off - pa_off; 
574 end_pa = pa + seglen; 
575 597
576 if (inc == 16) { 598 ps = seg->ds_addr + offset;
577 pa &= ~15; 599 pe = ps + seglen;
578 while (pa < end_pa) { 600
579 DCFL(pa); 601 if (ops & BUS_DMASYNC_PREWRITE) {
580 pa += 16; 602 p = ps & ~CACHELINE_MASK;
 603 e = (pe + CACHELINE_MASK) & ~CACHELINE_MASK;
 604
 605 /* flush cacheline */
 606 while ((p < e) && (p & (CACHELINE_SIZE * 8 - 1)) != 0) {
 607 DCFL(p);
 608 p += CACHELINE_SIZE;
581 } 609 }
582 } else { 610
583 pa &= ~PGOFSET; 611 /* flush cachelines per 128bytes */
584 while (pa < end_pa) { 612 while ((p < e) && (p & PAGE_MASK) != 0) {
585 DCFP(pa); 613 DCFL(p);
586 pa += PAGE_SIZE; 614 p += CACHELINE_SIZE;
 615 DCFL(p);
 616 p += CACHELINE_SIZE;
 617 DCFL(p);
 618 p += CACHELINE_SIZE;
 619 DCFL(p);
 620 p += CACHELINE_SIZE;
 621 DCFL(p);
 622 p += CACHELINE_SIZE;
 623 DCFL(p);
 624 p += CACHELINE_SIZE;
 625 DCFL(p);
 626 p += CACHELINE_SIZE;
 627 DCFL(p);
 628 p += CACHELINE_SIZE;
 629 }
 630
 631 /* flush page */
 632 while (p + PAGE_SIZE <= e) {
 633 DCFP(p);
 634 p += PAGE_SIZE;
 635 }
 636
 637 /* flush cachelines per 128bytes */
 638 while (p + CACHELINE_SIZE * 8 <= e) {
 639 DCFL(p);
 640 p += CACHELINE_SIZE;
 641 DCFL(p);
 642 p += CACHELINE_SIZE;
 643 DCFL(p);
 644 p += CACHELINE_SIZE;
 645 DCFL(p);
 646 p += CACHELINE_SIZE;
 647 DCFL(p);
 648 p += CACHELINE_SIZE;
 649 DCFL(p);
 650 p += CACHELINE_SIZE;
 651 DCFL(p);
 652 p += CACHELINE_SIZE;
 653 DCFL(p);
 654 p += CACHELINE_SIZE;
 655 }
 656
 657 /* flush cacheline */
 658 while (p < e) {
 659 DCFL(p);
 660 p += CACHELINE_SIZE;
587 } 661 }
588 } 662 }
 663
 664 /*
 665 * Normally, the `PREREAD' flag instructs us to purge the
 666 * cache for the specified offset and length. However, if
 667 * the offset/length is not aligned to a cacheline boundary,
 668 * we may end up purging some legitimate data from the
 669 * start/end of the cache. In such a case, *flush* the
 670 * cachelines at the start and end of the required region.
 671 */
 672 else if (ops & BUS_DMASYNC_PREREAD) {
 673 /* flush cacheline on start boundary */
 674 if (ps & CACHELINE_MASK) {
 675 DCFL(ps & ~CACHELINE_MASK);
 676 }
 677
 678 p = (ps + CACHELINE_MASK) & ~CACHELINE_MASK;
 679 e = pe & ~CACHELINE_MASK;
 680
 681 /* purge cacheline */
 682 while ((p < e) && (p & (CACHELINE_SIZE * 8 - 1)) != 0) {
 683 DCPL(p);
 684 p += CACHELINE_SIZE;
 685 }
 686
 687 /* purge cachelines per 128bytes */
 688 while ((p < e) && (p & PAGE_MASK) != 0) {
 689 DCPL(p);
 690 p += CACHELINE_SIZE;
 691 DCPL(p);
 692 p += CACHELINE_SIZE;
 693 DCPL(p);
 694 p += CACHELINE_SIZE;
 695 DCPL(p);
 696 p += CACHELINE_SIZE;
 697 DCPL(p);
 698 p += CACHELINE_SIZE;
 699 DCPL(p);
 700 p += CACHELINE_SIZE;
 701 DCPL(p);
 702 p += CACHELINE_SIZE;
 703 DCPL(p);
 704 p += CACHELINE_SIZE;
 705 }
 706
 707 /* purge page */
 708 while (p + PAGE_SIZE <= e) {
 709 DCPP(p);
 710 p += PAGE_SIZE;
 711 }
 712
 713 /* purge cachelines per 128bytes */
 714 while (p + CACHELINE_SIZE * 8 <= e) {
 715 DCPL(p);
 716 p += CACHELINE_SIZE;
 717 DCPL(p);
 718 p += CACHELINE_SIZE;
 719 DCPL(p);
 720 p += CACHELINE_SIZE;
 721 DCPL(p);
 722 p += CACHELINE_SIZE;
 723 DCPL(p);
 724 p += CACHELINE_SIZE;
 725 DCPL(p);
 726 p += CACHELINE_SIZE;
 727 DCPL(p);
 728 p += CACHELINE_SIZE;
 729 DCPL(p);
 730 p += CACHELINE_SIZE;
 731 }
 732
 733 /* purge cacheline */
 734 while (p < e) {
 735 DCPL(p);
 736 p += CACHELINE_SIZE;
 737 }
 738
 739 /* flush cacheline on end boundary */
 740 if (p < pe) {
 741 DCFL(p);
 742 }
 743 }
 744 offset = 0;
 745 len -= seglen;
589 } 746 }
590#endif 747#endif /* defined(M68040) || defined(M68060) */
591} 748}
592 749
593/* 750/*
594 * Common function for DMA-safe memory allocation. May be called 751 * Common function for DMA-safe memory allocation. May be called
595 * by bus-specific DMA memory allocation functions. 752 * by bus-specific DMA memory allocation functions.
596 */ 753 */
597int 754int
598bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, 755bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
599 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, 756 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
600 int flags) 757 int flags)
601{ 758{
602 759
603 return bus_dmamem_alloc_range(t, size, alignment, boundary, 760 return bus_dmamem_alloc_range(t, size, alignment, boundary,