mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Add support for parsing IPL file signatures as produced by the Linux kernel's sign-file tool. When preparing a disk for IPL, the signatures will be added as separate data components that can be used by the Secure Boot firmware feature to validate the integrity of the IPL files. Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
145 lines
3.7 KiB
C
145 lines
3.7 KiB
C
/*
|
|
* zipl - zSeries Initial Program Loader tool
|
|
*
|
|
* Main program for stage2 bootloader
|
|
*
|
|
* Copyright IBM Corp. 2013, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include "error.h"
|
|
#include "libc.h"
|
|
#include "menu.h"
|
|
#include "s390.h"
|
|
#include "stage2.h"
|
|
|
|
static int is_null_descriptor(disk_blockptr_t *address)
|
|
{
|
|
unsigned long long *value = (unsigned long long *)address;
|
|
|
|
return *value == 0;
|
|
}
|
|
|
|
static void *load_blocklist(struct component_entry *descriptor_address,
|
|
struct subchannel_id subchannel_id, void *load_address)
|
|
{
|
|
disk_blockptr_t *indirect_blocks, *indirect_blockspace,
|
|
*start_addr;
|
|
unsigned long length;
|
|
long long nr_descr;
|
|
|
|
/* start address to load first indirect blocks */
|
|
start_addr = (disk_blockptr_t *)&descriptor_address->data;
|
|
/* get a free page to store indirect blocks in */
|
|
indirect_blockspace = (void *)get_zeroed_page();
|
|
|
|
do {
|
|
length = extract_length(start_addr);
|
|
/* calculate number of descriptors to be processed and base 0 */
|
|
nr_descr = length/DESCR_PER_BLOCK - 1;
|
|
indirect_blocks = indirect_blockspace;
|
|
/* load indirect blocks */
|
|
load_direct(start_addr, subchannel_id, indirect_blocks);
|
|
|
|
/* process indirect blocks */
|
|
while (nr_descr > 0) {
|
|
if (is_null_descriptor(indirect_blocks))
|
|
goto out_free_page;
|
|
|
|
/* for special zero block simply clear mem */
|
|
if (!is_zero_block(indirect_blocks)) {
|
|
length = extract_length(indirect_blocks);
|
|
memset(load_address, 0, length);
|
|
load_address += length;
|
|
} else
|
|
load_address = load_direct(indirect_blocks,
|
|
subchannel_id,
|
|
load_address);
|
|
|
|
indirect_blocks++;
|
|
nr_descr--;
|
|
}
|
|
/* update pointer for next round */
|
|
start_addr = indirect_blocks;
|
|
/* as long as another indirect block needs to be loaded */
|
|
} while (!is_null_descriptor(indirect_blocks));
|
|
|
|
out_free_page:
|
|
free_page((unsigned long)indirect_blockspace);
|
|
return load_address;
|
|
}
|
|
|
|
|
|
static void execute(uint64_t psw)
|
|
{
|
|
asm volatile(
|
|
" lpsw %[psw]\n"
|
|
: : [psw] "Q" (psw) : "cc"
|
|
);
|
|
}
|
|
|
|
void start(void)
|
|
{
|
|
struct stage2_descr stage2_descr;
|
|
struct subchannel_id subchannel_id;
|
|
void *load_address;
|
|
struct component_entry *entry;
|
|
disk_blockptr_t *blockptr;
|
|
void *load_page;
|
|
int config_nr;
|
|
|
|
subchannel_id = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
|
|
stage2_descr = *(struct stage2_descr*)STAGE2_DESC;
|
|
|
|
/* print menu and get configuration number */
|
|
config_nr = menu();
|
|
kdump_stage2(config_nr);
|
|
|
|
io_irq_enable();
|
|
set_device(subchannel_id, ENABLED);
|
|
|
|
load_page = (void *)get_zeroed_page();
|
|
load_address = (disk_blockptr_t *) load_page;
|
|
|
|
/* load blockpointer list to load address */
|
|
load_direct((disk_blockptr_t *)&stage2_descr, subchannel_id,
|
|
load_address);
|
|
|
|
blockptr = (disk_blockptr_t *)(load_address +
|
|
sizeof(disk_blockptr_t));
|
|
|
|
load_direct(&blockptr[config_nr], subchannel_id, load_address);
|
|
|
|
/* skip header */
|
|
entry = (struct component_entry *)
|
|
(load_address + sizeof(struct component_header));
|
|
while (entry->type == COMPONENT_LOAD ||
|
|
entry->type == COMPONENT_SIGNATURE) {
|
|
if (entry->type == COMPONENT_SIGNATURE) {
|
|
/* Skip unhandled signature components */
|
|
entry++;
|
|
continue;
|
|
}
|
|
load_address = (void *)(unsigned long)
|
|
entry->address.load_address[1];
|
|
load_blocklist(entry, subchannel_id, load_address);
|
|
entry++;
|
|
}
|
|
if (entry->type != COMPONENT_EXECUTE)
|
|
panic(EWRONGTYPE, "");
|
|
|
|
free_page((unsigned long)load_page);
|
|
io_irq_disable();
|
|
set_device(subchannel_id, DISABLED);
|
|
|
|
execute(entry->address.load_psw);
|
|
}
|
|
|
|
void panic_notify(unsigned long UNUSED(reason))
|
|
{
|
|
}
|
|
|
|
uint64_t stage2_head __attribute__((section(".stage2.head")));
|