summaryrefslogtreecommitdiffstats
path: root/memtestEDK/Memtest/Test1/test.c
blob: 6b0403c995f8001925f528ddd81199ef8ee2d9bf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>

#include "test.h"
#include "memoryMap.h"

extern EFI_SYSTEM_TABLE *gST;

typedef unsigned long ulong;

#define ASSERT(n) do {                   \
    if (!(n)) {                          \
        gST->ConOut->OutputString(gST->ConOut, L"ASSERT FAIL\n"); \
    } } while(0)

volatile int segs; // TODO compute segs in main.c
volatile int 	bail; // TODO compute in main.c


#define LINE_PAT      5
#define COL_PAT		41
#define SPINSZ_DWORDS	0x4000000	/* 256 MB; units are dwords (32-bit words) */
#define BAILR		if (bail) return;



typedef void(*segment_fn)(ulong* start,  // start address
                          ulong len_dw,  // length of segment in dwords
                          const void* ctx);  // any context data needed

static const void* const nullptr = 0x0;
int me = 0; // my_cpu_num in main.c


/* Call segment_fn() for each up-to-SPINSZ segment between
 * 'start' and 'end'.
 */
void foreach_segment
(ulong* start, ulong* end,
 int me, const void* ctx, segment_fn func) {

    ASSERT(start < end);

    // Confirm 'start' points to an even dword, and 'end'
    // should point to an odd dword
    ASSERT(0   == (((ulong)start) & 0x7));
    ASSERT(0x4 == (((ulong)end)   & 0x7));

    // 'end' may be exactly 0xfffffffc, right at the 4GB boundary.
    //
    // To avoid overflow in our loop tests and length calculations,
    // use dword indices (the '_dw' vars) to avoid overflows.
    ulong start_dw = ((ulong)start) >> 2;
    ulong   end_dw = ((ulong)  end) >> 2;

    // end is always xxxxxffc, but increment end_dw to an
    // address beyond the segment for easier boundary calculations.
    ++end_dw;

    ulong seg_dw     = start_dw;
    ulong seg_end_dw = start_dw;

    int done = 0;
    do {
        // do_tick(me);
        { BAILR }

        // ensure no overflow
        ASSERT((seg_end_dw + SPINSZ_DWORDS) > seg_end_dw);
        seg_end_dw += SPINSZ_DWORDS;

        if (seg_end_dw >= end_dw) {
            seg_end_dw = end_dw;
            done++;
        }
        if (seg_dw == seg_end_dw) {
            break;
        }

        ASSERT(((ulong)seg_end_dw) <= 0x40000000);
        ASSERT(seg_end_dw > seg_dw);
        ulong seg_len_dw = seg_end_dw - seg_dw;

        func((ulong*)(seg_dw << 2), seg_len_dw, ctx);

        seg_dw = seg_end_dw;
    } while (!done);
}

/* Calls segment_fn() for each segment in vv->map.
 *
 * Does not slice by CPU number, so it covers the entire memory.
 * Contrast to sliced_foreach_segment().
 */
STATIC void unsliced_foreach_segment
(const void* ctx, int me, segment_fn func) {
    int j;
    for (j=0; j<segs; j++) {
        foreach_segment(vv->map[j].start,
                        vv->map[j].end,
                        me, ctx, func);
    }
}
STATIC void addr_tst1_seg(ulong* restrict buf,
                          ulong len_dw, const void* unused) {
    // Within each segment:
    //  - choose a low dword offset 'off'
    //  - write pat to *off
    //  - write ~pat to addresses that are above off by
    //    1, 2, 4, ... dwords up to the top of the segment. None
    //    should alias to the original dword.
    //  - write ~pat to addresses that are below off by
    //    1, 2, 4, etc dwords, down to the start of the segment. None
    //    should alias to the original dword. If adding a given offset
    //    doesn't produce a single bit address flip (because it produced
    //    a carry) subtracting the same offset should give a single bit flip.
    //  - repeat this, moving off ahead in increments of 1MB;
    //    this covers address bits within physical memory banks, we hope?

    ulong pat;
    int k;

    for (pat=0x5555aaaa, k=0; k<2; k++) {
    	Print(L"Pat: %u\n");
        // hprint(LINE_PAT, COL_PAT, pat);

        for (ulong off_dw = 0; off_dw < len_dw; off_dw += (1 << 18)) {
            buf[off_dw] = pat;
            pat = ~pat;

            for (ulong more_off_dw = 1; off_dw + more_off_dw < len_dw;
                 more_off_dw = more_off_dw << 1) {
                ASSERT(more_off_dw);  // it should never get to zero
                buf[off_dw + more_off_dw] = pat;
                //ulong bad;
          /*      if ((bad = buf[off_dw]) != ~pat) {
                    ad_err1(buf + off_dw,
                            buf + off_dw + more_off_dw,
                            bad, ~pat);
                    break;
                }*/
            }
            for (ulong more_off_dw = 1; off_dw > more_off_dw;
                 more_off_dw = more_off_dw << 1) {
                ASSERT(more_off_dw);  // it should never get to zero
                buf[off_dw - more_off_dw] = pat;
                //ulong bad;
              /*  if ((bad = buf[off_dw]) != ~pat) {
                    ad_err1(buf + off_dw,
                            buf + off_dw - more_off_dw,
                            bad, ~pat);
                    break;
                }*/
            }
        }
    }
}

/*
 * Memory address test, walking ones
 */
void addr_tst1(int me) // TODO TEST STARTS HERE
{
    unsliced_foreach_segment(nullptr, me, addr_tst1_seg);
}