Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion grub-core/loader/i386/slaunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
grub_dprintf ("slaunch", "allocate memory\r\n");
err = grub_relocator_alloc_chunk_align (relocator, &ch,
0, (0xffffffff - size) + 1,
size, 0x10000, /* SLB must be 64k aligned */
size > 0x10000 ? size : 0x10000, /* Alloc at least 64k */
0x10000, /* SLB must be 64k aligned */
GRUB_RELOCATOR_PREFERENCE_LOW, 1);
if (err)
{
Expand Down
276 changes: 267 additions & 9 deletions grub-core/loader/i386/slaunch_skinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,232 @@
#include <grub/types.h>
#include <grub/dl.h>
#include <grub/slaunch.h>
#include <grub/acpi.h>
#include <grub/crypto.h>

static inline grub_uint32_t *get_bootloader_data_addr (struct grub_slaunch_module *mod)
#define GRUB_ACPI_DRTM_SIGNATURE "DRTM"

struct drtm_t {
struct grub_acpi_table_header hdr;
grub_uint64_t DL_Entry_Base;
grub_uint64_t DL_Entry_Length;
grub_uint32_t DL_Entry32;
grub_uint64_t DL_Entry64;
grub_uint64_t DLME_Exit;
grub_uint64_t Log_Area_Start;
grub_uint32_t Log_Area_Length;
grub_uint64_t Architecture_Dependent;
grub_uint32_t DRT_Flags;
grub_uint8_t var_len_fields[];
} __attribute__ (( packed ));

static struct drtm_t *
search_drtm_in_rsdt (struct grub_acpi_table_header *t)
{
grub_uint32_t len;
grub_uint32_t *desc;

len = t->length - sizeof (*t);
desc = (grub_uint32_t *) (t + 1);

for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc)) {

t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;

if (t == NULL)
continue;

if (grub_memcmp (t->signature, GRUB_ACPI_DRTM_SIGNATURE,
sizeof (t->signature)) == 0)
return (struct drtm_t *)t;
}

return NULL;
}

static struct drtm_t *
search_drtm_in_xsdt (struct grub_acpi_table_header *t)
{
grub_uint32_t len;
grub_uint64_t *desc;

len = t->length - sizeof (*t);
desc = (grub_uint64_t *) (t + 1);

for (; len >= sizeof (*desc); desc++, len -= sizeof (*desc)) {

#if GRUB_CPU_SIZEOF_VOID_P == 4
if (*desc >= (1ULL << 32))
{
grub_printf ("Unreachable table\n");
continue;
}
#endif

t = (struct grub_acpi_table_header *) (grub_addr_t) *desc;

if (t == NULL)
continue;

if (grub_memcmp (t->signature, GRUB_ACPI_DRTM_SIGNATURE,
sizeof (t->signature)) == 0)
return (struct drtm_t *)t;
}

return NULL;
}

static struct drtm_t *
get_drtm_acpi_table (void)
{
struct drtm_t *drtm = NULL;
struct grub_acpi_rsdp_v10 *rsdp1 = grub_acpi_get_rsdpv1();

if (rsdp1)
drtm = search_drtm_in_rsdt ((void *) (grub_addr_t) rsdp1->rsdt_addr);

if (!drtm) {
struct grub_acpi_rsdp_v20 *rsdp2 = grub_acpi_get_rsdpv2 ();
if (!rsdp2)
grub_dprintf ("slaunch", "No RSDP\n");
else
drtm = search_drtm_in_xsdt ((void *) (grub_addr_t) rsdp2->xsdt_addr);
}

return drtm;
}

#define LZ_TAG_CLASS_MASK 0xF0

/* Tags with no particular class */
#define LZ_TAG_NO_CLASS 0x00
#define LZ_TAG_END 0x00
#define LZ_TAG_UNAWARE_OS 0x01
#define LZ_TAG_TAGS_SIZE 0x0F /* Always first */

/* Tags specifying kernel type */
#define LZ_TAG_BOOT_CLASS 0x10
#define LZ_TAG_BOOT_LINUX 0x10
#define LZ_TAG_BOOT_MB2 0x11

/* Tags specific to TPM event log */
#define LZ_TAG_EVENT_LOG_CLASS 0x20
#define LZ_TAG_EVENT_LOG 0x20
#define LZ_TAG_LZ_HASH 0x21

struct lz_tag_hdr {
grub_uint8_t type;
grub_uint8_t len;
} __attribute__ (( packed ));

struct lz_tag_tags_size {
struct lz_tag_hdr hdr;
grub_uint16_t size;
} __attribute__ (( packed ));

struct lz_tag_boot_linux {
struct lz_tag_hdr hdr;
grub_uint32_t zero_page;
} __attribute__ (( packed ));

struct lz_tag_boot_mb2 {
struct lz_tag_hdr hdr;
grub_uint32_t mbi;
grub_uint32_t kernel_entry;
grub_uint32_t kernel_size;
} __attribute__ (( packed ));

struct lz_tag_evtlog {
struct lz_tag_hdr hdr;
grub_uint32_t address;
grub_uint32_t size;
} __attribute__ (( packed ));

struct lz_tag_hash {
struct lz_tag_hdr hdr;
grub_uint16_t algo_id;
grub_uint8_t digest[];
} __attribute__ (( packed ));

static inline struct lz_tag_tags_size *get_bootloader_data_addr (
struct grub_slaunch_module *mod)
{
grub_uint16_t *ptr = (grub_uint16_t *)mod->addr;
return (grub_uint32_t *)(mod->addr + ptr[1]);
return (struct lz_tag_tags_size *)(mod->addr + ptr[1]);
}

static inline void *next_tag(struct lz_tag_tags_size *tags)
{
return (void *)(((grub_uint8_t *)tags) + tags->size);
}

grub_err_t
grub_slaunch_boot_skinit (struct grub_slaunch_params *slparams)
{
if (grub_slaunch_get_modules()) {
grub_uint32_t *boot_data = get_bootloader_data_addr(grub_slaunch_get_modules());
struct lz_tag_tags_size *tags = get_bootloader_data_addr(grub_slaunch_get_modules());
grub_uint32_t *apic = (grub_uint32_t *)0xfee00300ULL;
struct drtm_t *drtm = get_drtm_acpi_table();

grub_dprintf ("slaunch", "real_mode_target: 0x%x\r\n",
slparams->real_mode_target);
grub_dprintf ("slaunch", "prot_mode_target: 0x%x\r\n",
slparams->prot_mode_target);
grub_dprintf ("slaunch", "params: %p\r\n", slparams->params);

boot_data[GRUB_SL_ZEROPAGE_OFFSET/4] = (grub_uint32_t)slparams->real_mode_target;
/* Tags header */
tags->hdr.type = LZ_TAG_TAGS_SIZE;
tags->hdr.len = sizeof(struct lz_tag_tags_size);
tags->size = sizeof(struct lz_tag_tags_size);

/* Hashes of LZ */
{
grub_uint8_t buff[GRUB_MD_SHA256->contextsize]; /* SHA1 ctx is smaller */
struct lz_tag_hash *h = next_tag(tags);
h->hdr.type = LZ_TAG_LZ_HASH;
h->hdr.len = sizeof(struct lz_tag_hash) + GRUB_MD_SHA256->mdlen;
h->algo_id = 0x000B;
GRUB_MD_SHA256->init(buff);
GRUB_MD_SHA256->write(buff, grub_slaunch_get_modules()->addr,
(grub_addr_t)tags - (grub_addr_t)grub_slaunch_get_modules()->addr);
GRUB_MD_SHA256->final(buff);
grub_memcpy(h->digest, GRUB_MD_SHA256->read(buff), GRUB_MD_SHA256->mdlen);
tags->size += h->hdr.len;

h = next_tag(tags);
h->hdr.type = LZ_TAG_LZ_HASH;
h->hdr.len = sizeof(struct lz_tag_hash) + GRUB_MD_SHA1->mdlen;
h->algo_id = 0x0004;
GRUB_MD_SHA1->init(buff);
GRUB_MD_SHA1->write(buff, grub_slaunch_get_modules()->addr,
(grub_addr_t)tags - (grub_addr_t)grub_slaunch_get_modules()->addr);
GRUB_MD_SHA1->final(buff);
grub_memcpy(h->digest, GRUB_MD_SHA1->read(buff), GRUB_MD_SHA1->mdlen);
tags->size += h->hdr.len;
}

/* Boot protocol data */
struct lz_tag_boot_linux *b = next_tag(tags);
b->hdr.type = LZ_TAG_BOOT_LINUX;
b->hdr.len = sizeof(struct lz_tag_boot_linux);
b->zero_page = (grub_uint32_t)slparams->real_mode_target;
tags->size += b->hdr.len;

if (drtm) {
struct lz_tag_evtlog *e = next_tag(tags);
e->hdr.type = LZ_TAG_EVENT_LOG;
e->hdr.len = sizeof(struct lz_tag_evtlog);
e->address = drtm->Log_Area_Start;
e->size = drtm->Log_Area_Length;
tags->size += e->hdr.len;
}

/* Mark end of tags */
struct lz_tag_hdr *end = next_tag(tags);
end->type = LZ_TAG_END;
end->len = sizeof(struct lz_tag_hdr);
tags->size += end->len;

grub_dprintf ("slaunch", "broadcasting INIT\r\n");
*apic = 0x000c0500; // INIT, all excluding self

Expand All @@ -53,23 +258,76 @@ grub_slaunch_boot_skinit (struct grub_slaunch_params *slparams)
grub_dprintf ("slaunch", "grub_tis_request_locality\r\n");
grub_tis_request_locality(0xff); // relinquish all localities

grub_dprintf("linux", "Invoke SKINIT\r\n");
grub_dprintf("slaunch", "Invoke SKINIT\r\n");
return grub_relocator_skinit_boot (slparams->relocator, grub_slaunch_get_modules()->target, 0);
} else {
grub_dprintf("linux", "Secure Loader module not loaded, run slaunch_module\r\n");
grub_dprintf("slaunch", "Secure Loader module not loaded, run slaunch_module\r\n");
}
return GRUB_ERR_NONE;
}

grub_err_t
grub_slaunch_mb2_boot (struct grub_relocator *rel, struct grub_relocator32_state state)
{
grub_uint32_t *boot_data = get_bootloader_data_addr(grub_slaunch_get_modules());
struct lz_tag_tags_size *tags = get_bootloader_data_addr(grub_slaunch_get_modules());
grub_uint32_t *apic = (grub_uint32_t *)0xfee00300ULL;
struct drtm_t *drtm = get_drtm_acpi_table();

/* Tags header */
tags->hdr.type = LZ_TAG_TAGS_SIZE;
tags->hdr.len = sizeof(struct lz_tag_tags_size);
tags->size = sizeof(struct lz_tag_tags_size);

/* Hashes of LZ */
{
grub_uint8_t buff[GRUB_MD_SHA256->contextsize]; /* SHA1 ctx is smaller */
struct lz_tag_hash *h = next_tag(tags);
h->hdr.type = LZ_TAG_LZ_HASH;
h->hdr.len = sizeof(struct lz_tag_hash) + GRUB_MD_SHA256->mdlen;
h->algo_id = 0x000B;
GRUB_MD_SHA256->init(buff);
GRUB_MD_SHA256->write(buff, grub_slaunch_get_modules()->addr,
(grub_addr_t)tags - (grub_addr_t)grub_slaunch_get_modules()->addr);
GRUB_MD_SHA256->final(buff);
grub_memcpy(h->digest, GRUB_MD_SHA256->read(buff), GRUB_MD_SHA256->mdlen);
tags->size += h->hdr.len;

h = next_tag(tags);
h->hdr.type = LZ_TAG_LZ_HASH;
h->hdr.len = sizeof(struct lz_tag_hash) + GRUB_MD_SHA1->mdlen;
h->algo_id = 0x0004;
GRUB_MD_SHA1->init(buff);
GRUB_MD_SHA1->write(buff, grub_slaunch_get_modules()->addr,
(grub_addr_t)tags - (grub_addr_t)grub_slaunch_get_modules()->addr);
GRUB_MD_SHA1->final(buff);
grub_memcpy(h->digest, GRUB_MD_SHA1->read(buff), GRUB_MD_SHA1->mdlen);
tags->size += h->hdr.len;
}

/* Boot protocol data */
struct lz_tag_boot_mb2 *b = next_tag(tags);
b->hdr.type = LZ_TAG_BOOT_MB2;
b->hdr.len = sizeof(struct lz_tag_boot_mb2);
b->mbi = state.ebx;
b->kernel_entry = state.eip;
// TODO: save kernel size for measuring in LZ for non-ELF files?
boot_data[GRUB_SL_ZEROPAGE_OFFSET/4] = state.ebx;
boot_data[GRUB_SL_ZEROPAGE_OFFSET/4 - 1] = 2; // Pass boot protocol used
b->kernel_size = 0;
tags->size += b->hdr.len;

if (drtm) {
struct lz_tag_evtlog *e = next_tag(tags);
e->hdr.type = LZ_TAG_EVENT_LOG;
e->hdr.len = sizeof(struct lz_tag_evtlog);
e->address = drtm->Log_Area_Start;
e->size = drtm->Log_Area_Length;
tags->size += e->hdr.len;
}

/* Mark end of tags */
struct lz_tag_hdr *end = next_tag(tags);
end->type = LZ_TAG_END;
end->len = sizeof(struct lz_tag_hdr);
tags->size += end->len;

grub_dprintf ("slaunch", "broadcasting INIT\r\n");
*apic = 0x000c0500; // INIT, all excluding self
Expand Down
2 changes: 2 additions & 0 deletions include/grub/slaunch.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

#define GRUB_SL_BOOTPARAMS_OFFSET 0x12c
#define GRUB_SL_ZEROPAGE_OFFSET 0x14
#define GRUB_SL_EVENTLOG_ADDR_OFFSET 0x18
#define GRUB_SL_EVENTLOG_SIZE_OFFSET 0x1c

struct grub_slaunch_info
{
Expand Down