[riscv] Add a .lkrn build target resembling a Linux kernel binary

On x86 BIOS, it has been useful to be able to build iPXE to resemble a
Linux kernel, so that it can be loaded by programs such as syslinux
which already know how to handle Linux kernel binaries.

Add an equivalent .lkrn build target for RISC-V SBI, allowing for
build targets such as:

  make bin-riscv64/ipxe.lkrn

  make bin-riscv64/cgem.lkrn

The Linux kernel header format allows us to specify a required length
(including uninitialised-data portions) and defines that the image
will be loaded at a fixed offset from the start of RAM.  We can
therefore use known-safe areas of memory (within our own .bss) for the
initial temporary page table and stack.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-05-13 12:51:53 +01:00
parent 17fd67ce03
commit 8e38af800b
3 changed files with 131 additions and 0 deletions

View File

@@ -14,3 +14,4 @@ LDSCRIPT = arch/riscv/scripts/sbi.lds
# Media types
#
MEDIA += sbi
MEDIA += lkrn

View File

@@ -452,6 +452,7 @@ paging_mode_names:
* This can be used only once .bss is known to be writable.
*/
.section ".bss.page_table", "a", @nobits
.globl page_table
.balign PAGE_SIZE
page_table:
.space PAGE_SIZE

View File

@@ -0,0 +1,129 @@
/*
* Copyright (C) 2025 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/** @file
*
* Linux kernel prefix
*
*/
.section ".note.GNU-stack", "", @progbits
.text
/* Layout of kernel header */
.struct 0
hdr_code0: .space 4
hdr_code1: .space 4
hdr_text_offset: .space 8
hdr_image_size: .space 8
hdr_flags: .space 8
hdr_version: .space 4
hdr_res1: .space 4
hdr_res2: .space 8
hdr_magic: .space 8
hdr_magic2: .space 4
hdr_res3: .space 4
hdr_end:
.org 64
.previous
/* Header version */
#define HDR_VERSION( major, minor ) ( ( (major) << 16 ) | (minor) )
#define HDR_VERSION_0_2 HDR_VERSION ( 0, 2 )
/* Header flags */
#define HDR_FL_BIG_ENDIAN 0x00000001
/* Magic numbers */
#define HDR_MAGIC "RISCV\0\0\0"
#define HDR_MAGIC2 "RSC\x05"
/*
* Linux kernel header
*/
.section ".prefix", "ax", @progbits
/* Executable code / MZ header (for EFI-compatible binaries) */
.org hdr_code0
j _lkrn_start
/* Image load offset
*
* Must be set to the size of a single "megapage" (2MB for
* 64-bit, 4MB for 32-bit).
*/
.org hdr_text_offset
.dword _max_align
/* Image size (including uninitialised-data potions) */
.org hdr_image_size
.dword _memsz
/* Flags */
.org hdr_flags
.dword 0
/* Version */
.org hdr_version
.word HDR_VERSION_0_2
/* Magic numbers */
.org hdr_magic
.ascii HDR_MAGIC
.org hdr_magic2
.ascii HDR_MAGIC2
.org hdr_end
/*
* Linux kernel entry point
*/
.globl _lkrn_start
_lkrn_start:
/* Identify temporary page table and stack space
*
* Linux expects to be placed at the image load offset from
* the start of RAM. Assume that our loaded image is
* therefore already writable, and that we can therefore use
* the page table and stack within our (not yet zeroed) .bss
* section.
*/
la a2, page_table
la sp, _estack
/* Install iPXE */
call install
/* Call main program */
call main
/* We have no return path, since the Linux kernel does not
* define that a valid return address exists.
*
* Attempt a system reset, since there is nothing else we can
* viably do at this point.
*/
j reset_system
.size _lkrn_start, . - _lkrn_start