Skip to content

Commit

Permalink
discover: Check if the kernel image has Ultravisor support
Browse files Browse the repository at this point in the history
The PPC kernel image has an ELF Note 'namespace' called 'PowerPC'
to store capabilities and information which can be used by a
bootloader or userland. The capabilities can be accessed using
the 'type' PPC_ELFNOTE_CAPABILITIES which returns a bitmap
as 'descriptor' field.

Bit 0 in this bitmap indicates that the powerpc kernel binary
knows how to run in an ultravisor-enabled system. So, using this
bit, the petitboot can decide to abort the boot if the kernel is
incompatible, avoiding the crash later.

This validation only occours on PowerPC ultravisor-system and if
the config 'preboot check' in UI screen is enabled.

Signed-off-by: Maxiwell S. Garcia <maxiwell@linux.ibm.com>
  • Loading branch information
maxiwell authored and jk-ozlabs committed Jan 25, 2020
1 parent 3513c7f commit 7b108df
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 0 deletions.
21 changes: 21 additions & 0 deletions discover/boot.c
Expand Up @@ -448,6 +448,24 @@ static void cleanup_cancellations(struct boot_task *task,
talloc_free(task);
}

static bool preboot_check(struct boot_task *task)
{
const char *local_image = (task->local_image_override) ?
task->local_image_override : task->local_image;

char *preboot_check_err_msg = NULL;
bool preboot_check_ret = platform_preboot_check(local_image,
&preboot_check_err_msg);

if (preboot_check_err_msg) {
update_status(task->status_fn, task->status_arg,
STATUS_ERROR, "%s", preboot_check_err_msg);
talloc_free(preboot_check_err_msg);
}

return preboot_check_ret;
}

static void boot_process(struct load_url_result *result, void *data)
{
struct boot_task *task = data;
Expand All @@ -471,6 +489,9 @@ static void boot_process(struct load_url_result *result, void *data)

run_boot_hooks(task);

if (!preboot_check(task))
return;

update_status(task->status_fn, task->status_arg, STATUS_INFO,
_("Performing kexec load"));

Expand Down
43 changes: 43 additions & 0 deletions discover/platform-powerpc.c
Expand Up @@ -21,6 +21,7 @@
#include "platform.h"
#include "ipmi.h"
#include "dt.h"
#include "elf.h"

static const char *partition = "common";
static const char *sysparams_dir = "/sys/firmware/opal/sysparams/";
Expand Down Expand Up @@ -945,6 +946,47 @@ static void pre_boot(struct platform *p, const struct config *config)
platform->set_os_boot_sensor(platform);
}

static bool preboot_check(struct platform *p,
const struct config *config,
const char *image,
char **err_msg)
{
struct platform_powerpc *platform = p->platform_data;
unsigned int *ppc_cap_bitmap = NULL;
bool ultravisor_enabled;
struct stat statbuf;
bool ret = true;

/* check if ultravisor-system is enabled */
ultravisor_enabled = stat("/proc/device-tree/ibm,ultravisor",
&statbuf) == 0;

/* if ultravisor-system is disabled, continue the boot process */
if (!ultravisor_enabled)
return true;

ppc_cap_bitmap = elf_getnote_desc(elf_open_image(image),
POWERPC_ELFNOTE_NAMESPACE,
PPC_ELFNOTE_CAPABILITIES);

if ((ppc_cap_bitmap) && (*ppc_cap_bitmap & PPCCAP_ULTRAVISOR_BIT)) {
pb_debug("kernel capabilities: ultravisor mode found.\n");
} else {
ret = false;
pb_log_fn("kernel capabilities failed:"
" IBM Ultravisor mode is required.\n");
*err_msg = talloc_strdup(platform, "IBM Ultravisor capability"
" not found");
}
free(ppc_cap_bitmap);

/* if preboot_check is disabled, continue the boot process */
if (!config->preboot_check_enabled)
return true;

return ret;
}

static void get_sysinfo_stb(struct platform_powerpc *platform,
struct system_info *sysinfo)
{
Expand Down Expand Up @@ -1078,6 +1120,7 @@ static struct platform platform_powerpc = {
.get_sysinfo = get_sysinfo,
.restrict_clients = restrict_clients,
.set_password = set_password,
.preboot_check = preboot_check,
};

register_platform(platform_powerpc);
11 changes: 11 additions & 0 deletions discover/platform.c
Expand Up @@ -207,6 +207,17 @@ void platform_pre_boot(void)
platform->pre_boot(platform, config);
}

bool platform_preboot_check(const char *image, char **err_msg)
{
const struct config *config = config_get();

if (platform && config && platform->preboot_check)
return platform->preboot_check(platform, config,
image, err_msg);

return true;
}

int platform_get_sysinfo(struct system_info *info)
{
if (platform && platform->get_sysinfo)
Expand Down
5 changes: 5 additions & 0 deletions discover/platform.h
Expand Up @@ -14,6 +14,10 @@ struct platform {
int (*get_sysinfo)(struct platform *, struct system_info *);
bool (*restrict_clients)(struct platform *);
int (*set_password)(struct platform *, const char *hash);
bool (*preboot_check)(struct platform *,
const struct config *,
const char *image,
char **err_msg);
uint16_t dhcp_arch_id;
void *platform_data;
};
Expand All @@ -25,6 +29,7 @@ int platform_get_sysinfo(struct system_info *info);
bool platform_restrict_clients(void);
int platform_set_password(const char *hash);
void platform_pre_boot(void);
bool platform_preboot_check(const char *image, char **err_msg);

/* configuration interface */
const struct config *config_get(void);
Expand Down

0 comments on commit 7b108df

Please sign in to comment.