- LookupLevel start_lookup_level;
- int grain_size, stride;
- if (large_grain) { // 64 KB granule
- grain_size = 16;
- stride = grain_size - 3;
- if (tsz > grain_size + 2 * stride)
- start_lookup_level = L1;
- else if (tsz > grain_size + stride)
- start_lookup_level = L2;
- else
- start_lookup_level = L3;
- } else { // 4 KB granule
- grain_size = 12;
- stride = grain_size - 3;
- if (tsz > grain_size + 3 * stride)
- start_lookup_level = L0;
- else if (tsz > grain_size + 2 * stride)
- start_lookup_level = L1;
- else
- start_lookup_level = L2;
+ // See aarch64/translation/walk in Appendix G: ARMv8 Pseudocode Library
+ // in ARM DDI 0487A. These table values correspond to the cascading tests
+ // to compute the lookup level and are of the form
+ // (grain_size + N*stride), for N = {1, 2, 3}.
+ // A value of 64 will never succeed and a value of 0 will always succeed.
+ {
+ struct GrainMap {
+ GrainSize grain_size;
+ unsigned lookup_level_cutoff[MAX_LOOKUP_LEVELS];
+ };
+ static const GrainMap GM[] = {
+ { Grain4KB, { 39, 30, 0, 0 } },
+ { Grain16KB, { 47, 36, 25, 0 } },
+ { Grain64KB, { 64, 42, 29, 0 } }
+ };
+
+ const unsigned *lookup = NULL; // points to a lookup_level_cutoff
+
+ for (unsigned i = 0; i < 3; ++i) { // choose entry of GM[]
+ if (tg == GM[i].grain_size) {
+ lookup = GM[i].lookup_level_cutoff;
+ break;
+ }
+ }
+ assert(lookup);
+
+ for (int L = L0; L != MAX_LOOKUP_LEVELS; ++L) {
+ if (tsz > lookup[L]) {
+ start_lookup_level = (LookupLevel) L;
+ break;
+ }
+ }
+ panic_if(start_lookup_level == MAX_LOOKUP_LEVELS,
+ "Table walker couldn't find lookup level\n");