[coreboot] [RFC] SMM handling and resident coreboot

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Mon Jul 28 15:05:38 CEST 2008

On 28.07.2008 14:11, Stefan Reinauer wrote:
> Carl-Daniel Hailfinger wrote:
>>> Another alternative to keeping full coreboot around, would be to make
>>> the SMM handler self contained. This would mean, the SMM handler could
>>> not use coreboot's functions like printk_debug, pci_read_config32, it
>>> could not use the device tree, and it would become more complex, because
>>> for some information we have to reprobe the hardware, or parse the
>>> coreboot table.
>> From a v3 perspective, it might make sense to keep the SMI handler (if
>> it has limited size) in the boot block. That avoids any and all
>> requirements to keep code in RAM, thereby taking away the problem of
>> code relocation.
> I thought about this, too, but unfortunately it won't work. Two problems:
> * This still does not solve the problem for ACPI, and the coreboot
> table. That they survive is currently pure luck, and this is version
> agnostic, and starts causing trouble as soon as we think about scenarios
> like cleanly incorporating seabios.

Well, that problem should be solvable with e820 maps or coreboot tables
(and I thought it already is).

> * There is no heap nor data nor bss available, so we keep all
> disadvantages of keeping SMI self contained, except code duplication of
> maybe printk_debug() and pci_[read|write]_config[8|16|32] and/or
> possibly their enhanced PCIe versions. Considering that in a productive
> system printk falls away, making the SMM handler self contained is a
> considerable option.

Fair enough. So do we want a separate stage_SMM or should it be part of
stage2? The completely standalone SMM solution is also possible, but I
guess that choice only makes sense if the stuff to be done in SMM mode
is mostly independent of anything in the bootblock.

>>> In the case of the SMM handler, this would also confine us, because the
>>> actual SMI# handling code (written in C) would not be shared between
>>> CPUs but has to be duplicated for every CPU core. However, my current
>>> approach only keeps a very small amount of code per CPU, that is just
>>> enough to enter gcc compiled functions and return from them, cleanly.
>> AFAIK factory BIOS SMM handlers have the ability to lock down the memory
>> segment they are using, protecting them from accidental or deliberate
>> tampering by the OS (which could lead to interesting security issues).
>> Can we do that even if the handler is "somewhere" in RAM?
> Not really. There are certain memory regions that can be locked. But the
> smi_handler() C function does not live there, currently. If we want to
> lock out the OS, we need to go down the route of being self-contained.

I believe that is the one sticking point which forces us to use the
self-contained variant.

>>> One of the questions in my mind is: where should we put the coreboot
>>> image, if we want to keep it around?
>>> A little excerpt from coreboot v2:
>>> I know the problem of where to put coreboot has been thought about
>>> before, elfboot() relocates coreboot to another place when loading an
>>> ELF binary that demands the space where coreboot lives:
>>>  * coreboot tries to load a segment and finds out, that it is in the way.
>>>  * coreboot copies itself to a new position
>>>  * coreboot jumps into the assembler handler in jmp_to_elf_entry at the
>>> new position
>>>  * coreboot tries to start the ELF binary.
>>>  * If it fails, it overwrites the loaded ELF binary by copying itself
>>> back and jumping to the original position.
>>> This is quite an interesting concept, but it also makes clear that the
>>> ram portion of coreboot itself ("stage2") can not be relocated freely in
>>> memory. Yet.
>> Please see my other mail in this thread about possible problems with a
>> relocatable stage2. Besides that, we'd need a way in v3 to tag a LAR
>> member as PIC (sort of done for the special case of XIP in initram) and
>> new code to figure out a good load address during run time.
> So you are saying we can't make stage2 relocatable because noone else
> did before, or because we would have to write new code? I think both are
> acceptable risks given that v3 has a user base of exactly zero and is
> not in the shape to carry a port to any non-embedded systems anyways.

Actually, there are two problems^W challenges with relocatable code in v3:
- Calls from relocatable code (initram etc.) to other chunks of code
like (bootblock). GCC has no mode to emit calls the way we want and
future gcc versions or stronger optimizations will possibly make our
current indirect calls unworkable. I have a mostly finished,
Segher-approved solution for that problem on my disk. (Needs to be
cleaned up before sending.)
- PIC data segment funkiness. IIRC Segher once said that the way we
compile and link initram works only by accident and because we don't
have any (global) variables outside the stack. It had something to do
with data segment locations being treated as relative to code locations.
I'm fuzzy on the details, though.

>>> Since we know how big our RAM is when we copy coreboot to RAM, I suggest
>>> that we copy coreboot to the end of memory and run it from there. It is
>>> a pretty good assumption that no payload will require that space. During
>>> memory map creation, we just reserve 256k at the upper end, and we're good.  
>> Hm... I assume end of memory is "end of memory below 4G". If we want to
>> avoid conflicts with mapped memory areas of extension cards, stage2 code
>> has to be loaded twice: Once before setting up extension cards (load
>> stage2 to above 1M or other failsafe location) and after setting up
>> extension cards (load stage2 to end of memory below 4G and below
>> extension card space). That's not exactly the nicest code flow I can
>> think of.
> Yes, I guess I was referring to anything that fits in 32bit address
> space, as there is no coreboot port utilizing 64bit addressing modes.
> End of memory is end of _memory_, not end of address space. The memory
> hole for PCI devices is hard coded in coreboot, and most chipsets allow
> to remap memory "under" the hole to above 4G.

The only thing I've been able to find in v2 and v3 about memory holes is
that they are hardcoded to 1 GB size for GeodeLX and build-time
configurable for K8 with a default of 1GB size. That's pretty
interesting if someone has 2 graphics cards with 512MB each and another
extension card with a few kB.
It would be nice if you could point me to other information sources I
may have overlooked.



More information about the coreboot mailing list