hw_x86_64_muen: Add C++ implementation of Sinfo API

The Muen Sinfo API is used to retrieve information about the execution
environment of a subject running on the Muen Separation Kernel.

While the C++ API is defined in sinfo.h, musinfo.h specifies the
internal format of the information stored in the Sinfo pages provided by
the Muen SK. It is a copy of the file contained in the libmusinfo
library of the Muen project. That is the reason why the coding style in
this file differs from the official style.
This commit is contained in:
Reto Buerki 2015-04-21 17:21:11 +02:00 committed by Stefan Kalkowski
parent 5036b96c11
commit c434a5ceec
4 changed files with 426 additions and 0 deletions

View File

@ -18,6 +18,7 @@ SRC_S += spec/x86_64/crt0.s
# add C++ sources
SRC_CC += spec/x86_64_muen/platform_support.cc
SRC_CC += spec/x86_64_muen/sinfo.cc
SRC_CC += spec/x86_64/kernel/thread_base.cc
SRC_CC += spec/x86_64/idt.cc
SRC_CC += spec/x86_64/tss.cc

View File

@ -0,0 +1,138 @@
/*
* \brief Muen subject information API
* \author Reto Buerki
* \date 2015-04-21
*
* Defines functions to retrieve information about the execution environment of
* a subject running on the Muen Separation Kernel.
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SINFO_H
#define _SINFO_H
#include <base/stdint.h>
namespace Genode
{
/**
* Muen Subject Info class
*/
class Sinfo;
}
class Genode::Sinfo
{
public:
enum Config {
MAX_NAME_LENGTH = 63,
};
Sinfo();
/* Structure holding information about a memory region */
struct Memregion_info {
char name[MAX_NAME_LENGTH + 1];
uint64_t address;
uint64_t size;
bool writable;
bool executable;
};
/* Structure holding information about a Muen channel */
struct Channel_info {
char name[MAX_NAME_LENGTH + 1];
uint64_t address;
uint64_t size;
uint8_t event_number;
uint8_t vector;
bool writable;
bool has_event;
bool has_vector;
};
/*
* Check Muen sinfo Magic.
*/
static bool check_magic(void);
/*
* Return information for a channel given by name.
*
* If no channel with given name exists, False is returned. The
* event_number and vector parameters are only valid if indicated by
* the has_[event|vector] struct members.
*/
static bool get_channel_info(const char * const name,
struct Channel_info *channel);
/*
* Return information for a memory region given by name.
*
* If no memory region with given name exists, False is returned.
*/
static bool get_memregion_info(const char * const name,
struct Memregion_info *memregion);
/*
* Channel callback.
*
* Used in the muen_for_each_channel function. The optional void data pointer
* can be used to pass additional data.
*/
typedef bool (*Channel_cb)(const struct Channel_info * const channel,
void *data);
/*
* Invoke given callback function for each available channel.
*
* Channel information and the optional data argument are passed to each
* invocation of the callback. If a callback invocation returns false,
* processing is aborted and false is returned to the caller.
*/
static bool for_each_channel(Channel_cb func, void *data);
/*
* Memory region callback.
*
* Used in the muen_for_each_memregion function. The optional void data pointer
* can be used to pass additional data.
*/
typedef bool (*Memregion_cb)(const struct Memregion_info * const memregion,
void *data);
/*
* Invoke given callback function for each available memory region.
*
* Memory region information and the optional data argument are passed to each
* invocation of the callback. If a callback invocation returns false,
* processing is aborted and false is returned to the caller.
*/
static bool for_each_memregion(Memregion_cb func, void *data);
/*
* Return TSC tick rate in kHz.
*
* The function returns 0 if the TSC tick rate cannot be retrieved.
*/
static uint64_t get_tsc_khz(void);
/*
* Return start time of current minor frame in TSC ticks.
*/
static uint64_t get_sched_start(void);
/*
* Return end time of current minor frame in TSC ticks.
*/
static uint64_t get_sched_end(void);
};
#endif /* _SINFO_H */

View File

@ -0,0 +1,59 @@
#ifndef MUSINFO_H_
#define MUSINFO_H_
#include <base/stdint.h>
#define MUEN_SUBJECT_INFO_MAGIC 0x01006f666e69756dULL
#define MAX_NAME_LENGTH 63
#define MAX_RESOURCE_COUNT 255
#define NO_RESOURCE 0
using namespace Genode;
struct name_type {
uint8_t length;
char data[MAX_NAME_LENGTH];
} __attribute__((packed));
#define MEM_WRITABLE_FLAG (1 << 0)
#define MEM_EXECUTABLE_FLAG (1 << 1)
struct memregion_type {
uint64_t address;
uint64_t size;
uint8_t flags;
char padding[7];
} __attribute__((packed, aligned (8)));
#define CHAN_EVENT_FLAG (1 << 0)
#define CHAN_VECTOR_FLAG (1 << 1)
struct channel_info_type {
uint8_t flags;
uint8_t event;
uint8_t vector;
char padding[5];
} __attribute__((packed, aligned (8)));
struct resource_type {
struct name_type name;
uint8_t memregion_idx;
uint8_t channel_info_idx;
char padding[6];
} __attribute__((packed, aligned (8)));
struct subject_info_type {
uint64_t magic;
uint8_t resource_count;
uint8_t memregion_count;
uint8_t channel_info_count;
char padding[5];
uint64_t tsc_khz;
uint64_t tsc_schedule_start;
uint64_t tsc_schedule_end;
struct resource_type resources[MAX_RESOURCE_COUNT];
struct memregion_type memregions[MAX_RESOURCE_COUNT];
struct channel_info_type channels_info[MAX_RESOURCE_COUNT];
} __attribute__((packed, aligned (8)));
#endif /* MUSINFO_H_ */

View File

@ -0,0 +1,228 @@
/*
* \brief Muen subject information API impl
* \author Reto Buerki
* \date 2015-04-21
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
#include <util/string.h>
#include <sinfo.h>
#include "musinfo.h"
enum {
SINFO_BASE_ADDR = 0xe00000000,
};
static const subject_info_type *
const sinfo = ((subject_info_type *)SINFO_BASE_ADDR);
/* Log channel information */
static bool log_channel(
const struct Genode::Sinfo::Channel_info * const channel,
void *data)
{
if (channel->has_event || channel->has_vector) {
PDBG("muen-sinfo: [%s with %s %03d] %s\n",
channel->writable ? "writer" : "reader",
channel->has_event ? "event " : "vector",
channel->has_event ? channel->event_number : channel->vector,
channel->name);
} else {
PDBG("muen-sinfo: [%s with no %s ] %s\n",
channel->writable ? "writer" : "reader",
channel->writable ? "event " : "vector",
channel->name);
}
return true;
}
/* Log memory region information */
static bool log_memregion(
const struct Genode::Sinfo::Memregion_info * const region,
void *data)
{
PDBG("muen-sinfo: [addr 0x%016llx size 0x%016llx %s%s] %s\n",
region->address, region->size,
region->writable ? "rw" : "ro",
region->executable ? "x" : "-", region->name);
return true;
}
/* Fill channel struct with channel information from resource given by index */
static void fill_channel_data(
uint8_t idx,
struct Genode::Sinfo::Channel_info *channel)
{
const struct resource_type resource = sinfo->resources[idx];
const struct memregion_type memregion =
sinfo->memregions[resource.memregion_idx - 1];
const struct channel_info_type channel_info =
sinfo->channels_info[resource.channel_info_idx - 1];
memset(&channel->name, 0, MAX_NAME_LENGTH + 1);
memcpy(&channel->name, resource.name.data, resource.name.length);
channel->address = memregion.address;
channel->size = memregion.size;
channel->writable = memregion.flags & MEM_WRITABLE_FLAG;
channel->has_event = channel_info.flags & CHAN_EVENT_FLAG;
channel->event_number = channel_info.event;
channel->has_vector = channel_info.flags & CHAN_VECTOR_FLAG;
channel->vector = channel_info.vector;
}
/* Fill memregion struct with memory region info from resource given by index */
static void fill_memregion_data(
uint8_t idx,
struct Genode::Sinfo::Memregion_info *region)
{
const struct resource_type resource = sinfo->resources[idx];
const struct memregion_type memregion =
sinfo->memregions[resource.memregion_idx - 1];
memset(&region->name, 0, MAX_NAME_LENGTH + 1);
memcpy(&region->name, resource.name.data, resource.name.length);
region->address = memregion.address;
region->size = memregion.size;
region->writable = memregion.flags & MEM_WRITABLE_FLAG;
region->executable = memregion.flags & MEM_EXECUTABLE_FLAG;
}
/* Returns true if the given resource is a memory region */
static bool is_memregion(const struct resource_type * const resource)
{
return resource->memregion_idx != NO_RESOURCE;
}
/* Returns true if the given resource is a channel */
static bool is_channel(const struct resource_type * const resource)
{
return is_memregion(resource) && resource->channel_info_idx != NO_RESOURCE;
}
Sinfo::Sinfo()
{
if (!check_magic()) {
PERR("muen-sinfo: Subject information MAGIC mismatch\n");
return;
}
PINF("muen-sinfo: Subject information exports %d memory region(s)\n",
sinfo->memregion_count);
for_each_memregion(log_memregion, 0);
PINF("muen-sinfo: Subject information exports %d channel(s)\n",
sinfo->channel_info_count);
for_each_channel(log_channel, 0);
}
bool Sinfo::check_magic(void)
{
return sinfo != 0 && sinfo->magic == MUEN_SUBJECT_INFO_MAGIC;
}
bool Sinfo::get_channel_info(const char * const name,
struct Channel_info *channel)
{
int i;
if (!check_magic())
return false;
for (i = 0; i < sinfo->resource_count; i++) {
if (is_channel(&sinfo->resources[i]) &&
strcmp(sinfo->resources[i].name.data, name) == 0) {
fill_channel_data(i, channel);
return true;
}
}
return false;
}
bool Sinfo::get_memregion_info(const char * const name,
struct Memregion_info *memregion)
{
int i;
if (!check_magic())
return false;
for (i = 0; i < sinfo->resource_count; i++) {
if (is_memregion(&sinfo->resources[i]) &&
strcmp(sinfo->resources[i].name.data, name) == 0) {
fill_memregion_data(i, memregion);
return true;
}
}
return false;
}
bool Sinfo::for_each_channel(Channel_cb func, void *data)
{
int i;
struct Channel_info current_channel;
if (!check_magic())
return false;
for (i = 0; i < sinfo->resource_count; i++) {
if (is_channel(&sinfo->resources[i])) {
fill_channel_data(i, &current_channel);
if (!func(&current_channel, data))
return false;
}
}
return true;
}
bool Sinfo::for_each_memregion(Memregion_cb func, void *data)
{
int i;
struct Memregion_info current_region;
if (!check_magic())
return false;
for (i = 0; i < sinfo->resource_count; i++) {
if (is_memregion(&sinfo->resources[i])) {
fill_memregion_data(i, &current_region);
if (!func(&current_region, data))
return false;
}
}
return true;
}
uint64_t Sinfo::get_tsc_khz(void)
{
if (!check_magic())
return 0;
return sinfo->tsc_khz;
}
uint64_t Sinfo::get_sched_start(void)
{
if (!check_magic())
return 0;
return sinfo->tsc_schedule_start;
}
uint64_t Sinfo::get_sched_end(void)
{
if (!check_magic())
return 0;
return sinfo->tsc_schedule_end;
}