Signed-off-by: Maximilian Brune <maximilian.brune@9elements.com> Change-Id: I97cd3030cd660a86295257caf723c9f517bed146 Reviewed-on: https://review.coreboot.org/c/coreboot/+/76383 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin L Roth <gaumless@gmail.com>
		
			
				
	
	
		
			82 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Relocatable Modules (rmodules)
 | |
| 
 | |
| Relocatable modules are currently only used on x86.  Relocatable
 | |
| modules are executables. Exectuables which can be executed anywhere in
 | |
| memory. Anywhere means that the module does not need to be executed
 | |
| at a defined memory address which is known at build/link time. For
 | |
| coreboot stages like bootblock and romstage it is known at build
 | |
| time at which addresses they are executed.  For some exectuables it
 | |
| is however not known at which specific address they are executed in
 | |
| runtime (for example postcar and ramstage). Relocateable modules
 | |
| usually allocate the space for the modules just before they are
 | |
| supposed to be executed. After enough space is allocated, CBMEM will
 | |
| return the location of the allocated space. Now the relocation can be
 | |
| done by fixing up all relocation entries in the relocatable module
 | |
| based on the location of the binary (which was returned by CBMEM
 | |
| at runtime).
 | |
| 
 | |
| # Implementation Details
 | |
| 
 | |
| ## build time
 | |
| 
 | |
| At build time the rmodtool (util/cbfstool/rmodtool.c) is used to
 | |
| create relocatable modules. The rmodtool basically takes an ELF
 | |
| file as an input and writes an ELF as output. It basically does
 | |
| a simple conversion from one ELF file to another slighty changed
 | |
| ELF file. First the tool makes sure that the ELF file fits a few
 | |
| requirements. For example there can only be one segment (loadable
 | |
| program header) in the input ELF file. After that it goes through
 | |
| the ELF relocation table and takes any entry that applies to the one
 | |
| segment we want to load at runtime. The rmodtool will then write all
 | |
| these relocation entires in a new ELF section called ".reloc". After
 | |
| that the ELF relocation table will be cleared.
 | |
| 
 | |
| One can split the rmodules in two different kinds:
 | |
| 1. coreboot stages (postcar, ramstage)
 | |
| 2. simple binaries (smm, smmstub, sipi\_vector)
 | |
| 
 | |
| They are actually handled the same by the build system and only differ
 | |
| in the fact, that they are either coreboot stages or they are not.
 | |
| 
 | |
| In the end the ELF files will have three different ELF sections,
 | |
| which are all created by the rmodtool.
 | |
| 1. relocation header (.header)
 | |
| 2. program (.program)
 | |
| 3. relocation entries (.relocs)
 | |
| 
 | |
| ## runtime
 | |
| 
 | |
| Either rmodule\_load (lib/rmodule.c) is used directly or through the
 | |
| rmodule\_stage\_load (lib/rmodule.c) wrapper. It is used to load the
 | |
| stages (postcar and ramstage) or small programs like (sipi\_vector,
 | |
| smm, smmstub) into memory before jumping to them. In the case of a
 | |
| coreboot stage, CBMEM is used to allocate space for the stage in memory
 | |
| via the rmodule\_cbfs\_allocater (lib/rmodule.c). At this point the
 | |
| location of the stage in memory is known and all relocation (address
 | |
| fixups) need to be done now. This is basically just a simple loop that
 | |
| goes through each relocation entry. Each relocation entry is just an
 | |
| address pointing to a location that needs relocation. The relocation
 | |
| itself is just a simple addition, that adds an offset from where the
 | |
| image was "supposed" to be at link time, to where it is now relocated.
 | |
| 
 | |
| ## module\_parameters
 | |
| 
 | |
| module\_parameters is a section inside the rmodule ELF file. Its
 | |
| basically a way to pass runtime information to an rmodule
 | |
| before jumping to it. The caller will use rmodule\_parameters()
 | |
| (lib/rmodule.c) to get the runtime address of the module\_parameters
 | |
| and the callee (the rmodule itself) usually appends the section to
 | |
| specific types via compiler attributes. For example:
 | |
| ```
 | |
| static const
 | |
| volatile __attribute((aligned(4), __section__(".module_parameters")))
 | |
| struct smm_runtime smm_runtime;
 | |
| ```
 | |
| 
 | |
| # x86 why rmodules
 | |
| //TODO
 | |
| x86: postcar and ramstage cannot conflict with payload regarding
 | |
| memory placement. Therefore payload location is usually fixed and
 | |
| postcar/ramstage can be placed at a location in memory that is
 | |
| figured out at runtime.
 |