[U-Boot] Virtual addresses, u-boot, and the MMU

Wolfgang Denk
2009-09-01T19:21:23Z

Dear "J. William Campbell",

In message <4A9D5EF2.4030307@comcast.net> you wrote:
> I have followed the recent discussions about problems in the CFI
> driver caused by the need to change the attributes of the address at
> which the flash is mapped. This discussion has raised some questions in
> my mind regarding the assumptions u-boot makes regarding the behavior of
> the addresses used in the code. I am writing this message for comments
> that may correct any mis-understandings I have. First, the addresses
> used by the u-boot program to reference memory and code are all
> "virtual" addresses (VA) because they go through the MMU to become a
> physical address(PA). If there is no MMU, the virtual address and the
> physical address are identical.

Even if there is a MMU, we keep it "switched off" on most systems, or
otherwise set it up in such a way that there is still a 1:1 mapping,
i. e. the virtual address and physical address are identical, too.

There have been several discussions concerning this topic on IRC
(#u-boot at freenode); I'll try to summarize these here - not sure
though if I don't miss anything: please feel free to complement what
might be missing.

[Times are MET/MEST]

Nov 20, 2008:

[19:40:03] galak: do we think of nand->IO_ADDR_R as a physical or virtual addr?
[19:40:10] scottwood: Wouldn't it need to change on Linux too?
[19:40:42] galak: don't know do we does drivers/mtd/nand/fsl_elbc_nand.c look the same in linux?
[19:40:48] scottwood: IO_ADDR_R is virtual
[19:41:01] scottwood: So it needs to change with virt != phys
[19:41:51] galak: ok, so this loop in board_nand_init():
[19:41:51] galak: for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) {
[19:41:51] galak: br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br);
[19:41:51] galak: or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or);
[19:41:51] galak:
[19:41:52] galak: if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM &&
[19:41:54] galak: (br & or & BR_BA) == nand->IO_ADDR_R)
[19:41:56] galak: break;
[19:41:58] galak: }
[19:42:24] galak: use comparing a virt (IO_ADDR_R) with physical (br & or & BR_BA)
[19:43:25] scottwood: Right, it assumess identity mapping. We'll need some way of finding the physical address now.
[19:45:06] scottwood: Does eLBC just ignore the upper 4 bits of the physical address, and rely on LAWs for that?
[19:45:16] galak: yep
[19:45:31] galak: which makes this slightly more annoying
[19:47:21] galak: we could have board code implement a function that deals with the mapping (given IO_ADDR_R, it hands bank the bank #)
[19:47:36] scottwood: I'd rather not make it board-specific.
[19:47:56] scottwood: Is there a general virt-to-phys function in u-boot?
[19:49:10] galak: nope
[19:49:27] scottwood: There probably should be.
[19:49:38] galak: agreed, but that a huge overhaul
[19:50:29] scottwood: How many other platforms have virt != phys?
[19:50:56] galak: not sure, probably none
[19:51:10] scottwood: So virt_to_phys could do tlbsx on book-e and return the argument on everything else.
[19:51:36] galak: yeah, we could do that
[19:52:23] galak: we should probably have it walk BATs on classic
[19:52:33] scottwood: yeah
[19:53:57] galak: what do you think the API for virt_to_phys() looks like? (how to report error if no mapping exists?)
[19:54:54] scottwood: Could return ~0, or have the physical address returned via pointer.
[19:57:32] galak: ok..will work something up
[19:58:17] scottwood: thanks

Nov 26, 2008:

[20:09:43] beckyb: it's the whole virtual vs physical address question
[20:10:04] beckyb: when I did the 36b stuff that's in the tree now, I went for the minimally invasive approach
[20:10:27] beckyb: so, at the moment, all the command-line stuff takes a *virtual* address as an argument
[20:10:41] beckyb: I'm wondering if that's really what we want
[20:17:18] beckyb: wdenk_: The whole issue has come up because with galak's map_physmem patches, we have to actually start distinguishing between the 2 kinds of addresses inside u-boot
[20:17:50] beckyb: right now, the 36-bit code is taking advantage of the fact that u-boot doesn't know the difference
[20:18:20] beckyb: so the *physical* address only really exists right now in the MMU mapping
[20:18:33] beckyb: and in a few other places that actually care about the PA
[20:18:39] beckyb: I'll stop babbling now
[20:20:39] wdenk_: beckyb: I have to admit that I don't see the immediate problem yet.
[20:20:56] beckyb: wdenk_: OK, I'll babble some more
[20:21:00] wdenk_: beckyb: So far, everybody seems to be happy with using virtual addresses.
[20:21:01] beckyb: Let me use a concrete example
[20:21:14] beckyb: wdenk_: and I'm *fine* if we stick with that
[20:21:26] beckyb: I just want to be sure that's what we really want
[20:21:54] beckyb: I've been working on the flash code, which stores the physical sector address in a structure, then calls map_physmem to get a va *most* of the time it uses it
[20:22:16] beckyb: I've corrected all the places where it treats a PA as a pointer, no problem
[20:22:33] beckyb: but the "fli" command right now displays the physical address
[20:22:48] beckyb: if we're sticking with VAs on the command line, I'd like to change "fli" to display the VAs
[20:23:00] beckyb: so that the cp commands and fli take the same addrs
[20:23:06] wdenk_: Hm... I can't tell for sure what we want either.
[20:23:14] beckyb: it's a tough problem
[20:23:25] beckyb: using the VA in "fli" is a much less invasive solution
[20:23:44] wdenk_: But I agree that in such cases where it makes a difference, we should agree to use one consistent set of addresses.
[20:24:05] beckyb: if we go to using the "pa" on the command line, the changes get fairly invasive
[20:24:21] beckyb: as we have to go to phys_addr_t and strtoull
[20:24:44] beckyb: using the va will work *as long as u-boot doesn't start doing paging*
[20:25:03] beckyb: because using the VA assumes that mapping from VA to PA exists
[20:25:24] beckyb: otoh, if we use the PA, we have to change all the commands to call map_physmem to get a VA before doing anything
[20:25:25] wdenk_: Right. And I guess we can push this point at least out of this decade
[20:25:36] beckyb: sure, which is why I went with the VA for now
[20:25:47] beckyb: but before I made any more code changes, I wanted to talk with you about it
[20:26:20] wdenk_: I think we should ask this again on the ML - I'm easily overlooking some aspects here.
[20:26:36] beckyb: ok, I'll craft a note and send it out
[20:26:41] beckyb: thanks
[20:26:44] wdenk_: My gut feeling is that VA's are just fine. Hey, that's still a boot loader.
[20:26:51] beckyb: exactly
[20:27:22] beckyb: I'll probably word the note as "we're going with VAs on the command line unless somebody gives me a very good reason not to "
[20:27:23] beckyb:
[20:27:34] wdenk_: But I also see that we might need to extend some commands to operate on the PA's as well - in some cases you really want to be able to "md" or "mw" directly to some PCI addresses or similar.
[20:27:43] beckyb: right, that makes sense
[20:28:01] beckyb: at the least, we could start with a translation command
[20:28:19] wdenk_: good idea, that's even less intrusive.
[20:28:22] beckyb: that gives you the PA for a VA, so you can invoke the commands correctly. It's a quick and easy fix
[20:28:31] wdenk_: But then, it doesn't solve the problem.
[20:28:42] beckyb: nope, the user still has to be aware
[20:28:52] wdenk_: Assume you have a 32 bit system with 36 bit PA's.
[20:28:52] beckyb: The problem is, we don't really know what the user is thinking now
[20:29:07] beckyb: which I do
[20:29:10] wdenk_: How do you enter a PA then?
[20:29:40] beckyb: the translate command would have to be able to parse that, but all the other commands could still take the VA
[20:30:14] wdenk_: We have this case with the 440SPe "katmai" board with 4 GB of RAM.
[20:30:52] beckyb: right, and there are some limitations there currently
[20:31:04] beckyb: like you can't "mtest" all of RAM, because you can't map it all in
[20:31:11] beckyb: I haven't fixed that yet
[20:31:44] beckyb: but the rearranging of the memory map I did will make it easier to deal with on 8641
[20:31:48] wdenk_: "mtest" is the smallest problem. You always can run it on a documented range only.
[20:31:59] beckyb: sure, it's just an example
[20:32:51] beckyb: the fundamental point is, you're limited to accessing what you can map in 32 bits, unless we start making wholesale changes to u-boot
[20:33:10] beckyb: because software sees things at VAs
[20:35:17] wdenk_: So we agree to use all VA's in U-Boot, plus initially we will add an "xlat" command, and eventually (where and when needed) we might extend commands to recognize and handle PA's (something like "md xxxx" for VA versus "md .xxxx" for PA or similar) ?
[20:35:39] beckyb: something like that, yeah, or maybe md -p xxxx
[20:36:23] beckyb: and we need to start watching new code coming in very carefully, to start weaning people off this whole VA=PA assumption
[20:36:38] beckyb: for common stuff, anyway
[20:36:49] wdenk_: beckyb: I think it might be better to ad a marker to the address argument in case we should have commands where we have to pass more than one address and want to use different ones - like "cp" from VA to PA or vice versa.
[20:36:58] beckyb: ah, right
[20:37:10] beckyb: do any other u-boot commands do this?
[20:37:41] wdenk_: take more than one address? well, let me think.... bootm does.
[20:37:48] wdenk_: cmp
[20:37:54] beckyb: no, I mean that have some sort of marker in an arg
[20:38:04] beckyb: sorry, I wasn't clear
[20:38:41] wdenk_: I'm not sure. At least we do this in the command names - like "cp" versus "cp.b"
[20:39:00] beckyb: true..... so what if we had the marker be p.
[20:39:17] beckyb: The "." by itself is going to screw me up
[20:39:25] wdenk_: ".p" then?
[20:39:38] wdenk_: md feeddeadbeef.p
[20:40:01] beckyb: ah, it's at the end now. Sure, works for me. And we should also accept .v for completeness
[20:40:43] wdenk_: We can also use a "p." / "v." prefix - I'm not sure if I have any preferences yet
[20:41:12] beckyb: yeah, we can work that out later I'm sure the list will have preferences!
[20:41:59] beckyb: I'll try to get something out to the list this afternoon

Becky then posted the summary of this discussion here:

http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/50705

Note that there was a general agreement among those who raised their
voices.

> The "normal", or legacy,policy for u-boot is to arrange a memory
> map such that all physical addresses are mapped to some virtual address.
> Originally, the mapping were such that the VA was actually == the PA,
> but today on some CPUs, this is not possible. When the size of the
> physical address space exceeds the size of the virtual address space,
> the VA may not =- the PA numerically, but there is a one-to-one
> correspondence. It MAY also acceptable to map the same PA so that it
> appears more than once in the address space (VA), but if this is done,

This may or may not be possible. It may even make sense or be needed
on some systems, and it may be impossible to do on others.

In any case, I think we should be careful not to mix things: what we
are discussing here are address mappings. What we are not discussing
is specific memory properties like being cached/uncached, guarded/
non-guarded, etc.

Such properties are important, too, but they need to get handled
through a separate interface.

> Becky Bruce "re-wrote the driver to use VAs instead of PAs." I am
> not exactly sure what this means, but I assume it meant allowing the VA
> referencing the flash
> to be distinct from the PA where the flash "lives" (and may require 36
> bits on a PPC system to represent the PA). Does the driver re-map

I think the information provided above sheds more light on this.

> portions of the flash in order to access them? If the flash is really
> large, I can certainly see a need to do so. However, I assume on "medium
> size" flashes, it does not need to remap. In that case, don't all
> references just go through the MMU and get translated? The VA != PA, but
> from the point of view of u-boot, the VA is the only address that
> matters. The AVR32 certainly does not map flash dynamically, so it would
> not matter on that CPU.

OK.

> The issue with the CFI driver on the AVR32 is that it needs to
> disable cache on the address space of the flash memory when it is
> writing to the flash. This apparently is not trivial to do, but there is

Actually this is not specific to the AVR32, and so far most systems
simply do not enable caches at all on the flash memory regions. I
understand why the AVR32 solution is interesting, and I think, when
we try to find a solution for this we should use this chance to find
a solution that also allows other systems to turn on caches on the
flash memory - things like loading the Linux kernel or ramdisk images
etc. will benefit from that.

> a second mapping that does have the cache off. Wolfgang has recommended
> the creation of a function to turn off the cache for the flash area, and
> also (presumably) one to turn the flash back on when the write is
> complete. Haavard has at present a function that returns an alternate

Right. My rationale for this was the wish to provide such a solution
for all systems, including those that don;t allow to have several
mappings (with different attributes) for the same physical memory
region.

> address with the cache already off that addresses the same memory. This
> wouldn't cause a problem if the mapping happened immediately before the
> actual copy operation took place and was used for nothing else. However,
> if it happens early on in the driver, the address will not match the
> structure set up by the rest of the flash code using the non-translated
> address.

And this method will not work on all systems that don't support such
multiple mappings.

> Therefore, I have the following questions: If the map_physmem()
> macro is removed from the driver on the AVR32, does the driver work if
> it is told that the flash PA=VA = the un-cached address? If not, why

In the current state the situation PA=VA=un-cached is the default on
almost all systems, and is workign fine there.

> not? Shouldn't this be just like any CFI on an un-cached PPC address?
> The driver will be somewhat slower reading but otherwise it should work.
> If/when it does work, couldn't a map_in_cache() macro be placed directly
> in front of the read code that copies data from flash to other buffers.

While there are specific routines to "write" to the flash (init,
erase, write), there is no specific code to "read" from flash.
Reading is allowed everywhere by just performing load instructions
from this memory area. The CFI driver (nor any other flash driver) is
needed or involved to do that. That's the whole big advantage of NOR
flash (which makes it _memory_) over storage devices like NAND etc.
(which are _not_ memory).

You would have to add this macro everywhere - on anything that
accesses memory. All commands that take memory addresses either
directly or indirectly, each and every load instruction. That's not
practical. [OK, you could probably set up the MMU to trap on read
accesses on such a memory reagion, but that would not exactly be
simpler either.]

> The macro would return an address of the same data referenced through a
> cached address if it exists. This address would go nowhere else and
> never be stored anywhere. This would speed up the copy operation for
> situations where it matters, and is applicable to all platforms that can
> do such a thing. The most general solution would be a call to
> map_in_cache/map_in_not_cache for both reads and writes in the CFI

No. The CFI driver is not used for read operations, so this does not
work.

> driver. These routines would return a "substitute" address (or the same
> input one), and may actually add another mapping dynamically, use a
> pre-existing appropriate mapping, just turn on/turn off data cache
> globally, or do nothing). At the end of the copy, map_restore() would
> put the map back By default, the assumption would be that the flash is
> not cached and the macros do nothing. Sounds simple to me, what have I
> overlooked?

The only thing you overlooked in my opinion is that read accesses to
NOR flash are plain memory accesses that are not handled by the CFI
or any other driver.

Best regards,

Wolfgang Denk

--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
All repairs tend to destroy the structure, to increase the entropy
and disorder of the system. Less and less effort is spent on fixing
original design flaws; more and more is spent on fixing flaws intro-
duced by earlier fixes. - Fred Brooks, "The Mythical Man Month"