From 73774def6b7c52ce6d3be0e4a41852047e66f46b Mon Sep 17 00:00:00 2001 From: Michael LeMay Date: Sun, 9 Aug 2015 16:38:04 -0700 Subject: [PATCH] x86, galileo: Add sample non-driver protection domain This patch adds a simple non-driver protection domain sample to serve as an example for defining other non-driver protection domains. It simply performs a ping-pong test of protection domain switching latency during boot, including optional accesses to a private metadata region, and prints out the results. --- cpu/x86/quarkX1000.ld | 4 + cpu/x86/quarkX1000_multi_seg.ld | 4 + cpu/x86/quarkX1000_paging.ld | 4 + cpu/x86/startup.h | 46 ++++++ examples/galileo/Makefile | 8 +- examples/galileo/README.md | 11 ++ examples/galileo/prot-domain-switch-latency.c | 156 ++++++++++++++++++ platform/galileo/contiki-main.c | 11 ++ 8 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 cpu/x86/startup.h create mode 100644 examples/galileo/prot-domain-switch-latency.c diff --git a/cpu/x86/quarkX1000.ld b/cpu/x86/quarkX1000.ld index be91a74c7..d4ea66aa6 100644 --- a/cpu/x86/quarkX1000.ld +++ b/cpu/x86/quarkX1000.ld @@ -63,6 +63,10 @@ SECTIONS { { *(.rodata*) + _sdata_kern_startup_func = .; + KEEP(*(.kern_startup_func)) + _edata_kern_startup_func = .; + _sdata_shared_isr = .; KEEP(*(.shared_isr_data*)) _edata_shared_isr = .; diff --git a/cpu/x86/quarkX1000_multi_seg.ld b/cpu/x86/quarkX1000_multi_seg.ld index 945650399..c4e6293cf 100644 --- a/cpu/x86/quarkX1000_multi_seg.ld +++ b/cpu/x86/quarkX1000_multi_seg.ld @@ -119,6 +119,10 @@ SECTIONS { *(.rodata*) *(.data*) + _sdata_kern_startup_func = .; + KEEP(*(.kern_startup_func)) + _edata_kern_startup_func = .; + /* These could alternatively be treated as read-only data to prevent tampering from the user privilege level. diff --git a/cpu/x86/quarkX1000_paging.ld b/cpu/x86/quarkX1000_paging.ld index 19e50e1e0..87c89ed8b 100644 --- a/cpu/x86/quarkX1000_paging.ld +++ b/cpu/x86/quarkX1000_paging.ld @@ -128,6 +128,10 @@ SECTIONS { *(.rodata*) *(.data*) + _sdata_kern_startup_func = .; + KEEP(*(.kern_startup_func)) + _edata_kern_startup_func = .; + /* These could alternatively be treated as read-only data to prevent tampering from the user privilege level. diff --git a/cpu/x86/startup.h b/cpu/x86/startup.h new file mode 100644 index 000000000..56ad3b482 --- /dev/null +++ b/cpu/x86/startup.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_X86_STARTUP_H_ +#define CPU_X86_STARTUP_H_ + +/** + * \brief Declare a function that will be automatically invoked from the kernel + * protection domain during boot, after all of the default device + * initialization has been completed. + */ +#define KERN_STARTUP_FUNC(f) \ +static void f(void); \ +static uintptr_t \ + __attribute__((used, section(".kern_startup_func"))) \ + __kern_startup_f = (uintptr_t)f; \ +static void f(void) + +#endif /* CPU_X86_STARTUP_H_ */ diff --git a/examples/galileo/Makefile b/examples/galileo/Makefile index bc7b071ff..0852fe085 100644 --- a/examples/galileo/Makefile +++ b/examples/galileo/Makefile @@ -1,6 +1,6 @@ TARGET=galileo -KNOWN_EXAMPLES = gpio-input gpio-output gpio-interrupt i2c-LSM9DS0 i2c-callbacks print-imr +KNOWN_EXAMPLES = gpio-input gpio-output gpio-interrupt i2c-LSM9DS0 i2c-callbacks print-imr prot-domain-switch-latency ifeq ($(filter $(EXAMPLE),$(KNOWN_EXAMPLES)),) $(info Set the variable EXAMPLE to one of the following Galileo-specific examples:) @@ -12,6 +12,12 @@ ifeq ($(EXAMPLE),print-imr) CFLAGS += -DDBG_IMRS endif +ifeq ($(EXAMPLE),prot-domain-switch-latency) +ifeq ($(SAMPLE_METADATA),1) +CFLAGS += -DSAMPLE_METADATA=1 +endif +endif + CONTIKI_PROJECT = $(EXAMPLE) all: $(CONTIKI_PROJECT) diff --git a/examples/galileo/README.md b/examples/galileo/README.md index 49777a16c..8f3217f05 100644 --- a/examples/galileo/README.md +++ b/examples/galileo/README.md @@ -93,6 +93,17 @@ Intel Quark X1000 SoC Isolated Memory Regions (IMRs), the Host System Management Mode Controls register, and the Host Memory I/O Boundary register. +Protection Domains +------------------ + +### Protection Domain Switch Latency (EXAMPLE=prot-domain-switch-latency) + +This application measures and prints the average latency of repeatedly +switching from one protection domain to another and back, in ping-pong +fashion. It can optionally perform memory accesses to metadata +associated with the destination protection domain. This feature can +be enabled by specifying SAMPLE_METADATA=1 on the build command line. + References ---------- diff --git a/examples/galileo/prot-domain-switch-latency.c b/examples/galileo/prot-domain-switch-latency.c new file mode 100644 index 000000000..9b6908a2f --- /dev/null +++ b/examples/galileo/prot-domain-switch-latency.c @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015-2016, Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "contiki.h" +#include "prot-domains.h" +#include "startup.h" +#include "syscalls.h" + +#define CPU_FREQ (400 * 1000 * 1000) +/* Run the test for approximately eight seconds. + * + * Duration expressed as shift amount to avoid integer overflow. + */ +#define DURATION_SECONDS_SHAMT 3 + +#ifdef SAMPLE_METADATA +typedef struct sample_meta { + int cnt; + +#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING + /** + * See the comment on the padding in the metadata for the Intel Quark X1000 + * Ethernet driver for an explanation of why it is sized and structured like + * this. + */ + uint8_t pad[MIN_PAGE_SIZE - sizeof(int)]; +#endif +} __attribute__((packed)) sample_meta_t; + +static sample_meta_t ATTR_BSS_META meta = { .cnt = 0 }; +#endif + +PROT_DOMAINS_ALLOC(dom_client_data_t, ping_dcd); +PROT_DOMAINS_ALLOC(dom_client_data_t, pong_dcd); + +PROCESS(prot_domain_latency_process, "Ping-Pong Process"); +AUTOSTART_PROCESSES(&prot_domain_latency_process); +/*---------------------------------------------------------------------------*/ +void pong(uint64_t *mid, int *cnt); +SYSCALLS_DEFINE_SINGLETON(pong, pong_dcd, + uint64_t *mid, int *cnt) +{ +#ifdef SAMPLE_METADATA + sample_meta_t *loc_meta = (sample_meta_t *)PROT_DOMAINS_META(pong_dcd); +#endif + + *mid = _rdtsc(); + +#ifdef SAMPLE_METADATA + META_READL(*cnt, loc_meta->cnt); + META_WRITEL(loc_meta->cnt, *cnt + 1); +#endif +} +/*---------------------------------------------------------------------------*/ +void ping(void); +SYSCALLS_DEFINE_SINGLETON(ping, ping_dcd) +{ + uint64_t start, mid, end; + uint64_t diff1 = 0, diff2 = 0; + double diff1_d, diff2_d; + int i = 0; + int cnt; + + while(((diff1 + diff2) >> DURATION_SECONDS_SHAMT) < CPU_FREQ) { + start = _rdtsc(); + pong(&mid, &cnt); + end = _rdtsc(); + +#ifdef SAMPLE_METADATA + assert(cnt == i); +#endif + + /* exclude the warm-up round */ + if(i != 0) { + diff1 += mid - start; + diff2 += end - mid; + } + + i++; + } + + diff1_d = diff1; + diff2_d = diff2; + + diff1_d /= i - 1; + diff2_d /= i - 1; + + puts( "Sample protection domain ping-pong switching latency measurements:"); + printf(" %u iterations\n", i - 1); + printf(" Avg. # cycles ping -> pong: %.2f\n", diff1_d); + printf(" + Avg. # cycles pong -> ping: %.2f\n", diff2_d); + puts( " ----------------------------------------"); + printf(" Avg. # cycles round-trip: %.2f\n", diff1_d + diff2_d); +} +/*---------------------------------------------------------------------------*/ +KERN_STARTUP_FUNC(sample_domain_init) +{ + PROT_DOMAINS_INIT_ID(ping_dcd); + prot_domains_reg(&ping_dcd, 0, 0, 0, 0, false); + SYSCALLS_INIT(ping); + SYSCALLS_AUTHZ(ping, ping_dcd); + + PROT_DOMAINS_INIT_ID(pong_dcd); + prot_domains_reg(&pong_dcd, 0, 0, +#ifdef SAMPLE_METADATA + (uintptr_t)&meta, sizeof(meta), false); +#else + 0, 0, false); +#endif + SYSCALLS_INIT(pong); + SYSCALLS_AUTHZ(pong, pong_dcd); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(prot_domain_latency_process, ev, data) +{ + PROCESS_BEGIN(); + + /* Run the latency test from the ping domain so that interrupts + * are disabled during the test. + */ + ping(); + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/galileo/contiki-main.c b/platform/galileo/contiki-main.c index 7b31a9961..ccc1f519f 100644 --- a/platform/galileo/contiki-main.c +++ b/platform/galileo/contiki-main.c @@ -54,6 +54,8 @@ PROCINIT( &etimer_process #endif ); +extern int _sdata_kern_startup_func, _edata_kern_startup_func; + /*---------------------------------------------------------------------------*/ void app_main(void) @@ -78,6 +80,8 @@ app_main(void) int main(void) { + uintptr_t *func_ptr; + #ifdef X86_CONF_RESTRICT_DMA quarkX1000_imr_conf(); #endif @@ -104,6 +108,13 @@ main(void) */ pci_root_complex_lock(); + func_ptr = (uintptr_t *)&_sdata_kern_startup_func; + while(func_ptr != (uintptr_t *)&_edata_kern_startup_func) { + ((void (*)(void))*func_ptr)(); + + func_ptr++; + } + prot_domains_leave_main(); return 0;