January 27, 2017

What is where?

I was going to entitle this section "ram" but decided this would be more informative. What I am aiming to do here is to give a layout of important objects in RAM.

The Orange Pi PC and the PC Plus both have 1G of ram. Consider that the ARM in the H3 chip is a 32 bit device, so it has a 4G address space. We can ponder the four 1G sections as follows:

0x00000000 - 0x3fffffff -- sparse, SRAM at 0, IO all lives in here
0x40000000 - 0x7fffffff -- 1G of RAM
0x80000000 - 0xbfffffff -- another 1G of RAM in some other Orange Pi boards
0xc0000000 - 0xffffffff -- sparse -- the bootrom lives here.
Our first concern with RAM is to make sure we don't have U-boot load our image on top of itself or anything important (like the U-boot stack, or page tables).

U-boot gets loaded at 0x4A000000, much to my surprise. The image I am currently using is 425,906 bytes in size, so we can round up and figure that U-boot uses 512K, so:

U-boot image:  0x4a000000 - 0x4a07ffff
We can of course freely reclaim this space once we have our image loaded and running.

I am loading Kyu at 0x42000000 and the current image is 149,434 bytes in size, so round that up to 256K and we have:

Kyu image:  0x42000000 - 0x4203ffff
Note that this leaves a 32M gap at the start of ram. We can of course just pick this up in our memory allocator and then dole it out later. Maybe we should just load Kyu to 0x40000000 instead?

U-boot stack

When we start running, we inherit the U-boot stack at 0x79f34a48.

U-boot MMU setup

We can read the "system control register" via
mrc p15, 0, r0, c1, c0, 0
This yields 0x00C5187D, some notable bits here are:
0x1000 = bit 12 set enables I-cache
0x0004 = bit 2 set enables D-cache and unified cache
0x0002 = bit 1 clear allows address fault exceptions
0x0001 = bit 0 set enables the MMU
We can have two sets of translation tables, as controlled by the TTBCR
MRC p15, 0, , c2, c0, 2 ; Read TTBCR
This reads as zero (0x00000000), which is the reset value, so N=0 and the second set of translation tables that would be give by TTBR1 are never used, TTBR0 is the whole game. boundary between The MMU base register 0 (TTBR0) can be read via
mrc p15, 0, r0, c2, c0, 0
This yields 0x7Dff0059. Note that the low 14 bits should be masked off to obtain the base address (which is thus 0x7dff0000), the lower bits include settings to determine the cacheability of the page tables. See page 1730 or the ARMv7 Architecture Reference Manual.
d 0x7dff0000 8
7dff0000  00000c12 00100c12 00200c12 00300c12 
7dff0010  00400c12 00500c12 00600c12 00700c12 
7dff0020  00800c12 00900c12 00a00c12 00b00c12 
7dff0030  00c00c12 00d00c12 00e00c12 00f00c12 
7dff0040  01000c12 01100c12 01200c12 01300c12 
7dff0050  01400c12 01500c12 01600c12 01700c12 
7dff0060  01800c12 01900c12 01a00c12 01b00c12 
7dff0070  01c00c12 01d00c12 01e00c12 01f00c12 

The above is a dump of the first part of the translation table.
These are all "first level descriptors".
The low two bits are "2", which indicates that each entry
describes a 1M "section".
The upper 12 bits (3 hex digits) give the section base.
The lower 20 bits (here always 00c12) have control bits,
not all of which are used (and should be zero).

To map a 4G address space using 1M sections, we need 4096 entries (each of which is 4 bytes), so the table is 16K in size. So the translation table lives at:

MMU translation table:  0x7dff0000 - 0x7dff3fff
No telling why U-Boot put it here, leaving a 32M unused area (and then some) at the end of RAM.

I wrote a short ruby program to analyze a full dump of the translation tables. The output for the Orange Pi looks like this:

00000000 -- 0c12
40000000 -- 0c1e
80000000 -- 0c12

This shows the start of each region where the control bits change, so we have:

00000000 - 3fffffff  -- 0c12 (1G uncached)
40000000 - 7fffffff  -- 0c1e (1G cached)
80000000 - ffffffff  -- 0c12 (2G uncached)
The difference between 0xc12 and 0xc1e is that the C and B bits are set in the latter. The C bit enables caching (for the D cache) and the B bit enables write buffering. This is only necessary and important if the D cache is enabled. In that case ram should be cached, but IO addresses must not be.

Several observations can be made.

  1. The cached region could be extended to 2G as preemptive support for those Orange Pi boards with 2G of ram.
  2. The Orange Pi has static ram at address zero. To catch zero pointer references, we could set the low two bits to 0 for this segment, indicating that this is an invalid address. Note that the BBB has no ram at address zero and generates faults of this sort in any event.
  3. We could consider some uncached ram for various purposes (spin locks, network buffers, anything that is a DMA source or target).

U-Boot and MMU initialization


Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org