Merge pull request #60 from simonduq/pr/rm-galileo

Removed platform Galileo
This commit is contained in:
Simon Duquennoy 2017-09-01 13:43:53 +02:00 committed by GitHub
commit 833ad6fb33
114 changed files with 0 additions and 14073 deletions

View File

@ -1,48 +0,0 @@
CONTIKI_CPU_DIRS += . init/common
CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c
CC = gcc
LD = $(CC)
# Use gcc to invoke the assembler so that the preprocessor will be run on each
# file first, enabling us to use macros within assembly language files:
AS = $(CC)
OBJCOPY = objcopy
SIZE = size
STRIP = strip
# Omit exception handling unwind tables (see
# http://wiki.dwarfstd.org/index.php?title=Exception_Handling). Removing these
# tables saves space and has not caused any readily-apparent functional
# changes.
#
# Furthermore, the .eh_frame and .eh_frame_hdr sections that are otherwise
# generated are treated as code sections by the UEFI GenFw program, since they
# are read-only alloc sections. They get grouped with the actual code
# sections, ahead of the data sections. This perturbs symbols and complicates
# debugging.
#
# Synchronize the unwind table options here with the CFLAGS and CXXFLAGS in
# ./bsp/libc/build_newlib.sh.
CFLAGS += -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables
LDFLAGS += -Wl,-Map=contiki-$(TARGET).map,--build-id=none
ifeq ($(WERROR),1)
CFLAGS += -Werror
endif
ifeq ($(BUILD_RELEASE),1)
CFLAGS += -Os -fno-strict-aliasing -ffunction-sections -fdata-sections
# XXX: --gc-sections can be very tricky sometimes. If somehow the release
# binary seems to be broken, check if removing this option fixes the issue.
# Applying the --strip-all option to the UEFI build may induce an "Invalid operation" error.
# The UEFI GenFw program strips symbols.
MULTIBOOT_LDFLAGS += -Wl,--strip-all,--gc-sections
else
CFLAGS += -O0
ifeq ($(findstring clang,$(CC)),clang)
CFLAGS += -g
else
CFLAGS += -ggdb3
endif
endif

View File

@ -1,93 +0,0 @@
# See mm/README.md for a description of available settings:
X86_CONF_PROT_DOMAINS ?= none
include $(CONTIKI)/arch/cpu/x86/Makefile.x86_common
CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc net mm
CONTIKI_SOURCEFILES += bootstrap_quarkX1000.S rtc.c pit.c pic.c irq.c nmi.c pci.c uart-16x50.c uart.c gpio.c i2c.c eth.c shared-isr.c
CONTIKI_SOURCEFILES += imr.c msg-bus.c
CONTIKI_SOURCEFILES += stacks.c
ifneq ($(X86_CONF_PROT_DOMAINS),none)
CONTIKI_SOURCEFILES += prot-domains.c $(X86_CONF_PROT_DOMAINS)-prot-domains.c imr-conf.c
ifeq ($(X86_CONF_PROT_DOMAINS),paging)
LINKERSCRIPT_SFX = _paging
X86_CONF_SYSCALLS_INT = 1
ifeq ($(X86_CONF_USE_INVLPG),1)
CFLAGS += -DX86_CONF_USE_INVLPG
endif
# This matches the definition of X86_CONF_PROT_DOMAINS__PAGING in prot-domains.h:
CFLAGS += -DX86_CONF_PROT_DOMAINS=1
else ifeq ($(X86_CONF_PROT_DOMAINS),tss)
# This matches the definition of X86_CONF_PROT_DOMAINS__TSS in prot-domains.h:
CFLAGS += -DX86_CONF_PROT_DOMAINS=2
X86_CONF_MULTI_SEG = 1
CONTIKI_SOURCEFILES += tss-prot-domains-asm.S
else ifeq ($(X86_CONF_PROT_DOMAINS),swseg)
# This matches the definition of X86_CONF_PROT_DOMAINS__SWSEG in prot-domains.h:
CFLAGS += -DX86_CONF_PROT_DOMAINS=3
X86_CONF_SYSCALLS_INT = 1
X86_CONF_MULTI_SEG = 1
else
$(error Unrecognized setting for X86_CONF_PROT_DOMAINS: \
$(X86_CONF_PROT_DOMAINS). See arch/cpu/x86/mm/README.md for \
descriptions of available settings)
endif
ifeq ($(X86_CONF_SYSCALLS_INT),1)
CONTIKI_SOURCEFILES += syscalls-int-asm.S tss.c
endif
ifeq ($(X86_CONF_MULTI_SEG),1)
LINKERSCRIPT_SFX = _multi_seg
CONTIKI_SOURCEFILES += multi-segment.c
# Due to the way the multi-segment implementation of protection domains define
# tightly-bounded stack segments, the base pointer register cannot be used as
# a general-purpose register in all circumstances. The stack segment is used
# by default for a data access that uses the base pointer as the base register
# to compute the address. If the data referenced by the base pointer is not
# on the stack, then the access will fail. Thus, it is necessary to disable
# the omit-frame-pointer optimization. See mm/README.md for more details of
# how multi-segment protection domains are implemented.
CFLAGS += -fno-omit-frame-pointer
endif
endif
CFLAGS += -m32 -march=i586 -mtune=i586
LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/arch/cpu/x86/quarkX1000$(LINKERSCRIPT_SFX).ld
# The C compiler is used to invoke the assembler, so the CFLAGS should be
# passed to it on the command line:
ASFLAGS = -c $(CFLAGS)
ifeq ($(X86_CONF_RESTRICT_DMA),1)
CONTIKI_SOURCEFILES += imr-conf.c
CFLAGS += -DX86_CONF_RESTRICT_DMA
LDFLAGS += -Xlinker -T -Xlinker $(CONTIKI)/arch/cpu/x86/quarkX1000_dma.ld
endif
### UEFI support
UEFI_DIR = $(CONTIKI_CPU)/uefi
ifndef EN_UEFI
# Include a Makefile generated by the build_uefi.sh script, if available.
# If that script was not run, then UEFI support will not be built.
-include $(UEFI_DIR)/Makefile.uefi
endif
ifeq ($(EN_UEFI),1)
EDK2_DIR = $(UEFI_DIR)/edk2
GEN_FW = $(EDK2_DIR)/BaseTools/Source/C/bin/GenFw
CONTIKI_CPU_DIRS += uefi
CONTIKI_SOURCEFILES += bootstrap_uefi.c
CFLAGS += -I$(EDK2_DIR)/MdePkg/Include -I$(EDK2_DIR)/MdePkg/Include/Ia32
else
$(info Note: UEFI support is disabled.)
$(info To enable UEFI support, run $(CONTIKI_CPU)/uefi/build_uefi.sh prior)
$(info to building Contiki.)
endif

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) 2015, 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 "stacks.h"
# Multiboot
.set MAGIC_NUMBER, 0x1BADB002
.set FLAGS, 0x0
.set CHECKSUM, -MAGIC_NUMBER
.section .multiboot
.align 4
.long MAGIC_NUMBER
.long FLAGS
.long CHECKSUM
.section .boot_text
.global start
start:
cli
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
/* TSS-based protection domains use a multi-segment model that defines
* tight bounds around stacks. That means that the bottom of the stack
* has an offset of 0, which is the address of the stacks_main symbol.
* The following code computes the physical load address of the top of
* the stack, which is what should be initially used as the stack
* pointer while the flat memory model is in use.
*/
lea _sdata_addr, %eax
lea (stacks_main + STACKS_SIZE_MAIN)(%eax), %esp
#else
mov $(stacks_main + STACKS_SIZE_MAIN), %esp
#endif
call cpu_boot_stage0

View File

@ -1,48 +0,0 @@
/*
* 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_DMA_H_
#define CPU_X86_DMA_H_
#include "prot-domains.h"
#ifdef X86_CONF_RESTRICT_DMA
#define ATTR_BSS_DMA __attribute__((section(".dma_bss")))
#else
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define ATTR_BSS_DMA
#else
#define ATTR_BSS_DMA ATTR_BSS_META
#endif
#endif
extern int _ebss_pre_dma_addr, _sbss_dma_addr, _ebss_dma_addr;
#endif /* CPU_X86_DMA_H_ */

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2015, 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 "helpers.h"
#define NMI_ENABLE_PORT 0x70
void
nmi_enable(void)
{
uint8_t value = inb(NMI_ENABLE_PORT);
outb(NMI_ENABLE_PORT, value & ~BIT(8));
}
/*---------------------------------------------------------------------------*/
void
nmi_disable(void)
{
uint8_t value = inb(NMI_ENABLE_PORT);
outb(NMI_ENABLE_PORT, value | BIT(8));
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2015, 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 NMI_H
#define NMI_H
void nmi_enable(void);
void nmi_disable(void);
#endif /* NMI_H */

View File

@ -1,280 +0,0 @@
/*
* Copyright (C) 2015, 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 <assert.h>
#include "pci.h"
#include "helpers.h"
#include "syscalls.h"
/* I/O port for PCI configuration address */
#define PCI_CONFIG_ADDR_PORT 0xCF8
/* I/O port for PCI configuration data */
#define PCI_CONFIG_DATA_PORT 0xCFC
PROT_DOMAINS_ALLOC(dom_client_data_t, root_complex_drv);
/*---------------------------------------------------------------------------*/
/* Initialize PCI configuration register address in preparation for accessing
* the specified register.
*/
static void
set_addr(pci_config_addr_t addr)
{
addr.en_mapping = 1;
outl(PCI_CONFIG_ADDR_PORT, addr.raw);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Read from the specified PCI configuration register.
* \param addr Address of PCI configuration register.
* \return Value read from PCI configuration register.
*/
uint32_t
pci_config_read(pci_config_addr_t addr)
{
set_addr(addr);
return inl(PCI_CONFIG_DATA_PORT);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Write to the PCI configuration data port.
* \param addr Address of PCI configuration register.
* \param data Value to write.
*/
void
pci_config_write(pci_config_addr_t addr, uint32_t data)
{
set_addr(addr);
outl(PCI_CONFIG_DATA_PORT, data);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Enable PCI command bits of the specified PCI configuration
* register.
* \param addr Address of PCI configuration register.
* \param flags Flags used to enable PCI command bits.
*/
void
pci_command_enable(pci_config_addr_t addr, uint32_t flags)
{
uint32_t data;
addr.reg_off = 0x04; /* PCI COMMAND_REGISTER */
data = pci_config_read(addr);
pci_config_write(addr, data | flags);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set current PIRQ to interrupt queue agent. PCI based interrupts
* PIRQ[A:H] are then available for consumption by either the 8259
* PICs or the IO-APIC depending on configuration of the 8 PIRQx
* Routing Control Registers PIRQ[A:H]. See also pci_pirq_set_irq().
* \param agent Interrupt Queue Agent to be used, IRQAGENT[0:3].
* \param pin Interrupt Pin Route to be used, INT[A:D].
* \param pirq PIRQ to be used, PIRQ[A:H].
*/
SYSCALLS_DEFINE_SINGLETON(pci_irq_agent_set_pirq,
root_complex_drv,
IRQAGENT agent, INTR_PIN pin, PIRQ pirq)
{
uint16_t value;
uint32_t rcba_addr, offset = 0;
rcba_addr = PROT_DOMAINS_MMIO(root_complex_drv);
assert(agent >= IRQAGENT0 && agent <= IRQAGENT3);
assert(pin >= INTA && pin <= INTD);
assert(pirq >= PIRQA && pirq <= PIRQH);
switch(agent) {
case IRQAGENT0:
if(pin != INTA) {
halt();
}
offset = 0x3140;
break;
case IRQAGENT1:
offset = 0x3142;
break;
case IRQAGENT2:
if(pin != INTA) {
halt();
}
offset = 0x3144;
break;
case IRQAGENT3:
offset = 0x3146;
}
prot_domains_enable_mmio();
MMIO_READW(value, *(uint16_t ATTR_MMIO_ADDR_SPACE *)(rcba_addr + offset));
/* clear interrupt pin route and set corresponding pirq. */
switch(pin) {
case INTA:
value &= ~0xF;
value |= pirq;
break;
case INTB:
value &= ~0xF0;
value |= (pirq << 4);
break;
case INTC:
value &= ~0xF00;
value |= (pirq << 8);
break;
case INTD:
value &= ~0xF000;
value |= (pirq << 12);
}
MMIO_WRITEW(*(uint16_t ATTR_MMIO_ADDR_SPACE *)(rcba_addr + offset), value);
prot_domains_disable_mmio();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set current IRQ to PIRQ. The interrupt router can be
* programmed to allow PIRQ[A:H] to be routed internally
* to the 8259 as ISA compatible interrupts. See also
* pci_irq_agent_set_pirq().
* \param pirq PIRQ to be used, PIRQ[A:H].
* \param pin IRQ to be used, IRQ[0:15].
* \param route_to_legacy Whether or not the interrupt should be routed to PIC 8259.
*/
void
pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy)
{
pci_config_addr_t pci;
uint32_t value;
assert(pirq >= PIRQA && pirq <= PIRQH);
assert(irq >= 0 && irq <= 0xF);
assert(route_to_legacy == 0 || route_to_legacy == 1);
pci.raw = 0;
pci.bus = 0;
pci.dev = 31;
pci.func = 0;
pci.reg_off = (pirq <= PIRQD) ? 0x60 : 0x64; /* PABCDRC and PEFGHRC Registers */
value = pci_config_read(pci);
switch(pirq) {
case PIRQA:
case PIRQE:
value &= ~0x8F;
value |= irq;
value |= (!route_to_legacy << 7);
break;
case PIRQB:
case PIRQF:
value &= ~0x8F00;
value |= (irq << 8);
value |= (!route_to_legacy << 15);
break;
case PIRQC:
case PIRQG:
value &= ~0x8F0000;
value |= (irq << 16);
value |= (!route_to_legacy << 23);
break;
case PIRQD:
case PIRQH:
value &= ~0x8F000000;
value |= (irq << 24);
value |= (!route_to_legacy << 31);
}
set_addr(pci);
outl(PCI_CONFIG_DATA_PORT, value);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize a structure for a PCI device driver that performs
* MMIO to address range 0. Assumes that device has already
* been configured with an MMIO address range 0, e.g. by
* firmware.
* \param c_this Structure that will be initialized to represent the driver.
* \param pci_addr PCI base address of device.
* \param mmio_sz Size of MMIO region.
* \param meta Base address of optional driver-defined metadata.
* \param meta_sz Size of optional driver-defined metadata.
*/
void
pci_init(pci_driver_t ATTR_KERN_ADDR_SPACE *c_this,
pci_config_addr_t pci_addr,
size_t mmio_sz,
uintptr_t meta,
size_t meta_sz)
{
uintptr_t mmio;
/* The BAR value is masked to clear non-address bits. */
mmio = pci_config_read(pci_addr) & ~0xFFF;
prot_domains_reg(c_this, mmio, mmio_sz, meta, meta_sz, false);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize the PCI root complex driver.
*/
void
pci_root_complex_init(void)
{
uint32_t rcba_addr;
pci_config_addr_t pci = { .raw = 0 };
pci.dev = 31;
pci.reg_off = 0xF0; /* Root Complex Base Address Register */
/* masked to clear non-address bits. */
rcba_addr = pci_config_read(pci) & ~0x3FFF;
PROT_DOMAINS_INIT_ID(root_complex_drv);
prot_domains_reg(&root_complex_drv, rcba_addr, 0x4000, 0, 0, false);
SYSCALLS_INIT(pci_irq_agent_set_pirq);
SYSCALLS_AUTHZ(pci_irq_agent_set_pirq, root_complex_drv);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Prevent further invocations of pci_irq_agent_set_pirq.
*/
void
pci_root_complex_lock(void)
{
SYSCALLS_DEAUTHZ(pci_irq_agent_set_pirq, root_complex_drv);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,124 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_LEGACY_PC_PCI_H_
#define CPU_X86_DRIVERS_LEGACY_PC_PCI_H_
#include <stdint.h>
#include "helpers.h"
#include <stdlib.h>
#include "prot-domains.h"
/** PCI configuration register identifier for Base Address Registers */
#define PCI_CONFIG_REG_BAR0 0x10
#define PCI_CONFIG_REG_BAR1 0x14
/** PCI Interrupt Routing is mapped using Interrupt Queue Agents */
typedef enum {
IRQAGENT0,
IRQAGENT1,
IRQAGENT2,
IRQAGENT3
} IRQAGENT;
/** PCI Interupt Pins */
typedef enum {
INTA,
INTB,
INTC,
INTD
} INTR_PIN;
/**
* PCI based interrupts PIRQ[A:H] are then available for consumption by either
* the 8259 PICs or the IO-APIC.
*/
typedef enum {
PIRQA,
PIRQB,
PIRQC,
PIRQD,
PIRQE,
PIRQF,
PIRQG,
PIRQH,
} PIRQ;
/** PCI command register bit to enable bus mastering */
#define PCI_CMD_2_BUS_MST_EN BIT(2)
/** PCI command register bit to enable memory space */
#define PCI_CMD_1_MEM_SPACE_EN BIT(1)
/**
* PCI configuration address
*
* Refer to Intel Quark SoC X1000 Datasheet, Section 5.5 for more details on
* PCI configuration register access.
*/
typedef union pci_config_addr {
struct {
/** Register/offset number. Least-significant two bits should be zero. */
uint32_t reg_off : 8;
uint32_t func : 3; /**< Function number */
uint32_t dev : 5; /**< Device number */
uint32_t bus : 8; /**< Bus number */
uint32_t : 7;
/** Must be set to perform PCI configuration access. */
uint32_t en_mapping : 1;
};
uint32_t raw;
} pci_config_addr_t;
uint32_t pci_config_read(pci_config_addr_t addr);
void pci_config_write(pci_config_addr_t addr, uint32_t data);
void pci_command_enable(pci_config_addr_t addr, uint32_t flags);
typedef dom_client_data_t pci_driver_t;
void pci_init(pci_driver_t ATTR_KERN_ADDR_SPACE *c_this,
pci_config_addr_t pci_addr,
size_t mmio_sz,
uintptr_t meta,
size_t meta_sz);
void pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq);
void pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy);
void pci_root_complex_init(void);
void pci_root_complex_lock(void);
#define PCI_MMIO_READL(c_this, dest, reg_addr) \
MMIO_READL(dest, \
*((volatile uint32_t ATTR_MMIO_ADDR_SPACE *) \
(((uintptr_t)PROT_DOMAINS_MMIO(c_this)) + (reg_addr))))
#define PCI_MMIO_WRITEL(c_this, reg_addr, src) \
MMIO_WRITEL(*((volatile uint32_t ATTR_MMIO_ADDR_SPACE *) \
(((uintptr_t)PROT_DOMAINS_MMIO(c_this)) + (reg_addr))), \
src)
#endif /* CPU_X86_DRIVERS_LEGACY_PC_PCI_H_ */

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015, 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 "drivers/legacy_pc/pic.h"
#define PIC_ACK 0x20
void
pic_unmask_irq(unsigned int num)
{
uint16_t port;
uint8_t bitmap;
if(num <= 7) {
port = PIC1_DATA_PORT;
} else {
port = PIC2_DATA_PORT;
num -= 8;
}
bitmap = inb(port);
outb(port, bitmap & ~BIT(num));
}
/*---------------------------------------------------------------------------*/
void
pic_eoi(unsigned int irq)
{
if(irq >= 8) {
outb(PIC2_CMD_PORT, PIC_ACK);
}
outb(PIC1_CMD_PORT, PIC_ACK);
}

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2015, 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 PIC_H
#define PIC_H
#include "helpers.h"
#define PIC1_CMD_PORT 0x20
#define PIC1_DATA_PORT 0x21
#define PIC2_CMD_PORT 0xA0
#define PIC2_DATA_PORT 0xA1
#define PIC1_OFFSET 0x20
#define PIC2_OFFSET PIC1_OFFSET + 8
/*
* Returns the actual interrupt number of a given IRQ,
* no matter which PIC it is part of.
*/
#define PIC_INT(a) (a + PIC1_OFFSET)
void pic_unmask_irq(unsigned int num);
/* This function initializes the daisy-chained Master and Slave 8259 PICs.
* It is only called once, so let's give the compiler the option to inline it.
* For more information about the ICWs, please refer to http://stanislavs.org/helppc/8259.html.
*/
static inline void
pic_init(void)
{
/* ICW1: Initialization. */
outb(PIC1_CMD_PORT, 0x11);
outb(PIC2_CMD_PORT, 0x11);
/* ICW2: Remap IRQs by setting an IDT Offset for each PIC. */
outb(PIC1_DATA_PORT, PIC1_OFFSET);
outb(PIC2_DATA_PORT, PIC2_OFFSET);
/* ICW3: Setup Slave to Master's IRQ2. */
outb(PIC1_DATA_PORT, 0x04);
outb(PIC2_DATA_PORT, 0x02);
/* ICW4: Environment setup. Set PIC1 as master and PIC2 as slave. */
outb(PIC1_DATA_PORT, 0x01);
outb(PIC2_DATA_PORT, 0x01);
/* Set the IMR register, masking all hardware interrupts but IRQ 2.
* We will have to unmask each IRQ when registering them. */
outb(PIC1_DATA_PORT, 0xfb);
outb(PIC2_DATA_PORT, 0xff);
}
/*
* This function sends an end-of-interrupt (EOI) to the correct PIC according
* to the IRQ line number.
*/
void pic_eoi(unsigned int irq);
#endif /* PIC_H */

View File

@ -1,80 +0,0 @@
/*
* Copyright (C) 2015, 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 <math.h>
#include "drivers/legacy_pc/pic.h"
#include "drivers/legacy_pc/pit.h"
#include "helpers.h"
#include "interrupt.h"
/* PCs usually provide an 8254 PIT chip with maximum clock of 1.193182 MHz. */
#define PIT_CONTROL_PORT 0x43
#define PIT_COUNTER0_PORT 0x40
#define PIT_CLOCK_FREQUENCY 1193182
#define PIT_IRQ 0
#define PIT_INT PIC_INT(PIT_IRQ)
static pit_int_callback interrupt_cb;
static void
pit_int_handler(void)
{
interrupt_cb();
pic_eoi(PIT_IRQ);
}
/*---------------------------------------------------------------------------*/
void
pit_init(uint32_t ticks_rate, pit_int_callback cb)
{
SET_INTERRUPT_HANDLER(PIT_INT, 0, pit_int_handler);
interrupt_cb = cb;
/* Calculate the 16bit divisor that can provide the chosen clock tick rate
* (CLOCK_CONF_SECOND in contiki-conf.h). For reference --> tick rate = clock frequency / divisor.
* If we provide an odd divisor to the Square Wave generator (Mode 3) of
* the Counter0, the duty cycle won't be exactly 50%, so we always round
* it to nearest even integer.
*/
uint16_t divisor = rint(PIT_CLOCK_FREQUENCY / ticks_rate);
/* Setup Control register flags in a didactic way. */
uint8_t flags = 0x30; /* Set bits 7:6 to select Counter0 and 5:4 to select "write 7:0 bits first". */
flags |= 0x6; /* Set bits 3:1 to Mode 3 and bit 0 to BCD off. */
outb(PIT_CONTROL_PORT, flags);
outb(PIT_COUNTER0_PORT, divisor & 0xFF); /* Write least significant bytes first. */
outb(PIT_COUNTER0_PORT, (divisor >> 8) & 0xFF);
pic_unmask_irq(PIT_IRQ);
}

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) 2015, 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 PIT_H
#define PIT_H
#include <stdint.h>
typedef void (*pit_int_callback)(void);
/**
* Initializes the 8254 Programmable Interrupt Timer chip (Counter 0 only).
* The PIT Interrupt callback is implemented by the driver's users. It is
* called from interrupt context, so it has to return as soon as possible.
*/
void pit_init(uint32_t ticks_rate, pit_int_callback c);
#endif /* PIT_H */

View File

@ -1,95 +0,0 @@
/*
* Copyright (C) 2015, 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 "drivers/legacy_pc/rtc.h"
#include "drivers/legacy_pc/pic.h"
#include "drivers/legacy_pc/nmi.h"
#include "helpers.h"
#include "interrupt.h"
#define RTC_INDEX_REGISTER 0x70
#define RTC_TARGET_REGISTER 0x71
#define RTC_IRQ 8
#define RTC_INT PIC_INT(RTC_IRQ)
static void (*user_callback)(void);
static void
rtc_handler()
{
user_callback();
/* Clear Register C otherwise interrupts will not happen again.
* Register C is automatically cleared when it is read so we do
* a dummy read to clear it.
*/
outb(RTC_INDEX_REGISTER, 0x0C);
inb(RTC_TARGET_REGISTER);
/* Issue the End of Interrupt to PIC */
pic_eoi(RTC_IRQ);
}
/*---------------------------------------------------------------------------*/
/* Initialize the Real Time Clock.
* @frequency: RTC has very specific values for frequency. They are: 2, 4, 8,
* 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, and 8192 Hz.
* value otherwise it will not work properly.
* @callback: This callback is called every time the RTC IRQ is raised.
* It is executed in interrupt context.
*/
void
rtc_init(rtc_frequency_t frequency, void (*callback)(void))
{
uint8_t reg_a, reg_b;
user_callback = callback;
SET_INTERRUPT_HANDLER(RTC_INT, 0, rtc_handler);
nmi_disable();
/* Select interrupt period to 7.8125 ms */
outb(RTC_INDEX_REGISTER, 0x8A);
reg_a = inb(RTC_TARGET_REGISTER);
reg_a &= 0xF0;
reg_a |= frequency;
outb(RTC_INDEX_REGISTER, 0x8A);
outb(RTC_TARGET_REGISTER, reg_a);
/* Enable periodic interrupt */
outb(RTC_INDEX_REGISTER, 0x8B);
reg_b = inb(RTC_TARGET_REGISTER);
outb(RTC_INDEX_REGISTER, 0x8B);
outb(RTC_TARGET_REGISTER, reg_b | BIT(6));
nmi_enable();
pic_unmask_irq(RTC_IRQ);
}

View File

@ -1,52 +0,0 @@
/*
* Copyright (C) 2015, 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 RTC_H
#define RTC_H
typedef enum {
RTC_8192_HZ = 2,
RTC_4096_HZ = 3,
RTC_2048_HZ = 4,
RTC_1024_HZ = 5,
RTC_512_HZ = 6,
RTC_256_HZ = 7,
RTC_128_HZ = 8,
RTC_64_HZ = 9,
RTC_32_HZ = 10,
RTC_16_HZ = 11,
RTC_8_HZ = 12,
RTC_4_HZ = 13,
RTC_2_HZ = 14,
} rtc_frequency_t;
void rtc_init(rtc_frequency_t frequency, void (*callback)(void));
#endif /* RTC_H */

View File

@ -1,107 +0,0 @@
/*
* 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.
*/
#include <assert.h>
#include "idt.h"
#include "interrupt.h"
#include "pic.h"
#include "shared-isr.h"
/* Defined in linker script */
extern shared_isr_client_t _sdata_shared_isr, _edata_shared_isr;
static void __attribute__((used))
shared_handler(void)
{
shared_isr_client_t *client;
for(client = &_sdata_shared_isr; client < &_edata_shared_isr; client++) {
if(client->handler()) {
pic_eoi(client->irq);
return;
}
}
}
/**
* \brief Initialize shared ISR by iterating through all of its clients and
* configuring their interrupts to route to the shared ISR.
*/
void
shared_isr_init(void)
{
shared_isr_client_t *client = &_sdata_shared_isr;
shared_isr_client_t *consistency_check_client;
bool prev_conf;
void shared_isr_stub(void);
__asm__ __volatile__ (
ISR_STUB("shared_isr_stub", 0, "shared_handler", 0)
:
);
while(client < &_edata_shared_isr) {
consistency_check_client = &_sdata_shared_isr;
prev_conf = false;
while(consistency_check_client < client) {
if((client->irq == consistency_check_client->irq) ||
(client->pin == consistency_check_client->pin) ||
(client->pirq == consistency_check_client->pirq)) {
prev_conf = true;
/* This interrupt was previously configured. */
break;
}
consistency_check_client++;
}
if(prev_conf) {
/* The requested configurations for each IRQ must be consistent. */
assert((client->irq == consistency_check_client->irq) &&
(client->agent == consistency_check_client->agent) &&
(client->pin == consistency_check_client->pin) &&
(client->pirq == consistency_check_client->pirq));
} else {
idt_set_intr_gate_desc(PIC_INT(client->irq), (uint32_t)shared_isr_stub,
GDT_SEL_CODE_INT, PRIV_LVL_INT);
pci_irq_agent_set_pirq(client->agent, client->pin, client->pirq);
pci_pirq_set_irq(client->pirq, client->irq, 1);
pic_unmask_irq(client->irq);
}
client++;
}
}

View File

@ -1,67 +0,0 @@
/*
* 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_DRIVERS_LEGACY_PC_SHARED_ISR_H_
#define CPU_X86_DRIVERS_LEGACY_PC_SHARED_ISR_H_
#include <stdbool.h>
#include "pci.h"
/**
* The handler function should return true if and only if it handled the
* interrupt.
*/
typedef bool (*shared_isr_handler_t)(void);
typedef struct shared_isr_client {
uint8_t irq;
IRQAGENT agent;
INTR_PIN pin;
PIRQ pirq;
shared_isr_handler_t handler;
} shared_isr_client_t;
/* Unlike a non-shared interrupt handler function, an individual interrupt
* handler for a shared interrupt must not issue an EOI. The EOI is issued by
* the shared-isr subsystem.
*/
#define DEFINE_SHARED_IRQ(irq_, agent_, pin_, pirq_, handler_) \
static struct shared_isr_client \
__attribute__((used, section(".shared_isr_data"))) _shared_irq_##irq_ = { \
.irq = irq_, \
.agent = agent_, \
.pin = pin_, \
.pirq = pirq_, \
.handler = handler_ \
}
void shared_isr_init(void);
#endif /* CPU_X86_DRIVERS_LEGACY_PC_SHARED_ISR_H_ */

View File

@ -1,179 +0,0 @@
/*
* Copyright (C) 2015, 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 <stdlib.h>
#include "helpers.h"
#include "paging.h"
#include "prot-domains.h"
#include "syscalls.h"
#include "uart-16x50.h"
/* Refer to Intel Quark SoC X1000 Datasheet, Chapter 18 for more details on
* UART operation.
*/
/* Divisor Latch Access Bit (DLAB) mask for Line Control Register (LCR).
*
* When bit is set, enables access to divisor registers to set baud rate. When
* clear, enables access to other registers mapped to the same addresses as the
* divisor registers.
*/
#define UART_LCR_7_DLAB BIT(7)
/* Setting for LCR that configures the UART to operate with no parity, 1 stop
* bit, and eight bits per character.
*/
#define UART_LCR_8BITS 0x03
/* FIFO Control Register (FCR) bitmasks */
#define UART_FCR_0_FIFOE BIT(0) /*< enable FIFOs */
#define UART_FCR_1_RFIFOR BIT(1) /*< reset RX FIFO */
#define UART_FCR_2_XFIFOR BIT(2) /*< reset TX FIFO */
/* Line Status Register (LSR) Transmit Holding Register Empty bitmask to check
* whether the Transmit Holding Register (THR) or TX FIFO is empty.
*/
#define UART_LSR_5_THRE BIT(5)
/* MMIO registers for UART */
typedef struct uart_16x50_regs {
volatile uint32_t rbr_thr_dll, ier_dlh, iir_fcr, lcr;
volatile uint32_t mcr, lsr, msr, scr, usr, htx, dmasa;
} uart_16x50_regs_t;
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
/* When paging-based protection domains are in use, at least one page of memory
* must be reserved to facilitate access to the MMIO region, since that is the
* smallest unit of memory that can be managed with paging:
*/
#define UART_MMIO_SZ MIN_PAGE_SIZE
#else
/* Multi-segment protection domain implementations can control memory with
* byte granularity. Thus, only the registers defined in the uart_16x50_regs
* structure are included in the MMIO region allocated for this protection
* domain:
*/
#define UART_MMIO_SZ sizeof(uart_16x50_regs_t)
#endif
void uart_16x50_setup(uart_16x50_driver_t c_this, uint16_t dl);
/*---------------------------------------------------------------------------*/
SYSCALLS_DEFINE(uart_16x50_setup, uart_16x50_driver_t c_this, uint16_t dl)
{
uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *regs =
(uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *)PROT_DOMAINS_MMIO(c_this);
prot_domains_enable_mmio();
/* Set the DLAB bit to enable access to divisor settings. */
MMIO_WRITEL(regs->lcr, UART_LCR_7_DLAB);
/* The divisor settings configure the baud rate, and may need to be defined
* on a per-device basis.
*/
MMIO_WRITEL(regs->rbr_thr_dll, dl & UINT8_MAX);
MMIO_WRITEL(regs->ier_dlh, dl >> 8);
/* Clear the DLAB bit to enable access to other settings and configure other
* UART parameters.
*/
MMIO_WRITEL(regs->lcr, UART_LCR_8BITS);
/* Enable the FIFOs. */
MMIO_WRITEL(regs->iir_fcr,
UART_FCR_0_FIFOE | UART_FCR_1_RFIFOR | UART_FCR_2_XFIFOR);
prot_domains_disable_mmio();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Transmit a character through a UART.
* \param c_this Initialized structure representing the device.
* \param c Character to be transmitted.
*
* This procedure will block indefinitely until the UART is ready
* to accept the character to be transmitted.
*/
SYSCALLS_DEFINE(uart_16x50_tx, uart_16x50_driver_t c_this, uint8_t c)
{
uint32_t ready;
uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *regs =
(uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *)PROT_DOMAINS_MMIO(c_this);
prot_domains_enable_mmio();
/* Wait for space in TX FIFO. */
do {
MMIO_READL(ready, regs->lsr);
} while((ready & UART_LSR_5_THRE) == 0);
/* Add character to TX FIFO. */
MMIO_WRITEL(regs->rbr_thr_dll, c);
prot_domains_disable_mmio();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Perform common initialization that must precede per-port
* initialization.
*/
/*---------------------------------------------------------------------------*/
void
uart_16x50_init(void)
{
SYSCALLS_INIT(uart_16x50_setup);
SYSCALLS_INIT(uart_16x50_tx);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize an MMIO-programmable 16X50 UART.
* \param c_this Structure that will be initialized to represent the device.
* \param pci_addr PCI address of device.
* \param dl Divisor setting to configure the baud rate.
*/
void
uart_16x50_init_port(uart_16x50_driver_t ATTR_KERN_ADDR_SPACE *c_this,
pci_config_addr_t pci_addr,
uint16_t dl)
{
uart_16x50_driver_t loc_c_this;
/* This assumes that the UART had an MMIO range assigned to it by the
* firmware during boot.
*/
pci_init(c_this, pci_addr, UART_MMIO_SZ, 0, 0);
SYSCALLS_AUTHZ(uart_16x50_setup, *c_this);
SYSCALLS_AUTHZ(uart_16x50_tx, *c_this);
prot_domains_copy_dcd(&loc_c_this, c_this);
uart_16x50_setup(loc_c_this, dl);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,46 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_LEGACY_PC_UART_16X50_H_
#define CPU_X86_DRIVERS_LEGACY_PC_UART_16X50_H_
#include "pci.h"
typedef pci_driver_t uart_16x50_driver_t;
void uart_16x50_init(void);
void uart_16x50_init_port(uart_16x50_driver_t ATTR_KERN_ADDR_SPACE *c_this,
pci_config_addr_t pci_addr,
uint16_t dl);
void uart_16x50_tx(uart_16x50_driver_t c_this, uint8_t c);
#endif /* CPU_X86_DRIVERS_LEGACY_PC_UART_16X50_H_ */

View File

@ -1,465 +0,0 @@
/*
* Copyright (C) 2015, 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 <string.h>
#include <assert.h>
#include <stdio.h>
#include "contiki-net.h"
#include "dma.h"
#include "eth.h"
#include "helpers.h"
#include "syscalls.h"
#include "net/ip/uip.h"
#include "pci.h"
typedef pci_driver_t quarkX1000_eth_driver_t;
/* Refer to Intel Quark SoC X1000 Datasheet, Chapter 15 for more details on
* Ethernet device operation.
*
* This driver puts the Ethernet device into a very simple and space-efficient
* mode of operation. It only allocates a single packet descriptor for each of
* the transmit and receive directions, computes checksums on the CPU, and
* enables store-and-forward mode for both transmit and receive directions.
*/
/* Transmit descriptor */
typedef struct quarkX1000_eth_tx_desc {
/* First word of transmit descriptor */
union {
struct {
/* Only valid in half-duplex mode. */
uint32_t deferred_bit : 1;
uint32_t err_underflow : 1;
uint32_t err_excess_defer : 1;
uint32_t coll_cnt_slot_num : 4;
uint32_t vlan_frm : 1;
uint32_t err_excess_coll : 1;
uint32_t err_late_coll : 1;
uint32_t err_no_carrier : 1;
uint32_t err_carrier_loss : 1;
uint32_t err_ip_payload : 1;
uint32_t err_frm_flushed : 1;
uint32_t err_jabber_tout : 1;
/* OR of all other error bits. */
uint32_t err_summary : 1;
uint32_t err_ip_hdr : 1;
uint32_t tx_timestamp_stat : 1;
uint32_t vlan_ins_ctrl : 2;
uint32_t addr2_chained : 1;
uint32_t tx_end_of_ring : 1;
uint32_t chksum_ins_ctrl : 2;
uint32_t replace_crc : 1;
uint32_t tx_timestamp_en : 1;
uint32_t dis_pad : 1;
uint32_t dis_crc : 1;
uint32_t first_seg_in_frm : 1;
uint32_t last_seg_in_frm : 1;
uint32_t intr_on_complete : 1;
/* When set, descriptor is owned by DMA. */
uint32_t own : 1;
};
uint32_t tdes0;
};
/* Second word of transmit descriptor */
union {
struct {
uint32_t tx_buf1_sz : 13;
uint32_t : 3;
uint32_t tx_buf2_sz : 13;
uint32_t src_addr_ins_ctrl : 3;
};
uint32_t tdes1;
};
/* Pointer to frame data buffer */
uint8_t *buf1_ptr;
/* Unused, since this driver initializes only a single descriptor for each
* direction.
*/
uint8_t *buf2_ptr;
} quarkX1000_eth_tx_desc_t;
/* Transmit descriptor */
typedef struct quarkX1000_eth_rx_desc {
/* First word of receive descriptor */
union {
struct {
uint32_t ext_stat : 1;
uint32_t err_crc : 1;
uint32_t err_dribble_bit : 1;
uint32_t err_rx_mii : 1;
uint32_t err_rx_wdt : 1;
uint32_t frm_type : 1;
uint32_t err_late_coll : 1;
uint32_t giant_frm : 1;
uint32_t last_desc : 1;
uint32_t first_desc : 1;
uint32_t vlan_tag : 1;
uint32_t err_overflow : 1;
uint32_t length_err : 1;
uint32_t s_addr_filt_fail : 1;
uint32_t err_desc : 1;
uint32_t err_summary : 1;
uint32_t frm_len : 14;
uint32_t d_addr_filt_fail : 1;
uint32_t own : 1;
};
uint32_t rdes0;
};
/* Second word of receive descriptor */
union {
struct {
uint32_t rx_buf1_sz : 13;
uint32_t : 1;
uint32_t addr2_chained : 1;
uint32_t rx_end_of_ring : 1;
uint32_t rx_buf2_sz : 13;
uint32_t : 2;
uint32_t dis_int_compl : 1;
};
uint32_t rdes1;
};
/* Pointer to frame data buffer */
uint8_t *buf1_ptr;
/* Unused, since this driver initializes only a single descriptor for each
* direction.
*/
uint8_t *buf2_ptr;
} quarkX1000_eth_rx_desc_t;
/* Driver metadata associated with each Ethernet device */
typedef struct quarkX1000_eth_meta {
/* Transmit descriptor */
volatile quarkX1000_eth_tx_desc_t tx_desc;
/* Transmit DMA packet buffer */
volatile uint8_t tx_buf[ALIGN(UIP_BUFSIZE, 4)];
/* Receive descriptor */
volatile quarkX1000_eth_rx_desc_t rx_desc;
/* Receive DMA packet buffer */
volatile uint8_t rx_buf[ALIGN(UIP_BUFSIZE, 4)];
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
/* Domain-defined metadata must fill an even number of pages, since that is
* the minimum granularity of access control supported by paging. However,
* using the "aligned(4096)" attribute causes the alignment of the kernel
* data section to increase, which causes problems when generating UEFI
* binaries, as is described in the linker script. Thus, it is necessary
* to manually pad the structure to fill a page. This only works if the
* sizes of the actual fields of the structure are collectively less than a
* page.
*/
uint8_t pad[MIN_PAGE_SIZE -
(sizeof(quarkX1000_eth_tx_desc_t) +
ALIGN(UIP_BUFSIZE, 4) +
sizeof(quarkX1000_eth_rx_desc_t) +
ALIGN(UIP_BUFSIZE, 4))];
#endif
} __attribute__((packed)) quarkX1000_eth_meta_t;
#define LOG_PFX "quarkX1000_eth: "
#define MMIO_SZ 0x2000
#define MAC_CONF_14_RMII_100M BIT(14)
#define MAC_CONF_11_DUPLEX BIT(11)
#define MAC_CONF_3_TX_EN BIT(3)
#define MAC_CONF_2_RX_EN BIT(2)
#define OP_MODE_25_RX_STORE_N_FORWARD BIT(25)
#define OP_MODE_21_TX_STORE_N_FORWARD BIT(21)
#define OP_MODE_13_START_TX BIT(13)
#define OP_MODE_1_START_RX BIT(1)
#define REG_ADDR_MAC_CONF 0x0000
#define REG_ADDR_MACADDR_HI 0x0040
#define REG_ADDR_MACADDR_LO 0x0044
#define REG_ADDR_TX_POLL_DEMAND 0x1004
#define REG_ADDR_RX_POLL_DEMAND 0x1008
#define REG_ADDR_RX_DESC_LIST 0x100C
#define REG_ADDR_TX_DESC_LIST 0x1010
#define REG_ADDR_DMA_OPERATION 0x1018
PROT_DOMAINS_ALLOC(quarkX1000_eth_driver_t, drv);
static quarkX1000_eth_meta_t ATTR_BSS_DMA meta;
void quarkX1000_eth_setup(uintptr_t meta_phys_base);
/*---------------------------------------------------------------------------*/
SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_setup, drv, uintptr_t meta_phys_base)
{
uip_eth_addr mac_addr;
uint32_t mac_tmp1, mac_tmp2;
quarkX1000_eth_rx_desc_t rx_desc;
quarkX1000_eth_tx_desc_t tx_desc;
quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
(quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
prot_domains_enable_mmio();
/* Read the MAC address from the device. */
PCI_MMIO_READL(drv, mac_tmp1, REG_ADDR_MACADDR_HI);
PCI_MMIO_READL(drv, mac_tmp2, REG_ADDR_MACADDR_LO);
prot_domains_disable_mmio();
/* Convert the data read from the device into the format expected by
* Contiki.
*/
mac_addr.addr[5] = (uint8_t)(mac_tmp1 >> 8);
mac_addr.addr[4] = (uint8_t)mac_tmp1;
mac_addr.addr[3] = (uint8_t)(mac_tmp2 >> 24);
mac_addr.addr[2] = (uint8_t)(mac_tmp2 >> 16);
mac_addr.addr[1] = (uint8_t)(mac_tmp2 >> 8);
mac_addr.addr[0] = (uint8_t)mac_tmp2;
printf(LOG_PFX "MAC address = %02x:%02x:%02x:%02x:%02x:%02x.\n",
mac_addr.addr[0],
mac_addr.addr[1],
mac_addr.addr[2],
mac_addr.addr[3],
mac_addr.addr[4],
mac_addr.addr[5]
);
uip_setethaddr(mac_addr);
/* Initialize transmit descriptor. */
tx_desc.tdes0 = 0;
tx_desc.tdes1 = 0;
tx_desc.tx_end_of_ring = 1;
tx_desc.first_seg_in_frm = 1;
tx_desc.last_seg_in_frm = 1;
tx_desc.tx_end_of_ring = 1;
META_WRITEL(loc_meta->tx_desc.tdes0, tx_desc.tdes0);
META_WRITEL(loc_meta->tx_desc.tdes1, tx_desc.tdes1);
META_WRITEL(loc_meta->tx_desc.buf1_ptr,
(uint8_t *)PROT_DOMAINS_META_OFF_TO_PHYS(
(uintptr_t)&loc_meta->tx_buf, meta_phys_base));
META_WRITEL(loc_meta->tx_desc.buf2_ptr, 0);
/* Initialize receive descriptor. */
rx_desc.rdes0 = 0;
rx_desc.rdes1 = 0;
rx_desc.own = 1;
rx_desc.first_desc = 1;
rx_desc.last_desc = 1;
rx_desc.rx_buf1_sz = UIP_BUFSIZE;
rx_desc.rx_end_of_ring = 1;
META_WRITEL(loc_meta->rx_desc.rdes0, rx_desc.rdes0);
META_WRITEL(loc_meta->rx_desc.rdes1, rx_desc.rdes1);
META_WRITEL(loc_meta->rx_desc.buf1_ptr,
(uint8_t *)PROT_DOMAINS_META_OFF_TO_PHYS(
(uintptr_t)&loc_meta->rx_buf, meta_phys_base));
META_WRITEL(loc_meta->rx_desc.buf2_ptr, 0);
prot_domains_enable_mmio();
/* Install transmit and receive descriptors. */
PCI_MMIO_WRITEL(drv, REG_ADDR_RX_DESC_LIST,
PROT_DOMAINS_META_OFF_TO_PHYS(
(uintptr_t)&loc_meta->rx_desc, meta_phys_base));
PCI_MMIO_WRITEL(drv, REG_ADDR_TX_DESC_LIST,
PROT_DOMAINS_META_OFF_TO_PHYS(
(uintptr_t)&loc_meta->tx_desc, meta_phys_base));
PCI_MMIO_WRITEL(drv, REG_ADDR_MAC_CONF,
/* Set the RMII speed to 100Mbps */
MAC_CONF_14_RMII_100M |
/* Enable full-duplex mode */
MAC_CONF_11_DUPLEX |
/* Enable transmitter */
MAC_CONF_3_TX_EN |
/* Enable receiver */
MAC_CONF_2_RX_EN);
PCI_MMIO_WRITEL(drv, REG_ADDR_DMA_OPERATION,
/* Enable receive store-and-forward mode for simplicity. */
OP_MODE_25_RX_STORE_N_FORWARD |
/* Enable transmit store-and-forward mode for simplicity. */
OP_MODE_21_TX_STORE_N_FORWARD |
/* Place the transmitter state machine in the Running
state. */
OP_MODE_13_START_TX |
/* Place the receiver state machine in the Running state. */
OP_MODE_1_START_RX);
prot_domains_disable_mmio();
printf(LOG_PFX "Enabled 100M full-duplex mode.\n");
}
/*---------------------------------------------------------------------------*/
/**
* \brief Poll for a received Ethernet frame.
* \param frame_len Will be set to the size of the received Ethernet frame or
* zero if no frame is available.
*
* If a frame is received, this procedure copies it into the
* global uip_buf buffer.
*/
SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_poll, drv, uint16_t * frame_len)
{
uint16_t *loc_frame_len;
uint16_t frm_len = 0;
quarkX1000_eth_rx_desc_t tmp_desc;
quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
(quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
PROT_DOMAINS_VALIDATE_PTR(loc_frame_len, frame_len, sizeof(*frame_len));
META_READL(tmp_desc.rdes0, loc_meta->rx_desc.rdes0);
/* Check whether the RX descriptor is still owned by the device. If not,
* process the received frame or an error that may have occurred.
*/
if(tmp_desc.own == 0) {
META_READL(tmp_desc.rdes1, loc_meta->rx_desc.rdes1);
if(tmp_desc.err_summary) {
fprintf(stderr,
LOG_PFX "Error receiving frame: RDES0 = %08x, RDES1 = %08x.\n",
tmp_desc.rdes0, tmp_desc.rdes1);
assert(0);
}
frm_len = tmp_desc.frm_len;
assert(frm_len <= UIP_BUFSIZE);
MEMCPY_FROM_META(uip_buf, loc_meta->rx_buf, frm_len);
/* Return ownership of the RX descriptor to the device. */
tmp_desc.own = 1;
META_WRITEL(loc_meta->rx_desc.rdes0, tmp_desc.rdes0);
prot_domains_enable_mmio();
/* Request that the device check for an available RX descriptor, since
* ownership of the descriptor was just transferred to the device.
*/
PCI_MMIO_WRITEL(drv, REG_ADDR_RX_POLL_DEMAND, 1);
prot_domains_disable_mmio();
}
*loc_frame_len = frm_len;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Transmit the current Ethernet frame.
*
* This procedure will block indefinitely until the Ethernet device is
* ready to accept a new outgoing frame. It then copies the current
* Ethernet frame from the global uip_buf buffer to the device DMA
* buffer and signals to the device that a new frame is available to be
* transmitted.
*/
SYSCALLS_DEFINE_SINGLETON(quarkX1000_eth_send, drv)
{
quarkX1000_eth_tx_desc_t tmp_desc;
quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *loc_meta =
(quarkX1000_eth_meta_t ATTR_META_ADDR_SPACE *)PROT_DOMAINS_META(drv);
/* Wait until the TX descriptor is no longer owned by the device. */
do {
META_READL(tmp_desc.tdes0, loc_meta->tx_desc.tdes0);
} while(tmp_desc.own == 1);
META_READL(tmp_desc.tdes1, loc_meta->tx_desc.tdes1);
/* Check whether an error occurred transmitting the previous frame. */
if(tmp_desc.err_summary) {
fprintf(stderr,
LOG_PFX "Error transmitting frame: TDES0 = %08x, TDES1 = %08x.\n",
tmp_desc.tdes0, tmp_desc.tdes1);
assert(0);
}
/* Transmit the next frame. */
assert(uip_len <= UIP_BUFSIZE);
MEMCPY_TO_META(loc_meta->tx_buf, uip_buf, uip_len);
tmp_desc.tx_buf1_sz = uip_len;
META_WRITEL(loc_meta->tx_desc.tdes1, tmp_desc.tdes1);
tmp_desc.own = 1;
META_WRITEL(loc_meta->tx_desc.tdes0, tmp_desc.tdes0);
prot_domains_enable_mmio();
/* Request that the device check for an available TX descriptor, since
* ownership of the descriptor was just transferred to the device.
*/
PCI_MMIO_WRITEL(drv, REG_ADDR_TX_POLL_DEMAND, 1);
prot_domains_disable_mmio();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize the first Quark X1000 Ethernet MAC.
*
* This procedure assumes that an MMIO range for the device was
* previously assigned, e.g. by firmware.
*/
void
quarkX1000_eth_init(void)
{
pci_config_addr_t pci_addr = { .raw = 0 };
/* PCI address from section 15.4 of Intel Quark SoC X1000 Datasheet. */
pci_addr.dev = 20;
pci_addr.func = 6;
/* Activate MMIO and DMA access. */
pci_command_enable(pci_addr, PCI_CMD_2_BUS_MST_EN | PCI_CMD_1_MEM_SPACE_EN);
printf(LOG_PFX "Activated MMIO and DMA access.\n");
pci_addr.reg_off = PCI_CONFIG_REG_BAR0;
PROT_DOMAINS_INIT_ID(drv);
/* Configure the device MMIO range and initialize the driver structure. */
pci_init(&drv, pci_addr, MMIO_SZ,
(uintptr_t)&meta, sizeof(quarkX1000_eth_meta_t));
SYSCALLS_INIT(quarkX1000_eth_setup);
SYSCALLS_AUTHZ(quarkX1000_eth_setup, drv);
SYSCALLS_INIT(quarkX1000_eth_poll);
SYSCALLS_AUTHZ(quarkX1000_eth_poll, drv);
SYSCALLS_INIT(quarkX1000_eth_send);
SYSCALLS_AUTHZ(quarkX1000_eth_send, drv);
quarkX1000_eth_setup(prot_domains_lookup_meta_phys_base(&drv));
}
/*---------------------------------------------------------------------------*/

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_QUARKX1000_ETH_H_
#define CPU_X86_DRIVERS_QUARKX1000_ETH_H_
#include <stdint.h>
void quarkX1000_eth_init(void);
void quarkX1000_eth_poll(uint16_t *frame_len);
void quarkX1000_eth_send(void);
#endif /* CPU_X86_DRIVERS_QUARKX1000_ETH_H_ */

View File

@ -1,292 +0,0 @@
/*
* 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 "gpio.h"
#include <stdbool.h>
#include "helpers.h"
#include "paging.h"
#include "shared-isr.h"
#include "syscalls.h"
/* GPIO Controler Registers */
#define SWPORTA_DR 0x00
#define SWPORTA_DDR 0x04
#define INTEN 0x30
#define INTMASK 0x34
#define INTTYPE_LEVEL 0x38
#define INT_POLARITY 0x3c
#define INTSTATUS 0x40
#define RAW_INTSTATUS 0x44
#define DEBOUNCE 0x48
#define PORTA_EOI 0x4c
#define EXT_PORTA 0x50
#define LS_SYNC 0x60
#define PINS 8
#define GPIO_IRQ 9
#define HIGHEST_REG LS_SYNC
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
#define MMIO_SZ MIN_PAGE_SIZE
#else
#define MMIO_SZ (HIGHEST_REG + 4)
#endif
PROT_DOMAINS_ALLOC(pci_driver_t, drv);
struct gpio_internal_data {
quarkX1000_gpio_callback callback;
};
static struct gpio_internal_data data;
void quarkX1000_gpio_mmin(uint32_t offset, uint32_t *res);
SYSCALLS_DEFINE_SINGLETON(quarkX1000_gpio_mmin, drv,
uint32_t offset, uint32_t *res)
{
uint32_t *loc_res;
PROT_DOMAINS_VALIDATE_PTR(loc_res, res, sizeof(*res));
if(HIGHEST_REG < offset) {
halt();
}
prot_domains_enable_mmio();
PCI_MMIO_READL(drv, *loc_res, offset);
prot_domains_disable_mmio();
}
static inline uint32_t
read(uint32_t offset)
{
uint32_t res;
quarkX1000_gpio_mmin(offset, &res);
return res;
}
void quarkX1000_gpio_mmout(uint32_t offset, uint32_t val);
SYSCALLS_DEFINE_SINGLETON(quarkX1000_gpio_mmout, drv,
uint32_t offset, uint32_t val)
{
if(HIGHEST_REG < offset) {
halt();
}
prot_domains_enable_mmio();
PCI_MMIO_WRITEL(drv, offset, val);
prot_domains_disable_mmio();
}
static inline void
write(uint32_t offset, uint32_t val)
{
quarkX1000_gpio_mmout(offset, val);
}
/* value must be 0x0 or 0x1 */
static void
set_bit(uint32_t offset, uint32_t bit, uint32_t value)
{
uint32_t reg;
reg = read(offset);
reg &= ~BIT(bit);
reg |= value << bit;
write(offset, reg);
}
static bool
gpio_isr(void)
{
uint32_t int_status;
int_status = read(INTSTATUS);
if(int_status == 0) {
return false;
}
if (data.callback)
data.callback(int_status);
write(PORTA_EOI, -1);
return true;
}
static void
gpio_interrupt_config(uint8_t pin, int flags)
{
/* set as input */
set_bit(SWPORTA_DDR, pin, 0);
/* set interrupt enabled */
set_bit(INTEN, pin, 1);
/* unmask interrupt */
set_bit(INTMASK, pin, 0);
/* set active high/low */
set_bit(INT_POLARITY, pin, !!(flags & QUARKX1000_GPIO_ACTIVE_HIGH));
/* set level/edge */
set_bit(INTTYPE_LEVEL, pin, !!(flags & QUARKX1000_GPIO_EDGE));
/* set debounce */
set_bit(DEBOUNCE, pin, !!(flags & QUARKX1000_GPIO_DEBOUNCE));
/* set clock synchronous */
set_bit(LS_SYNC, 0, !!(flags & QUARKX1000_GPIO_CLOCK_SYNC));
}
int
quarkX1000_gpio_config(uint8_t pin, int flags)
{
if (((flags & QUARKX1000_GPIO_IN) && (flags & QUARKX1000_GPIO_OUT)) ||
((flags & QUARKX1000_GPIO_INT) && (flags & QUARKX1000_GPIO_OUT))) {
return -1;
}
if (flags & QUARKX1000_GPIO_INT) {
gpio_interrupt_config(pin, flags);
} else {
/* set direction */
set_bit(SWPORTA_DDR, pin, !!(flags & QUARKX1000_GPIO_OUT));
/* set interrupt disabled */
set_bit(INTEN, pin, 0);
}
return 0;
}
int
quarkX1000_gpio_config_port(int flags)
{
uint8_t i;
for (i = 0; i < PINS; i++) {
if (quarkX1000_gpio_config(i, flags) < 0) {
return -1;
}
}
return 0;
}
int
quarkX1000_gpio_read(uint8_t pin, uint8_t *value)
{
uint32_t value32 = read(EXT_PORTA);
*value = !!(value32 & BIT(pin));
return 0;
}
int
quarkX1000_gpio_write(uint8_t pin, uint8_t value)
{
set_bit(SWPORTA_DR, pin, !!value);
return 0;
}
int
quarkX1000_gpio_read_port(uint8_t *value)
{
uint32_t value32 = read(EXT_PORTA);
*value = value32 & ~0xFFFFFF00;
return 0;
}
int
quarkX1000_gpio_write_port(uint8_t value)
{
write(SWPORTA_DR, value);
return 0;
}
int
quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback)
{
data.callback = callback;
return 0;
}
void
quarkX1000_gpio_clock_enable(void)
{
set_bit(LS_SYNC, 0, 1);
}
void
quarkX1000_gpio_clock_disable(void)
{
set_bit(LS_SYNC, 0, 0);
}
DEFINE_SHARED_IRQ(GPIO_IRQ, IRQAGENT3, INTC, PIRQC, gpio_isr);
int
quarkX1000_gpio_init(void)
{
pci_config_addr_t pci_addr;
pci_addr.raw = 0;
pci_addr.bus = 0;
pci_addr.dev = 21;
pci_addr.func = 2;
pci_addr.reg_off = PCI_CONFIG_REG_BAR1;
pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN);
PROT_DOMAINS_INIT_ID(drv);
pci_init(&drv, pci_addr, MMIO_SZ, 0, 0);
SYSCALLS_INIT(quarkX1000_gpio_mmin);
SYSCALLS_AUTHZ(quarkX1000_gpio_mmin, drv);
SYSCALLS_INIT(quarkX1000_gpio_mmout);
SYSCALLS_AUTHZ(quarkX1000_gpio_mmout, drv);
data.callback = 0;
quarkX1000_gpio_clock_enable();
/* clear registers */
write(INTEN, 0);
write(INTMASK, 0);
write(PORTA_EOI, 0);
return 0;
}

View File

@ -1,74 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_QUARKX1000_GPIO_H_
#define CPU_X86_DRIVERS_QUARKX1000_GPIO_H_
#include <stdint.h>
#include "pci.h"
#define QUARKX1000_GPIO_IN (0 << 0)
#define QUARKX1000_GPIO_OUT (1 << 0)
#define QUARKX1000_GPIO_INT (1 << 1)
#define QUARKX1000_GPIO_ACTIVE_LOW (0 << 2)
#define QUARKX1000_GPIO_ACTIVE_HIGH (1 << 2)
#define QUARKX1000_GPIO_LEVEL (0 << 3)
#define QUARKX1000_GPIO_EDGE (1 << 3)
#define QUARKX1000_GPIO_DEBOUNCE (1 << 4)
#define QUARKX1000_GPIO_CLOCK_SYNC (1 << 5)
#define QUARKX1000_GPIO_POL_NORMAL (0 << 6)
#define QUARKX1000_GPIO_POL_INV (1 << 6)
#define QUARKX1000_GPIO_PUD_NORMAL (0 << 7)
#define QUARKX1000_GPIO_PUD_PULL_UP (1 << 7)
#define QUARKX1000_GPIO_PUD_PULL_DOWN (2 << 7)
#define QUARKX1000_GPIO_DIR_MASK (1 << 0)
#define QUARKX1000_GPIO_POL_MASK (1 << 6)
#define QUARKX1000_GPIO_PUD_MASK (3 << 7)
typedef void (*quarkX1000_gpio_callback)(uint32_t);
int quarkX1000_gpio_init(void);
int quarkX1000_gpio_config(uint8_t pin, int flags);
int quarkX1000_gpio_read(uint8_t pin, uint8_t *value);
int quarkX1000_gpio_write(uint8_t pin, uint8_t value);
int quarkX1000_gpio_config_port(int flags);
int quarkX1000_gpio_read_port(uint8_t *value);
int quarkX1000_gpio_write_port(uint8_t value);
int quarkX1000_gpio_set_callback(quarkX1000_gpio_callback callback);
void quarkX1000_gpio_clock_enable(void);
void quarkX1000_gpio_clock_disable(void);
#endif /* CPU_X86_DRIVERS_QUARKX1000_GPIO_H_ */

View File

@ -1,158 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_QUARKX1000_I2C_REGISTERS_H_
#define CPU_X86_DRIVERS_QUARKX1000_I2C_REGISTERS_H_
#define QUARKX1000_IC_CON 0x00
#define QUARKX1000_IC_TAR 0x04
#define QUARKX1000_IC_DATA_CMD 0x10
#define QUARKX1000_IC_SS_SCL_HCNT 0x14
#define QUARKX1000_IC_SS_SCL_LCNT 0x18
#define QUARKX1000_IC_FS_SCL_HCNT 0x1C
#define QUARKX1000_IC_FS_SCL_LCNT 0x20
#define QUARKX1000_IC_INTR_STAT 0x2C
#define QUARKX1000_IC_INTR_MASK 0x30
#define QUARKX1000_IC_RAW_INTR_STAT 0x34
#define QUARKX1000_IC_RX_TL 0x38
#define QUARKX1000_IC_TX_TL 0x3C
#define QUARKX1000_IC_CLR_INTR 0x40
#define QUARKX1000_IC_CLR_RX_UNDER 0x44
#define QUARKX1000_IC_CLR_RX_OVER 0x48
#define QUARKX1000_IC_CLR_TX_OVER 0x4C
#define QUARKX1000_IC_CLR_RD_REQ 0x50
#define QUARKX1000_IC_CLR_TX_ABRT 0x54
#define QUARKX1000_IC_CLR_ACTIVITY 0x5C
#define QUARKX1000_IC_CLR_STOP_DET 0x60
#define QUARKX1000_IC_CLR_START_DET 0x64
#define QUARKX1000_IC_ENABLE 0x6C
#define QUARKX1000_IC_STATUS 0x70
#define QUARKX1000_IC_TXFLR 0x74
#define QUARKX1000_IC_RXFLR 0x78
#define QUARKX1000_IC_SDA_HOLD 0x7C
#define QUARKX1000_IC_TX_ABRT_SOURCE 0x80
#define QUARKX1000_IC_ENABLE_STATUS 0x9C
#define QUARKX1000_IC_FS_SPKLEN 0xA0
#define QUARKX1000_IC_HIGHEST QUARKX1000_IC_FS_SPKLEN
/* IC_CON */
#define QUARKX1000_IC_CON_MASTER_MODE_SHIFT 0
#define QUARKX1000_IC_CON_MASTER_MODE_MASK 0x01
#define QUARKX1000_IC_CON_SPEED_SHIFT 1
#define QUARKX1000_IC_CON_SPEED_MASK 0x06
#define QUARKX1000_IC_CON_10BITADDR_MASTER_SHIFT 4
#define QUARKX1000_IC_CON_10BITADDR_MASTER_MASK 0x10
#define QUARKX1000_IC_CON_RESTART_EN_SHIFT 5
#define QUARKX1000_IC_CON_RESTART_EN_MASK 0x20
/* IC_TAR */
#define QUARKX1000_IC_TAR_SHIFT 0
#define QUARKX1000_IC_TAR_MASK 0x3FF
/* IC_DATA_CMD */
#define QUARKX1000_IC_DATA_CMD_DAT_SHIFT 0
#define QUARKX1000_IC_DATA_CMD_DAT_MASK 0x0FF
#define QUARKX1000_IC_DATA_CMD_CMD_SHIFT 8
#define QUARKX1000_IC_DATA_CMD_CMD_MASK 0x100
#define QUARKX1000_IC_DATA_CMD_STOP_SHIFT 9
#define QUARKX1000_IC_DATA_CMD_STOP_MASK 0x200
#define QUARKX1000_IC_DATA_CMD_RESTART_SHIFT 10
#define QUARKX1000_IC_DATA_CMD_RESTART_MASK 0x400
/* IC_SS_SCL_HCNT */
#define QUARKX1000_IC_SS_SCL_HCNT_SHIFT 0
#define QUARKX1000_IC_SS_SCL_HCNT_MASK 0xFFFF
/* IC_SS_SCL_LCNT */
#define QUARKX1000_IC_SS_SCL_LCNT_SHIFT 0
#define QUARKX1000_IC_SS_SCL_LCNT_MASK 0xFFFF
/* IC_FS_SCL_HCNT */
#define QUARKX1000_IC_FS_SCL_HCNT_SHIFT 0
#define QUARKX1000_IC_FS_SCL_HCNT_MASK 0xFFFF
/* IC_FS_SCL_LCNT */
#define QUARKX1000_IC_FS_SCL_LCNT_SHIFT 0
#define QUARKX1000_IC_FS_SCL_LCNT_MASK 0xFFFF
/* IC_INTR_STAT */
#define QUARKX1000_IC_INTR_STAT_RX_UNDER_SHIFT 0
#define QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK 0x001
#define QUARKX1000_IC_INTR_STAT_RX_OVER_SHIFT 1
#define QUARKX1000_IC_INTR_STAT_RX_OVER_MASK 0x002
#define QUARKX1000_IC_INTR_STAT_RX_FULL_SHIFT 2
#define QUARKX1000_IC_INTR_STAT_RX_FULL_MASK 0x004
#define QUARKX1000_IC_INTR_STAT_TX_OVER_SHIFT 3
#define QUARKX1000_IC_INTR_STAT_TX_OVER_MASK 0x008
#define QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT 4
#define QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK 0x010
#define QUARKX1000_IC_INTR_STAT_RD_REQ_SHIFT 5
#define QUARKX1000_IC_INTR_STAT_RD_REQ_MASK 0x020
#define QUARKX1000_IC_INTR_STAT_TX_ABRT_SHIFT 6
#define QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK 0x040
#define QUARKX1000_IC_INTR_STAT_ACTIVITY_SHIFT 8
#define QUARKX1000_IC_INTR_STAT_ACTIVITY_MASK 0x100
#define QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT 9
#define QUARKX1000_IC_INTR_STAT_STOP_DET_MASK 0x200
#define QUARKX1000_IC_INTR_STAT_START_DET_SHIFT 10
#define QUARKX1000_IC_INTR_STAT_START_DET_MASK 0x400
/* IC_ENABLE */
#define QUARKX1000_IC_ENABLE_SHIFT 0
#define QUARKX1000_IC_ENABLE_MASK 0x01
/* IC_STATUS */
#define QUARKX1000_IC_STATUS_ACTIVITY_SHIFT 0
#define QUARKX1000_IC_STATUS_ACTIVITY_MASK 0x01
#define QUARKX1000_IC_STATUS_TFNF_SHIFT 1
#define QUARKX1000_IC_STATUS_TFNF_MASK 0x02
#define QUARKX1000_IC_STATUS_TFE_SHIFT 2
#define QUARKX1000_IC_STATUS_TFE_MASK 0x04
#define QUARKX1000_IC_STATUS_RFNE_SHIFT 3
#define QUARKX1000_IC_STATUS_RFNE_MASK 0x08
#define QUARKX1000_IC_STATUS_RFF_SHIFT 4
#define QUARKX1000_IC_STATUS_RFF_MASK 0x10
#define QUARKX1000_IC_STATUS_MST_ACTIVITY_SHIFT 5
#define QUARKX1000_IC_STATUS_MST_ACTIVITY_MASK 0x20
/* IC_TXFLR */
#define QUARKX1000_IC_TXFLR_SHIFT 0
#define QUARKX1000_IC_TXFLR_MASK 0x1F
/* IC_RXFLR */
#define QUARKX1000_IC_RXFLR_SHIFT 0
#define QUARKX1000_IC_RXFLR_MASK 0x1F
/* IC_FS_SPKLEN */
#define QUARKX1000_IC_FS_SPKLEN_SHIFT 0
#define QUARKX1000_IC_FS_SPKLEN_MASK 0xFF
#endif /* CPU_X86_DRIVERS_QUARKX1000_I2C_REGISTERS_H_ */

View File

@ -1,575 +0,0 @@
/*
* 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 "contiki.h"
#include "i2c.h"
#include "i2c-registers.h"
#include "paging.h"
#include "shared-isr.h"
#include "syscalls.h"
#define I2C_CLOCK_SPEED 25 /* kHz */
#define I2C_FIFO_DEPTH 16
#define I2C_STD_HCNT (I2C_CLOCK_SPEED * 4)
#define I2C_STD_LCNT (I2C_CLOCK_SPEED * 5)
#define I2C_FS_HCNT (I2C_CLOCK_SPEED)
#define I2C_FS_LCNT (I2C_CLOCK_SPEED)
#define I2C_FS_SPKLEN_LCNT_OFFSET 8
#define I2C_FS_SPKLEN_HCNT_OFFSET 6
#define I2C_POLLING_TIMEOUT (CLOCK_SECOND / 10)
#define I2C_IRQ 9
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
#define MMIO_SZ MIN_PAGE_SIZE
#else
#define MMIO_SZ (QUARKX1000_IC_HIGHEST + 4)
#endif
typedef enum {
I2C_DIRECTION_READ,
I2C_DIRECTION_WRITE
} I2C_DIRECTION;
PROT_DOMAINS_ALLOC(pci_driver_t, drv);
struct quarkX1000_i2c_config {
QUARKX1000_I2C_SPEED speed;
QUARKX1000_I2C_ADDR_MODE addressing_mode;
quarkX1000_i2c_callback cb_rx;
quarkX1000_i2c_callback cb_tx;
quarkX1000_i2c_callback cb_err;
};
struct i2c_internal_data {
struct quarkX1000_i2c_config config;
I2C_DIRECTION direction;
uint8_t rx_len;
uint8_t *rx_buffer;
uint8_t tx_len;
uint8_t *tx_buffer;
uint8_t rx_tx_len;
uint32_t hcnt;
uint32_t lcnt;
};
static struct i2c_internal_data device;
static int inited = 0;
void quarkX1000_i2c_mmin(uint32_t offset, uint32_t *res);
SYSCALLS_DEFINE_SINGLETON(quarkX1000_i2c_mmin, drv,
uint32_t offset, uint32_t *res)
{
uint32_t *loc_res;
PROT_DOMAINS_VALIDATE_PTR(loc_res, res, sizeof(*res));
if(QUARKX1000_IC_HIGHEST < offset) {
halt();
}
prot_domains_enable_mmio();
PCI_MMIO_READL(drv, *loc_res, offset);
prot_domains_disable_mmio();
}
static inline uint32_t
read(uint32_t offset)
{
uint32_t res;
quarkX1000_i2c_mmin(offset, &res);
return res;
}
void quarkX1000_i2c_mmout(uint32_t offset, uint32_t val);
SYSCALLS_DEFINE_SINGLETON(quarkX1000_i2c_mmout, drv,
uint32_t offset, uint32_t val)
{
if(QUARKX1000_IC_HIGHEST < offset) {
halt();
}
prot_domains_enable_mmio();
PCI_MMIO_WRITEL(drv, offset, val);
prot_domains_disable_mmio();
}
static inline void
write(uint32_t offset, uint32_t val)
{
quarkX1000_i2c_mmout(offset, val);
}
static uint32_t
get_value(uint32_t offset, uint32_t mask, uint32_t shift)
{
uint32_t register_value = read(offset);
register_value &= ~(0xFFFFFFFF - mask);
return register_value >> shift;
}
static void
set_value(uint32_t offset, uint32_t mask, uint32_t shift, uint32_t value)
{
uint32_t register_value = read(offset);
register_value &= ~mask;
register_value |= value << shift;
write(offset, register_value);
}
static void
i2c_data_read(void)
{
uint8_t i, rx_cnt;
if (device.rx_len == 0)
return;
rx_cnt = get_value(QUARKX1000_IC_RXFLR,
QUARKX1000_IC_RXFLR_MASK, QUARKX1000_IC_RXFLR_SHIFT);
if (rx_cnt > device.rx_len)
rx_cnt = device.rx_len;
for (i = 0; i < rx_cnt; i++) {
device.rx_buffer[i] = get_value(QUARKX1000_IC_DATA_CMD,
QUARKX1000_IC_DATA_CMD_DAT_MASK, QUARKX1000_IC_DATA_CMD_DAT_SHIFT);
}
device.rx_buffer += i;
device.rx_len -= i;
}
static void
i2c_data_send(void)
{
uint32_t data = 0;
uint8_t i, tx_cnt;
if (device.rx_tx_len == 0)
return;
tx_cnt = I2C_FIFO_DEPTH - get_value(QUARKX1000_IC_TXFLR,
QUARKX1000_IC_TXFLR_MASK, QUARKX1000_IC_TXFLR_SHIFT);
if (tx_cnt > device.rx_tx_len)
tx_cnt = device.rx_tx_len;
for (i = 0; i < tx_cnt; i++) {
if (device.tx_len > 0) {
data = device.tx_buffer[i];
if (device.tx_len == 1)
data |= (device.rx_len > 0) ? QUARKX1000_IC_DATA_CMD_RESTART_MASK : QUARKX1000_IC_DATA_CMD_STOP_MASK;
device.tx_len -= 1;
} else {
data = QUARKX1000_IC_DATA_CMD_CMD_MASK;
if (device.rx_tx_len == 1)
data |= QUARKX1000_IC_DATA_CMD_STOP_MASK;
}
write(QUARKX1000_IC_DATA_CMD, data);
device.rx_tx_len -= 1;
}
device.tx_buffer += i;
}
static bool
i2c_isr(void)
{
bool handled = false;
if (read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK) {
i2c_data_read();
write(QUARKX1000_IC_INTR_MASK, 0);
read(QUARKX1000_IC_CLR_INTR);
if (device.direction == I2C_DIRECTION_WRITE) {
if (device.config.cb_tx)
device.config.cb_tx();
} else {
if (device.config.cb_rx)
device.config.cb_rx();
}
handled = true;
}
if (read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK) {
i2c_data_send();
if (device.rx_tx_len <= 0) {
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 0);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1);
}
handled = true;
}
if(read(QUARKX1000_IC_INTR_STAT) & QUARKX1000_IC_INTR_STAT_RX_FULL_MASK) {
i2c_data_read();
handled = true;
}
if (read(QUARKX1000_IC_INTR_STAT) & (QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK
| QUARKX1000_IC_INTR_STAT_TX_OVER_MASK | QUARKX1000_IC_INTR_STAT_RX_OVER_MASK
| QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK)) {
write(QUARKX1000_IC_INTR_MASK, 0);
read(QUARKX1000_IC_CLR_INTR);
if (device.config.cb_err)
device.config.cb_err();
handled = true;
}
return handled;
}
void
quarkX1000_i2c_configure(QUARKX1000_I2C_SPEED speed,
QUARKX1000_I2C_ADDR_MODE addressing_mode)
{
uint32_t hcnt, lcnt;
uint8_t ic_fs_spklen;
device.config.speed = speed;
device.config.addressing_mode = addressing_mode;
if (device.config.speed == QUARKX1000_I2C_SPEED_STANDARD) {
lcnt = I2C_STD_LCNT;
hcnt = I2C_STD_HCNT;
} else {
lcnt = I2C_FS_LCNT;
hcnt = I2C_FS_HCNT;
}
ic_fs_spklen = get_value(QUARKX1000_IC_FS_SPKLEN,
QUARKX1000_IC_FS_SPKLEN_MASK, QUARKX1000_IC_FS_SPKLEN_SHIFT);
/* We adjust the Low Count and High Count based on the Spike Suppression Limit */
device.lcnt = (lcnt < (ic_fs_spklen + I2C_FS_SPKLEN_LCNT_OFFSET)) ? ic_fs_spklen + I2C_FS_SPKLEN_LCNT_OFFSET : lcnt;
device.hcnt = (hcnt < (ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET)) ? ic_fs_spklen + I2C_FS_SPKLEN_HCNT_OFFSET : hcnt;
/* Clear interrupts. */
read(QUARKX1000_IC_CLR_INTR);
}
void
quarkX1000_i2c_set_callbacks(quarkX1000_i2c_callback rx,
quarkX1000_i2c_callback tx,
quarkX1000_i2c_callback err)
{
device.config.cb_rx = rx;
device.config.cb_tx = tx;
device.config.cb_err = err;
}
static int
i2c_setup(void)
{
/* Clear all values */
write(QUARKX1000_IC_CON, 0);
/* Clear interrupts */
read(QUARKX1000_IC_CLR_INTR);
/* Quark X1000 SoC I2C only supports master mode. */
set_value(QUARKX1000_IC_CON,
QUARKX1000_IC_CON_MASTER_MODE_MASK, QUARKX1000_IC_CON_MASTER_MODE_SHIFT, 1);
/* Set restart enable */
set_value(QUARKX1000_IC_CON,
QUARKX1000_IC_CON_RESTART_EN_MASK, QUARKX1000_IC_CON_RESTART_EN_SHIFT, 1);
/* Set addressing mode */
if (device.config.addressing_mode == QUARKX1000_I2C_ADDR_MODE_10BIT) {
set_value(QUARKX1000_IC_CON,
QUARKX1000_IC_CON_10BITADDR_MASTER_MASK, QUARKX1000_IC_CON_10BITADDR_MASTER_SHIFT, 1);
}
if (device.config.speed == QUARKX1000_I2C_SPEED_STANDARD) {
set_value(QUARKX1000_IC_SS_SCL_LCNT,
QUARKX1000_IC_SS_SCL_LCNT_MASK, QUARKX1000_IC_SS_SCL_LCNT_SHIFT, device.lcnt);
set_value(QUARKX1000_IC_SS_SCL_HCNT,
QUARKX1000_IC_SS_SCL_HCNT_MASK, QUARKX1000_IC_SS_SCL_HCNT_SHIFT, device.hcnt);
set_value(QUARKX1000_IC_CON,
QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x1);
} else {
set_value(QUARKX1000_IC_FS_SCL_LCNT,
QUARKX1000_IC_FS_SCL_LCNT_MASK, QUARKX1000_IC_FS_SCL_LCNT_SHIFT, device.lcnt);
set_value(QUARKX1000_IC_FS_SCL_HCNT,
QUARKX1000_IC_FS_SCL_HCNT_MASK, QUARKX1000_IC_FS_SCL_HCNT_SHIFT, device.hcnt);
set_value(QUARKX1000_IC_CON,
QUARKX1000_IC_CON_SPEED_MASK, QUARKX1000_IC_CON_SPEED_SHIFT, 0x2);
}
return 0;
}
static void
i2c_operation_setup(uint8_t *write_buf, uint8_t write_len,
uint8_t *read_buf, uint8_t read_len, uint16_t addr)
{
device.rx_len = read_len;
device.rx_buffer = read_buf;
device.tx_len = write_len;
device.tx_buffer = write_buf;
device.rx_tx_len = device.rx_len + device.tx_len;
/* Disable controller */
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
i2c_setup();
/* Disable interrupts */
write(QUARKX1000_IC_INTR_MASK, 0);
/* Clear interrupts */
read(QUARKX1000_IC_CLR_INTR);
/* Set address of target slave */
set_value(QUARKX1000_IC_TAR,
QUARKX1000_IC_TAR_MASK, QUARKX1000_IC_TAR_SHIFT, addr);
}
/* This is an interrupt based operation */
static int
i2c_operation(uint8_t *write_buf, uint8_t write_len,
uint8_t *read_buf, uint8_t read_len, uint16_t addr)
{
if (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK)
return -1;
i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr);
/* Enable master TX and RX interrupts */
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_TX_OVER_MASK, QUARKX1000_IC_INTR_STAT_TX_OVER_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_TX_EMPTY_MASK, QUARKX1000_IC_INTR_STAT_TX_EMPTY_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_TX_ABRT_MASK, QUARKX1000_IC_INTR_STAT_TX_ABRT_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_RX_UNDER_MASK, QUARKX1000_IC_INTR_STAT_RX_UNDER_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_RX_OVER_MASK, QUARKX1000_IC_INTR_STAT_RX_OVER_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_RX_FULL_MASK, QUARKX1000_IC_INTR_STAT_RX_FULL_SHIFT, 1);
set_value(QUARKX1000_IC_INTR_MASK,
QUARKX1000_IC_INTR_STAT_STOP_DET_MASK, QUARKX1000_IC_INTR_STAT_STOP_DET_SHIFT, 1);
/* Enable controller */
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1);
return 0;
}
/* This is an interrupt based write */
int
quarkX1000_i2c_write(uint8_t *buf, uint8_t len, uint16_t addr)
{
device.direction = I2C_DIRECTION_WRITE;
return i2c_operation(buf, len, 0, 0, addr);
}
/* This is an interrupt based read */
int
quarkX1000_i2c_read(uint8_t *buf, uint8_t len, uint16_t addr)
{
device.direction = I2C_DIRECTION_READ;
return i2c_operation(0, 0, buf, len, addr);
}
static int
i2c_polling_operation(uint8_t *write_buf, uint8_t write_len,
uint8_t *read_buf, uint8_t read_len, uint16_t addr)
{
uint32_t start_time, intr_mask_stat;
if (!(read(QUARKX1000_IC_CON) & QUARKX1000_IC_CON_MASTER_MODE_MASK))
return -1;
/* Wait i2c idle */
start_time = clock_seconds();
while (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
return -1;
}
}
/* Get interrupt mask to restore in the end of polling operation */
intr_mask_stat = read(QUARKX1000_IC_INTR_MASK);
i2c_operation_setup(write_buf, write_len, read_buf, read_len, addr);
/* Enable controller */
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 1);
/* Transmit */
if (device.tx_len != 0) {
while (device.tx_len > 0) {
start_time = clock_seconds();
while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFNF_MASK)) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
return -1;
}
}
i2c_data_send();
}
start_time = clock_seconds();
while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_TFE_MASK)) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
return -1;
}
}
}
i2c_data_send();
/* Receive */
if (device.rx_len != 0) {
while (device.rx_len > 0) {
start_time = clock_seconds();
while (!(read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_RFNE_MASK)) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
return -1;
}
}
i2c_data_read();
}
}
/* Stop Det */
start_time = clock_seconds();
while (!(read(QUARKX1000_IC_RAW_INTR_STAT) & QUARKX1000_IC_INTR_STAT_STOP_DET_MASK)) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
return -1;
}
}
read(QUARKX1000_IC_CLR_STOP_DET);
/* Wait i2c idle */
start_time = clock_seconds();
while (read(QUARKX1000_IC_STATUS) & QUARKX1000_IC_STATUS_ACTIVITY_MASK) {
if ((clock_seconds() - start_time) > I2C_POLLING_TIMEOUT) {
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
return -1;
}
}
/* Disable controller */
set_value(QUARKX1000_IC_ENABLE,
QUARKX1000_IC_ENABLE_MASK, QUARKX1000_IC_ENABLE_SHIFT, 0);
/* Restore interrupt mask */
write(QUARKX1000_IC_INTR_MASK, intr_mask_stat);
return 0;
}
int
quarkX1000_i2c_polling_write(uint8_t *buf, uint8_t len, uint16_t addr)
{
device.direction = I2C_DIRECTION_WRITE;
return i2c_polling_operation(buf, len, 0, 0, addr);
}
int
quarkX1000_i2c_polling_read(uint8_t *buf, uint8_t len, uint16_t addr)
{
device.direction = I2C_DIRECTION_READ;
return i2c_polling_operation(0, 0, buf, len ,addr);
}
int
quarkX1000_i2c_is_available(void)
{
return inited;
}
DEFINE_SHARED_IRQ(I2C_IRQ, IRQAGENT3, INTC, PIRQC, i2c_isr);
int
quarkX1000_i2c_init(void)
{
pci_config_addr_t pci_addr;
pci_addr.raw = 0;
pci_addr.bus = 0;
pci_addr.dev = 21;
pci_addr.func = 2;
pci_addr.reg_off = PCI_CONFIG_REG_BAR0;
pci_command_enable(pci_addr, PCI_CMD_1_MEM_SPACE_EN);
PROT_DOMAINS_INIT_ID(drv);
pci_init(&drv, pci_addr, MMIO_SZ, 0, 0);
SYSCALLS_INIT(quarkX1000_i2c_mmin);
SYSCALLS_AUTHZ(quarkX1000_i2c_mmin, drv);
SYSCALLS_INIT(quarkX1000_i2c_mmout);
SYSCALLS_AUTHZ(quarkX1000_i2c_mmout, drv);
inited = 1;
return 0;
}

View File

@ -1,62 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_DRIVERS_QUARKX1000_I2C_H_
#define CPU_X86_DRIVERS_QUARKX1000_I2C_H_
#include "pci.h"
typedef enum {
QUARKX1000_I2C_SPEED_STANDARD,
QUARKX1000_I2C_SPEED_FAST
} QUARKX1000_I2C_SPEED;
typedef enum {
QUARKX1000_I2C_ADDR_MODE_7BIT,
QUARKX1000_I2C_ADDR_MODE_10BIT
} QUARKX1000_I2C_ADDR_MODE;
typedef void (*quarkX1000_i2c_callback)(void);
int quarkX1000_i2c_init(void);
void quarkX1000_i2c_configure(QUARKX1000_I2C_SPEED speed,
QUARKX1000_I2C_ADDR_MODE addressing_mode);
void quarkX1000_i2c_set_callbacks(quarkX1000_i2c_callback rx,
quarkX1000_i2c_callback tx,
quarkX1000_i2c_callback err);
int quarkX1000_i2c_is_available(void);
int quarkX1000_i2c_read(uint8_t *buf, uint8_t len, uint16_t addr);
int quarkX1000_i2c_write(uint8_t *buf, uint8_t len, uint16_t addr);
int quarkX1000_i2c_polling_read(uint8_t *buf, uint8_t len, uint16_t addr);
int quarkX1000_i2c_polling_write(uint8_t *buf, uint8_t len, uint16_t addr);
#endif /* CPU_X86_DRIVERS_QUARKX1000_I2C_H_ */

View File

@ -1,82 +0,0 @@
/*
* 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 "dma.h"
#include "imr.h"
#include "msg-bus.h"
/*---------------------------------------------------------------------------*/
void
quarkX1000_imr_conf(void)
{
quarkX1000_imr_t imr;
int imr_idx = 0;
imr.lo.raw = 0;
imr.hi.raw = 0;
imr.rdmsk.raw = 0;
imr.wrmsk.raw = 0;
imr.lo.lock = 1;
imr.rdmsk.cpu0 = imr.rdmsk.cpu_0 = 1;
imr.wrmsk.cpu0 = imr.wrmsk.cpu_0 = 1;
quarkX1000_msg_bus_init();
imr.lo.addr = 0;
imr.hi.addr = (((uint32_t)&_sbss_dma_addr) - 1) >> QUARKX1000_IMR_SHAMT;
quarkX1000_imr_write(imr_idx, imr);
imr_idx++;
imr.lo.addr = ((uint32_t)&_ebss_dma_addr) >> QUARKX1000_IMR_SHAMT;
imr.hi.addr = ~0;
quarkX1000_imr_write(imr_idx, imr);
imr_idx++;
imr.lo.addr = 0;
imr.hi.addr = 0;
imr.rdmsk.raw = ~0;
imr.wrmsk.raw = ~0;
/* Lock the other IMRs open */
while(imr_idx < QUARKX1000_IMR_CNT) {
quarkX1000_imr_write(imr_idx, imr);
imr_idx++;
}
#ifndef DBG_IMRS
/* The IMRs are locked by the hardware, but the message bus could still
* provide access to other potentially-sensitive functionality.
*/
quarkX1000_msg_bus_lock();
#endif
}
/*---------------------------------------------------------------------------*/

View File

@ -1,36 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_DRIVERS_QUARKX1000_IMR_CONF_H_
#define CPU_X86_DRIVERS_QUARKX1000_IMR_CONF_H_
void quarkX1000_imr_conf(void);
#endif /* CPU_X86_DRIVERS_QUARKX1000_IMR_CONF_H_ */

View File

@ -1,89 +0,0 @@
/*
* 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 <assert.h>
#include "imr.h"
#include "msg-bus.h"
#define MEM_MANAGER_PORT 5
#define IMR_BASE_OFFSET 0x40
#define IMR_REG_COUNT 4
#define IMR_LO_OFFSET 0
#define IMR_HI_OFFSET 1
#define IMR_RDMSK_OFFSET 2
#define IMR_WRMSK_OFFSET 3
/*---------------------------------------------------------------------------*/
/**
* \brief Read the contents of the specified IMR.
*/
quarkX1000_imr_t
quarkX1000_imr_read(uint32_t imr_idx)
{
quarkX1000_imr_t imr;
uint32_t reg_base = IMR_BASE_OFFSET + (IMR_REG_COUNT * imr_idx);
assert(imr_idx < QUARKX1000_IMR_CNT);
quarkX1000_msg_bus_read(MEM_MANAGER_PORT,
reg_base + IMR_LO_OFFSET, &imr.lo.raw);
quarkX1000_msg_bus_read(MEM_MANAGER_PORT,
reg_base + IMR_HI_OFFSET, &imr.hi.raw);
quarkX1000_msg_bus_read(MEM_MANAGER_PORT,
reg_base + IMR_RDMSK_OFFSET, &imr.rdmsk.raw);
quarkX1000_msg_bus_read(MEM_MANAGER_PORT,
reg_base + IMR_WRMSK_OFFSET, &imr.wrmsk.raw);
return imr;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Overwrite the contents of the specified IMR.
*/
void
quarkX1000_imr_write(uint32_t imr_idx, quarkX1000_imr_t imr)
{
uint32_t reg_base = IMR_BASE_OFFSET + (IMR_REG_COUNT * imr_idx);
assert(imr_idx < QUARKX1000_IMR_CNT);
quarkX1000_msg_bus_write(MEM_MANAGER_PORT,
reg_base + IMR_HI_OFFSET, imr.hi.raw);
quarkX1000_msg_bus_write(MEM_MANAGER_PORT,
reg_base + IMR_RDMSK_OFFSET, imr.rdmsk.raw);
quarkX1000_msg_bus_write(MEM_MANAGER_PORT,
reg_base + IMR_WRMSK_OFFSET, imr.wrmsk.raw);
/* This register must be programmed last, in case it sets the lock bit. */
quarkX1000_msg_bus_write(MEM_MANAGER_PORT,
reg_base + IMR_LO_OFFSET, imr.lo.raw);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,125 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_DRIVERS_QUARKX1000_IMR_H_
#define CPU_X86_DRIVERS_QUARKX1000_IMR_H_
#include <stdint.h>
typedef union quarkX1000_imr_lo {
struct {
uint32_t : 2;
uint32_t addr : 22;
uint32_t : 7;
uint32_t lock : 1;
};
uint32_t raw;
} quarkX1000_imr_lo_t;
typedef union quarkX1000_imr_hi {
struct {
uint32_t : 2;
uint32_t addr : 22;
uint32_t : 8;
};
uint32_t raw;
} quarkX1000_imr_hi_t;
/* Amount to shift imr_lo/hi.addr left to obtain the bound address */
#define QUARKX1000_IMR_SHAMT 10
typedef union quarkX1000_imr_rdmsk {
struct {
uint32_t cpu0 : 1;
uint32_t cpu_0 : 1;
uint32_t : 6;
uint32_t vc0_sai_id0 : 1;
uint32_t vc0_sai_id1 : 1;
uint32_t vc0_sai_id2 : 1;
uint32_t vc0_sai_id3 : 1;
uint32_t vc1_sai_id0 : 1;
uint32_t vc1_sai_id1 : 1;
uint32_t vc1_sai_id2 : 1;
uint32_t vc1_sai_id3 : 1;
uint32_t : 13;
uint32_t punit : 1;
uint32_t : 1;
uint32_t esram_flush_init : 1;
};
uint32_t raw;
} quarkX1000_imr_rdmsk_t;
typedef union quarkX1000_imr_wrmsk {
struct {
uint32_t cpu0 : 1;
uint32_t cpu_0 : 1;
uint32_t : 6;
uint32_t vc0_sai_id0 : 1;
uint32_t vc0_sai_id1 : 1;
uint32_t vc0_sai_id2 : 1;
uint32_t vc0_sai_id3 : 1;
uint32_t vc1_sai_id0 : 1;
uint32_t vc1_sai_id1 : 1;
uint32_t vc1_sai_id2 : 1;
uint32_t vc1_sai_id3 : 1;
uint32_t : 13;
uint32_t punit : 1;
uint32_t cpu_snoop : 1;
uint32_t esram_flush_init : 1;
};
uint32_t raw;
} quarkX1000_imr_wrmsk_t;
/* Refer to Intel Quark SoC X1000 Datasheet, Section 12.7.4 for more details on
* the IMR registers.
*/
typedef struct quarkX1000_imr {
quarkX1000_imr_lo_t lo;
quarkX1000_imr_hi_t hi;
quarkX1000_imr_rdmsk_t rdmsk;
quarkX1000_imr_wrmsk_t wrmsk;
} quarkX1000_imr_t;
/* The Intel Quark SoC X1000 defines eight general IMRs. */
#define QUARKX1000_IMR_CNT 8
/* Routines for accessing the Isolated Memory Region (IMR) feature.
*
* The Intel Quark X1000 SoC includes support for Isolated Memory Regions
* (IMRs), which are specified using range registers and associated
* control registers that are accessible via the message bus.
*
* Refer to Intel Quark SoC X1000 Datasheet, Section 12.2 for more information.
*/
quarkX1000_imr_t quarkX1000_imr_read(uint32_t imr_idx);
void quarkX1000_imr_write(uint32_t imr_idx, quarkX1000_imr_t imr);
#endif /* CPU_X86_DRIVERS_QUARKX1000_IMR_H_ */

View File

@ -1,143 +0,0 @@
/*
* 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 "msg-bus.h"
#include "pci.h"
#include "syscalls.h"
PROT_DOMAINS_ALLOC(dom_client_data_t, quarkX1000_msg_bus);
/** Message bus control register */
#define MCR_PCI_REG_ADDR 0xD0
/** Message data register */
#define MDR_PCI_REG_ADDR 0xD4
/** Message control register extension */
#define MCRX_PCI_REG_ADDR 0xD8
typedef union mcr {
struct {
uint32_t : 4;
uint32_t byte_en : 4;
uint32_t reg_off : 8;
uint32_t port : 8;
uint32_t opcode : 8;
};
uint32_t raw;
} mcr_t;
typedef union mcrx {
struct {
uint32_t : 8;
uint32_t reg_off : 24;
};
uint32_t raw;
} mcrx_t;
/*---------------------------------------------------------------------------*/
static void
request_op(uint8_t port, uint32_t reg_off, uint8_t opcode)
{
pci_config_addr_t pci_addr = { .raw = 0 };
mcr_t mcr = { .raw = 0 };
mcrx_t mcrx = { .raw = 0 };
pci_addr.reg_off = MCR_PCI_REG_ADDR;
mcr.opcode = opcode;
mcr.byte_en = 0xF;
mcr.port = port;
mcr.reg_off = reg_off & 0xFF;
pci_config_write(pci_addr, mcr.raw);
pci_addr.reg_off = MCRX_PCI_REG_ADDR;
mcrx.reg_off = reg_off >> 8;
pci_config_write(pci_addr, mcrx.raw);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Read from a message bus register.
* \param port Port of message bus register to be read.
* \param reg_off Register/offset identifier of message bus register to read.
* \param val Storage location for value that has been read.
*/
SYSCALLS_DEFINE_SINGLETON(quarkX1000_msg_bus_read,
quarkX1000_msg_bus,
uint8_t port,
uint32_t reg_off,
uint32_t *val)
{
uint32_t *loc_val;
pci_config_addr_t pci_addr = { .raw = 0 };
PROT_DOMAINS_VALIDATE_PTR(loc_val, val, sizeof(*val));
request_op(port, reg_off, 0x10);
pci_addr.reg_off = MDR_PCI_REG_ADDR;
*loc_val = pci_config_read(pci_addr);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Write to a message bus register.
* \param port Port of message bus register to be written.
* \param reg_off Register/offset identifier of message bus register to write.
* \param val Value to write.
*/
SYSCALLS_DEFINE_SINGLETON(quarkX1000_msg_bus_write,
quarkX1000_msg_bus,
uint8_t port,
uint32_t reg_off,
uint32_t val)
{
pci_config_addr_t pci_addr = { .raw = 0 };
pci_addr.reg_off = MDR_PCI_REG_ADDR;
pci_config_write(pci_addr, val);
request_op(port, reg_off, 0x11);
}
/*---------------------------------------------------------------------------*/
void
quarkX1000_msg_bus_init(void)
{
PROT_DOMAINS_INIT_ID(quarkX1000_msg_bus);
prot_domains_reg(&quarkX1000_msg_bus, 0, 0, 0, 0, true);
SYSCALLS_INIT(quarkX1000_msg_bus_read);
SYSCALLS_AUTHZ(quarkX1000_msg_bus_read, quarkX1000_msg_bus);
SYSCALLS_INIT(quarkX1000_msg_bus_write);
SYSCALLS_AUTHZ(quarkX1000_msg_bus_write, quarkX1000_msg_bus);
}
/*---------------------------------------------------------------------------*/
void
quarkX1000_msg_bus_lock(void)
{
SYSCALLS_DEAUTHZ(quarkX1000_msg_bus_read, quarkX1000_msg_bus);
SYSCALLS_DEAUTHZ(quarkX1000_msg_bus_write, quarkX1000_msg_bus);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,52 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_DRIVERS_QUARKX1000_MSG_BUS_H_
#define CPU_X86_DRIVERS_QUARKX1000_MSG_BUS_H_
#include <stdint.h>
/* Routines for accessing the message bus.
*
* The Intel Quark X1000 SoC includes a message bus that is accessible
* via PCI configuration registers. It communicates to various SoC
* components such as the Isolated Memory Region (IMR) registers and the
* Remote Management Unit.
*
* Refer to Intel Quark SoC X1000 Datasheet, Section 12.5 for more details on
* the message bus.
*/
void quarkX1000_msg_bus_init(void);
void quarkX1000_msg_bus_lock(void);
void quarkX1000_msg_bus_read(uint8_t port, uint32_t reg_off, uint32_t *val);
void quarkX1000_msg_bus_write(uint8_t port, uint32_t reg_off, uint32_t val);
#endif /* CPU_X86_DRIVERS_QUARKX1000_MSG_BUS_H_ */

View File

@ -1,101 +0,0 @@
/*
* Copyright (C) 2015, 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 "uart.h"
#include "uart-16x50.h"
#include <assert.h>
PROT_DOMAINS_ALLOC(uart_16x50_driver_t, quarkX1000_uart0);
PROT_DOMAINS_ALLOC(uart_16x50_driver_t, quarkX1000_uart1);
/* UART base frequency from section 18.2.2 of Intel Quark SoC X1000
* Datasheet.
*/
#define QUARK_X1000_UART_FBASE 44236800
/*---------------------------------------------------------------------------*/
/**
* \brief Perform common initialization that must precede per-port
* initialization.
*/
void
quarkX1000_uart_init(void)
{
uart_16x50_init();
}
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize a UART.
* \param dev Device to initialize.
*/
void
quarkX1000_uart_init_port(quarkX1000_uart_dev_t dev, unsigned baud)
{
uint16_t dl;
pci_config_addr_t pci_addr;
uart_16x50_driver_t ATTR_KERN_ADDR_SPACE *drv;
assert((dev == QUARK_X1000_UART_0) || (dev == QUARK_X1000_UART_1));
pci_addr.raw = 0;
/* PCI addresses from section 18.4 of Intel Quark SoC X1000 Datasheet. */
pci_addr.dev = 20;
pci_addr.func = (dev == QUARK_X1000_UART_0) ? 1 : 5;
pci_addr.reg_off = PCI_CONFIG_REG_BAR0;
if(dev == QUARK_X1000_UART_0) {
drv = &quarkX1000_uart0;
PROT_DOMAINS_INIT_ID(quarkX1000_uart0);
} else {
drv = &quarkX1000_uart1;
PROT_DOMAINS_INIT_ID(quarkX1000_uart1);
}
/* Divisor setting from section 18.2.2 of Intel Quark SoC X1000 Datasheet. */
dl = QUARK_X1000_UART_FBASE / (16 * baud);
uart_16x50_init_port(drv, pci_addr, dl);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Transmit a character via a UART.
* \param dev Device to use.
* \param c Character to transmit.
*/
void
quarkX1000_uart_tx(quarkX1000_uart_dev_t dev, uint8_t c)
{
uart_16x50_driver_t drv;
assert((dev == QUARK_X1000_UART_0) || (dev == QUARK_X1000_UART_1));
prot_domains_copy_dcd(&drv,
(dev == QUARK_X1000_UART_0) ?
&quarkX1000_uart0 : &quarkX1000_uart1);
uart_16x50_tx(drv, c);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,45 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_QUARKX1000_UART_H_
#define CPU_X86_DRIVERS_QUARKX1000_UART_H_
#include <stdint.h>
typedef enum {
QUARK_X1000_UART_0,
QUARK_X1000_UART_1
} quarkX1000_uart_dev_t;
void quarkX1000_uart_init(void);
void quarkX1000_uart_init_port(quarkX1000_uart_dev_t dev, unsigned baud);
void quarkX1000_uart_tx(quarkX1000_uart_dev_t dev, uint8_t c);
#endif /* CPU_X86_DRIVERS_QUARKX1000_UART_H_ */

View File

@ -1,63 +0,0 @@
/*
* Copyright (C) 2015, 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.
*/
.text
.global halt
halt:
cli
die: hlt
jmp die
.global outb
outb:
mov 4(%esp), %dx
mov 8(%esp), %al
out %al, %dx
ret
.global outl
outl:
mov 4(%esp), %dx
mov 8(%esp), %eax
out %eax, %dx
ret
.global inb
inb:
mov 4(%esp), %dx
in %dx, %al
ret
.global inl
inl:
mov 4(%esp), %dx
in %dx, %eax
ret

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2015, 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 HELPERS_H
#define HELPERS_H
#include <stdint.h>
#define BIT(n) (1UL << (n))
void halt(void) __attribute__((__noreturn__));
#define STRINGIFY(x) #x
/* The C preprocessor will not expand macro arguments that are converted to
* strings in the macro body using the '#' operator. The EXP_STRINGIFY macro
* introduces an additional level of argument expansion for instances where
* the developer wishes to convert the expanded argument to a string.
*/
#define EXP_STRINGIFY(x) STRINGIFY(x)
#define ALIGN(x, amt) \
(((x) & ~((amt) - 1)) + ((((x) & ((amt) - 1)) == 0) ? 0 : (amt)))
/** Wrappers for the assembly 'out' instruction. */
void outb(uint16_t port, uint8_t val);
void outl(uint16_t port, uint32_t val);
/** Wrappers for the assembly 'in' instruction */
uint8_t inb(uint16_t port);
uint32_t inl(uint16_t port);
#endif /* HELPERS_H */

View File

@ -1,124 +0,0 @@
/*
* Copyright (C) 2015, 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 "cpu.h"
#include "gdt.h"
#include "helpers.h"
#include "idt.h"
#include "interrupt.h"
#include "irq.h"
#include "stacks.h"
static void
double_fault_handler(struct interrupt_context context)
{
halt();
}
/*---------------------------------------------------------------------------*/
/* The OS has switched to its own segment descriptors. When multi-segment
* protection domain support is enabled, this routine runs with the
* necessary address translations configured to invoke other routines that
* require those translations to be in place. However, the protection domain
* support, if enabled, has not yet been fully activated.
*/
static void
boot_stage1(void)
{
idt_init();
/* Set an interrupt handler for Double Fault exception. This way, we avoid
* the system to triple fault, leaving no trace about what happened.
*/
SET_EXCEPTION_HANDLER(8, 1, double_fault_handler);
/* Initialize protection domain support, if enabled */
prot_domains_init();
prot_domains_leave_boot_stage1();
}
/*---------------------------------------------------------------------------*/
int main(void);
/* This routine runs with the initial, flat address space, even if protection
* domain support is enabled. The goal behind the design of this routine is to
* keep it as short as possible, since it is unable to directly reference data
* and invoke functions that are intended to be accessible later after the
* system has booted when a multi-segment protection domain model is in use.
*/
void
cpu_boot_stage0(void)
{
/* Reserve three stack slots for return addresses */
uintptr_t top_of_stack = STACKS_INIT_TOP;
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
uintptr_t *top_of_stack_ptr =
(uintptr_t *)DATA_OFF_TO_PHYS_ADDR(top_of_stack);
top_of_stack_ptr[0] = (uintptr_t)prot_domains_launch_kernel;
top_of_stack_ptr[1] = (uintptr_t)prot_domains_launch_app;
#endif
/* Perform common GDT initialization */
gdt_init();
/* Switch all data segment registers to the newly-initialized flat data
* descriptor.
*/
__asm__(
"mov %0, %%ds\n\t"
"mov %0, %%es\n\t"
"mov %0, %%fs\n\t"
"mov %0, %%gs\n\t"
:
: "r" (GDT_SEL_DATA_FLAT)
);
/**
* Perform specific GDT initialization tasks for the protection domain
* implementation that is enabled, if any.
*/
prot_domains_gdt_init();
/* Do not pass memory operands to the asm block below, since it is
* switching from the flat address space to a multi-segment address space
* model if such a model is used by the enabled protection domain
* implementation, if any.
*/
__asm__(
"mov %[_ss_], %%ss\n\t"
"mov %[_esp_], %%esp\n\t"
"ljmp %[_cs_], %[_stage1_]\n\t"
:
: [_ss_] "r" (GDT_SEL_STK_EXC),
[_esp_] "r" (top_of_stack),
[_cs_] "i" ((uint16_t)GDT_SEL_CODE_EXC),
[_stage1_] "i" (boot_stage1)
);
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2015, 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_H
#define CPU_H
#include "prot-domains.h"
void cpu_boot_stage0(void) ATTR_CODE_BOOT;
#endif /* CPU_H */

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2015, 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 <stdint.h>
#include "gdt.h"
#include "gdt-layout.h"
#include "helpers.h"
#include "prot-domains.h"
#include "segmentation.h"
#define GDT_MEM_PL0 (SEG_DESCTYPE_NSYS | SEG_GRAN_PAGE)
#define GDT_CODE_PL0 (GDT_MEM_PL0 | SEG_TYPE_CODE_EXRD)
#define GDT_DATA_PL0 (GDT_MEM_PL0 | SEG_TYPE_DATA_RDWR)
typedef struct gdtr
{
uint16_t limit;
uint32_t base;
} __attribute__((packed)) gdtr_t;
/* From Intel Combined Manual, Vol. 3 , Section 3.5.1: The base addresses of
* the GDT should be aligned on an eight-byte boundary to yield the best
* processor performance.
*/
segment_desc_t __attribute__ ((aligned(8))) ATTR_BSS_GDT_START
gdt[GDT_NUM_FIXED_DESC];
#define GDT_LEN \
((((uintptr_t)&_ebss_gdt_addr) - \
(uintptr_t)gdt)/sizeof(segment_desc_t))
/*---------------------------------------------------------------------------*/
static void ATTR_CODE_BOOT
set_descriptor(unsigned int index,
uint32_t base,
uint32_t len,
uint16_t flag)
{
segment_desc_t descriptor;
if(GDT_LEN <= index) {
halt();
}
segment_desc_init(&descriptor, base, len, flag);
/* Save descriptor into gdt */
gdt_insert_boot(index, descriptor);
}
/*---------------------------------------------------------------------------*/
void
gdt_copy_desc_change_dpl(unsigned int dest_idx,
unsigned int src_idx,
unsigned dpl)
{
segment_desc_t desc;
if((GDT_LEN <= dest_idx) || (GDT_LEN <= src_idx)) {
halt();
}
gdt_lookup(src_idx, &desc);
SEG_SET_FLAG(desc, DPL, dpl);
gdt_insert(dest_idx, desc);
}
/*---------------------------------------------------------------------------*/
/* This function initializes the Global Descriptor Table. For simplicity, the
* memory is initially organized following the flat model. Thus, memory appears
* to Contiki as a single continuous address space. Code, data, and stack
* are all contained in this address space (so called linear address space).
* Certain protection domain implementations switch to a multi-segment memory
* model later during boot.
*/
void
gdt_init(void)
{
gdtr_t gdtr;
/* Initialize gdtr structure */
gdtr.limit = sizeof(segment_desc_t) * GDT_LEN - 1;
gdtr.base = KERN_DATA_OFF_TO_PHYS_ADDR(gdt);
/* Initialize descriptors */
set_descriptor(GDT_IDX_NULL, 0, 0, 0);
set_descriptor(GDT_IDX_CODE_FLAT, 0, 0x100000, GDT_CODE_PL0);
set_descriptor(GDT_IDX_DATA_FLAT, 0, 0x100000, GDT_DATA_PL0);
/* Load GDTR */
__asm__ __volatile__ ("lgdt %0" :: "m" (gdtr));
}
/*---------------------------------------------------------------------------*/
void
gdt_insert_boot(unsigned int idx, segment_desc_t desc)
{
((segment_desc_t *)KERN_DATA_OFF_TO_PHYS_ADDR(gdt))[idx] = desc;
}
/*---------------------------------------------------------------------------*/
void
gdt_insert(unsigned int idx, segment_desc_t desc)
{
if(GDT_LEN <= idx) {
halt();
}
KERN_WRITEL(gdt[idx].raw_lo, desc.raw_lo);
KERN_WRITEL(gdt[idx].raw_hi, desc.raw_hi);
}
/*---------------------------------------------------------------------------*/
void
gdt_lookup(unsigned int idx, segment_desc_t *desc)
{
if((GDT_LEN <= idx) || (desc == NULL)) {
halt();
}
KERN_READL(desc->raw_lo, gdt[idx].raw_lo);
KERN_READL(desc->raw_hi, gdt[idx].raw_hi);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,78 +0,0 @@
/*
* 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.
*/
#ifndef GDT_H
#define GDT_H
#include "gdt-layout.h"
#include "prot-domains.h"
#include "segmentation.h"
extern segment_desc_t ATTR_KERN_ADDR_SPACE gdt[];
extern int ATTR_KERN_ADDR_SPACE _ebss_gdt_addr;
#define GDT_IDX_OF_DESC(ptr) \
((((uintptr_t)(ptr)) - ((uintptr_t)&gdt))/ \
sizeof(segment_desc_t))
typedef struct far_pointer {
/** Far pointer offset. */
uint32_t offset;
/** Far pointer segment/gate selector. */
uint16_t sel;
uint16_t pad;
} __attribute__((packed)) far_pointer_t;
/**
* \brief Compute the selector for a GDT entry allocated somewhere besides gdt.c.
* \param ptr Pointer to GDT descriptor.
* \param rpl Requested Privilege Level.
*/
#define GDT_SEL_OF_DESC(ptr, rpl) GDT_SEL(GDT_IDX_OF_DESC(ptr), rpl)
/* Section for fixed GDT entries */
#define ATTR_BSS_GDT \
__attribute__((section(".gdt_bss"))) ATTR_KERN_ADDR_SPACE
/* Section for TSS and LDT descriptors for protection domains */
#define ATTR_BSS_GDT_MID \
__attribute__((used, section(".gdt_bss_mid"))) ATTR_KERN_ADDR_SPACE
/* Section for other GDT entries */
#define ATTR_BSS_GDT_START \
__attribute__((section(".gdt_bss_start"))) ATTR_KERN_ADDR_SPACE
void gdt_copy_desc_change_dpl(unsigned int dest_idx,
unsigned int src_idx,
unsigned dpl);
void gdt_init(void) ATTR_CODE_BOOT;
void gdt_insert(unsigned int idx, segment_desc_t desc);
void gdt_insert_boot(unsigned int idx, segment_desc_t desc) ATTR_CODE_BOOT;
void gdt_lookup(unsigned int idx, segment_desc_t *desc);
#endif /* GDT_H */

View File

@ -1,112 +0,0 @@
/*
* Copyright (C) 2015, 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 "gdt-layout.h"
#include "prot-domains.h"
#include <stdint.h>
#include "helpers.h"
#include "segmentation.h"
#include "idt.h"
#define NUM_DESC 256
typedef struct idtr {
uint16_t limit;
uint32_t base;
} __attribute__((packed)) idtr_t;
typedef union intr_gate_desc {
struct __attribute__((packed)) {
uint16_t offset_low;
uint16_t selector; /* Segment Selector for destination code segment */
uint16_t fixed:11;
uint16_t d:1; /* Size of gate: 1 = 32 bits; 0 = 16 bits */
uint16_t pad:1;
uint16_t dpl:2; /* Descriptor Privilege Level */
uint16_t p:1; /* Segment Present flag */
uint16_t offset_high;
};
uint64_t raw;
struct {
uint32_t raw_lo;
uint32_t raw_hi;
};
} intr_gate_desc_t;
/* According to Intel Combined Manual, Vol. 3, Section 6.10, the base addresses
* of the IDT should be aligned on an 8-byte boundary to maximize performance
* of cache line fills.
*/
static intr_gate_desc_t __attribute__((aligned(8))) ATTR_BSS_KERN
idt[NUM_DESC];
/*---------------------------------------------------------------------------*/
/* XXX: If you change this function prototype, make sure you fix the assembly
* code in SET_INT_EXC_HANDLER macro in interrupt.h. Otherwise, you might
* face a very-hard-to-find bug in the interrupt handling system.
*/
void
idt_set_intr_gate_desc(int intr_num,
uint32_t offset,
uint16_t cs,
uint16_t dpl)
{
intr_gate_desc_t desc;
desc.offset_low = offset & 0xFFFF;
desc.selector = cs;
desc.fixed = BIT(9) | BIT(10);
desc.pad = 0;
desc.d = 1;
desc.dpl = dpl;
desc.p = 1;
desc.offset_high = (offset >> 16) & 0xFFFF;
KERN_WRITEL(idt[intr_num].raw_hi, desc.raw_hi);
KERN_WRITEL(idt[intr_num].raw_lo, desc.raw_lo);
}
/*---------------------------------------------------------------------------*/
/* Initialize Interrupt Descriptor Table. The IDT is initialized with
* null descriptors. Therefore, any interrupt at this point will cause
* a triple fault.
*/
void
idt_init(void)
{
idtr_t idtr;
/* Initialize idtr structure */
idtr.limit = (sizeof(intr_gate_desc_t) * NUM_DESC) - 1;
idtr.base = KERN_DATA_OFF_TO_PHYS_ADDR((uint32_t)idt);
/* Load IDTR register */
__asm__("lidt %0\n\t" :: "m" (idtr));
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2015, 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 IDT_H
#define IDT_H
#include <stdint.h>
#include "prot-domains.h"
void idt_init(void);
void idt_set_intr_gate_desc(int intr_num,
uint32_t offset,
uint16_t cs,
uint16_t dpl);
#endif /* IDT_H */

View File

@ -1,148 +0,0 @@
/*
* Copyright (C) 2015, 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 INTERRUPT_H
#define INTERRUPT_H
#include <stdint.h>
#include "gdt-layout.h"
#include "idt.h"
struct interrupt_context {
/* The general-purpose register values are saved by the pushal instruction in
* the interrupt dispatcher. Having access to these saved values may be
* useful in some future interrupt or exception handler, and saving and later
* restoring them also enables the ISR to freely overwrite the EAX, ECX, and
* EDX registers as is permitted by the cdecl calling convention.
*/
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
/* These two values are pushed on the stack by the CPU when it delivers an
* exception with an associated error code. Currently, only the double fault
* handler accepts this structure as a parameter, and that type of exception
* does have an associated error code.
*/
uint32_t error_code;
uint32_t eip;
/* The CPU pushes additional values beyond these on the stack, specifically
* the code segment descriptor and flags. If a privilege-level change occurs
* during delivery, the CPU additionally pushes the stack pointer and stack
* segment descriptor.
*/
};
#define ISR_STUB(label_str, has_error_code, handler_str, exc) \
"jmp 2f\n\t" \
".align 4\n\t" \
label_str ":\n\t" \
" pushal\n\t" \
PROT_DOMAINS_ENTER_ISR(exc) \
" call " handler_str "\n\t" \
PROT_DOMAINS_LEAVE_ISR(exc) \
" popal\n\t" \
" .if " #has_error_code "\n\t" \
" add $4, %%esp\n\t" \
" .endif\n\t" \
" iret\n\t" \
"2:\n\t"
/* Helper macro to register interrupt handler function.
*
* num: Interrupt number (0-255)
* has_error_code: 0 if interrupt doesn't push error code onto the
* stack. Otherwise, set this argument to 1.
* handler: Pointer to function that should be called once the
* interrupt is raised. In case has_error_code == 0
* the function prototype should be the following:
* void handler(void)
* Otherwise, it should be:
* void handler(struct interrupt_context context)
* exc: 0 if this is an interrupt, which should be handled
* at the interrupt privilege level. 1 if this is an
* exception, which should be handled at the
* exception privilege level.
* dpl: Privilege level for IDT descriptor, which is the
* numerically-highest privilege level that can
* generate this interrupt with a software interrupt
* instruction.
*
* Since there is no easy way to write an Interrupt Service Routines
* (ISR) in C (for further information on this, see [1]), we provide
* this helper macro. It basically provides an assembly trampoline
* to a C function (handler parameter) which, indeed, handles the
* interrupt.
*
* [1] http://wiki.osdev.org/Interrupt_Service_Routines
*/
#define SET_INT_EXC_HANDLER(num, has_error_code, handler, exc, dpl) \
do { \
__asm__ __volatile__ ( \
"pushl %[_dpl_]\n\t" \
"pushl %[_cs_]\n\t" \
"pushl $1f\n\t" \
"pushl %[_isr_num_]\n\t" \
"call idt_set_intr_gate_desc\n\t" \
"add $16, %%esp\n\t" \
ISR_STUB("1", has_error_code, "%P[_handler_]", exc) \
: \
: [_isr_num_] "g" (num), \
[_handler_] "i" (handler), \
[_cs_] "i" (exc ? GDT_SEL_CODE_EXC : GDT_SEL_CODE_INT), \
[_dpl_] "i" (dpl) \
/* the invocation of idt_set_intr_gate_desc may clobber */ \
/* the caller-saved registers: */ \
: "eax", "ecx", "edx" \
); \
} while (0)
#define SET_INTERRUPT_HANDLER(num, has_error_code, handler) \
SET_INT_EXC_HANDLER(num, has_error_code, handler, 0, PRIV_LVL_INT)
#define SET_EXCEPTION_HANDLER(num, has_error_code, handler) \
SET_INT_EXC_HANDLER(num, has_error_code, handler, 1, PRIV_LVL_EXC)
/* Disable maskable hardware interrupts */
#define DISABLE_IRQ() \
do { \
__asm__ ("cli"); \
} while (0)
/* Enable maskable hardware interrupts */
#define ENABLE_IRQ() \
do { \
__asm__ ("sti"); \
} while (0)
#endif /* INTERRUPT_H */

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2015, 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 IRQ_H
#define IRQ_H
void irq_init(void);
#endif /* IRQ_H */

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2015, 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 "drivers/legacy_pc/pic.h"
#include "interrupt.h"
#include "irq.h"
#define IRQ7_INT PIC_INT(7)
static void
spurious_irq7_handler(void)
{
/*
* NOTE: Originally IRQ7 was used for the parallel port interrupts. Nowadays,
* though, it is only used if some other IRQ (i.e.: a PCIx interrupt) is
* mapped to it. In this case we will have to check the PIC ISR register in
* order to confirm this was a real interrupt.
*
* In case of a spurious interrupt, we should NEVER send an EOI here so the PIC
* doesn't trigger the next queued interrupt.
*/
}
/*---------------------------------------------------------------------------*/
void
irq_init(void)
{
pic_init();
/* Set a 'fake' handler for the Spurious IRQ7 interrupts.
* Refer to http://wiki.osdev.org/PIC .
*/
SET_INTERRUPT_HANDLER(IRQ7_INT, 0, spurious_irq7_handler);
}

View File

@ -1,997 +0,0 @@
X86 Lightweight Protection Domain Support for Contiki
=====================================================
Introduction
------------
The X86 port of Contiki implements a simple, lightweight form of
protection domains using a pluggable framework. Currently, there are
three plugins available:
- Flat memory model with paging.
- Multi-segment memory model with either hardware- or
software-switched segments. The hardware-switched segments
approach is based on Task-State Segment (TSS) structures.
For an introduction to paging and TSS and possible ways in which they
can be used, refer to the following resources:
- Intel Combined Manual (Intel 64 and IA-32 Architectures Software
Developer's Manual), Vol. 3, Chapter 4
- Programming the 80386, by John H. Crawford and Patrick
P. Gelsinger, Chapter 5
The overall goal of a protection domain implementation within this
framework is to define a set of resources that should be accessible to
each protection domain and to prevent that protection domain from
accessing other resources. The details of each implementation of
protection domains may differ substantially, but they should all be
guided by the principle of least privilege [1]. However, that
idealized principle is balanced against the practical objectives of
limiting the number of relatively time-consuming context switches and
minimizing changes to existing code. In fact, no changes were made to
code outside of the CPU- and platform-specific code directories for
the initial plugins.
Each protection domain can optionally be associated with a metadata
and/or MMIO region. The hardware can support additional regions per
protection domain, but that would increase complexity and is unneeded
for the existing protection domains.
After boot, all code runs in the context of some protection domain.
Two default protection domains are implemented:
- kern: Kernel protection domain that is more privileged than any
other protection domain. As little code as possible should be placed
in this protection domain.
- app: Application protection domain used whenever special privileges
are not required.
Additional protection domains are defined as needed. For example,
each driver may reside in a separate protection domain, although not
all drivers require additional privileges beyond those available in
the relevant scheduling context in the app protection domain. The
Ethernet and UART drivers are assigned separate protection domains.
Non-driver protection domains can also be defined. Other drivers only
require access to programmed IO ports accessible via the IN* and OUT*
instructions, and such drivers do not require separate protection
domains. They run in the Contiki preemptive scheduling context and
the kernel protection domain, both of which are granted access to all
IO ports.
Each protection domain may have associated system calls. A system
call transfers control from a client protection domain to a defined
entrypoint in a server protection domain. As their name suggests,
system calls adhere to a synchronous call-return model (rather than
some alternative such as an asynchronous message-passing model). To
invoke a system call, the client provides two identifiers to the
system call dispatcher. The first identifies the server domain and
the second identifies the system call to be invoked. The protection
domain implementation should associate allowable system calls with
particular server protection domains and reject any system call
requests that are not within that set of allowable system calls. The
system call implementations do not restrict the clients that are
permitted to invoke each system call. No modifications that the
client can make to the server domain and system call identifiers can
open up new entrypoints into the server domain. The entrypoints are
fixed at boot time.
However, if the identifiers were stored in shared memory, it may be
possible for a protection domain to influence the system calls issued
by some other protection domain, which may be undesirable. Thus, the
server domain identifiers are stored in memory that can only be
written by the kernel protection domain and the system call
identifiers are embedded in the code.
The system call dispatcher is responsible for reconfiguring the system
to enforce the appropriate resource access controls for the server
protection domain. It should then transfer control to the approved
entrypoint for the requested system call.
Contiki defines a process concept that is orthogonal to protection
domains [2]. A single Contiki process may run code in multiple
protection domains at various points in time. Contiki processes run
in a cooperative scheduling context. Contiki also defines a
preemptive scheduling context for interrupt handlers and real-time
timers. When protection domain support is enabled, interrupts are
only enabled when the application protection domain is active and is
running code in the cooperative scheduling context. Code running in
the preemptive context may also invoke multiple protection domains.
Contiki can also support preemptive multithreading, but support for
that has not yet been added to the X86 port so we do not discuss it
further.
A single stack is shared by all code that runs in the cooperative
scheduling context in all protection domains, and separate stacks are
defined for short interrupt dispatchers in the preemptive scheduling
context and for exception handlers and software system call
dispatchers. Except for the interrupt dispatchers, code in the
preemptive scheduling context also shares the same stack with the
cooperative scheduling context. All protection domains also share a
main data section, so similar considerations are also relevant to
that.
Introducing multi-core support would complicate things further, since
another core running a protection domain that the first core never
invoked could access data from the protection domain on the first
core. It may be possible to adequately address such concerns by
allocating per-core stacks.
Note that this stack arrangement means that a given protection domain
may read and write data written to the stack by some other protection
domain. For example, a protection domain B may push data onto the
stack and later pop that data off of the stack, but a protection
domain A that invoked protection domain B may still be able to read
the data that was pushed and popped to and from the stack, since
popping the data off of the stack does not automatically erase that
stack memory location. Another possibility is that protection domain
B may modify a stack entry pushed by protection domain A before it
invoked protection domain B, and protection domain A may later use the
modified value. Permitting legitimate accesses to callers' stacks is
in fact the primary motivation for this stack arrangement, in that it
makes it simple for A to pass data to and from B (on the shared stack)
when requesting services from B. A system call invocation is nearly
transparent to the developer, appearing almost identical to an
ordinary function call. However, B can access any data on the stack.
The third case is that A can read data placed on the stack by B after
B returns, unless B wipes that data from the stack before returning.
A related sub-case is that if an interrupt handler is invoked, it
pushes the current contents of the general-purpose registers onto the
stack, which may then be revealed to other protection domains besides
the one that was interrupted. However, interrupts are only actually
enabled in the application protection domain.
Similarly, register contents may be accessed and modified across
protection domain boundaries in some protection domain
implementations. The TSS task switching mechanism automatically saves
and restores many registers to and from TSS data structures when
switching tasks, but the other protection domain implementations do
not perform analogous operations.
For the reasons described above, each protection domain should only
invoke other protection domains that it trusts to properly handle data
on the stack.
Design
------
### Boot Process
The system boots in the following phases.
#### UEFI Bootstrap
Primary implementation sources:
- cpu/x86/uefi/bootstrap_uefi.c
When the OS is compiled as a UEFI binary, a short bootstrap phase that
is UEFI-compliant is run initially. It simply performs a minimal set
of functions to exit the UEFI boot services and then transfer control
to the Multiboot bootstrap phase.
#### Multiboot Bootstrap
Primary implementation sources:
- cpu/x86/bootstrap_quarkX1000.S
This phase disables interrupts, sets the stack pointer to the top of
the main stack, and then invokes boot stage 0.
#### Boot Stage 0
Primary implementation sources:
- cpu/x86/init/common/cpu.c
- cpu/x86/init/common/gdt.c
The UEFI firmware or Multiboot-compliant bootloader should have
configured an initial Global Descriptor Table (GDT) with flat segments
and configured the CPU to operate in protected mode with paging
disabled. Flat segments each map the whole 4GiB physical memory
space. This is the state of the system when the OS enters boot stage
0. This stage is responsible for setting up a new GDT and loading the
segment registers with the appropriate descriptors from the new GDT to
enable boot stage 1 to run. Code in stage 1 for multi-segment
protection domain implementations require that the appropriate
segment-based address translations be configured.
#### Boot Stage 1
Primary implementation sources:
- cpu/x86/init/common/cpu.c
- cpu/x86/init/common/idt.c
- cpu/x86/mm/prot-domains.c
Boot stage 1 intializes the Interrupt Descriptor Table (IDT) and
installs a handler for double-fault exceptions. Handlers for
additional interrupts and exceptions are installed later in boot
stages 1 and 2.
This stage also initializes protection domain support and enters the
kernel protection domain.
#### Boot Stage 2
Primary implementation sources:
- cpu/x86/init/common/cpu.c
- platform/galileo/contiki-main.c
The entrypoint for the kernel protection domain is 'main'. Boot stage
2 initializes hardware devices and associated interrupts. It then
transfers control to the application protection domain. Note that
this is a transfer of control, not a call that would be matched with
some future return. This is an important distinction, because
protection domains are not reentrant. Thus, if the kernel protection
domain called the application protection domain, it would not be
possible to invoke any kernel system calls until the system is reset,
since the application protection domain never exits/returns while the
system is running. There are not actually any kernel system calls
provided in the initial implementation of protection domains, but they
may be added in the future.
The core protection domain configuration (e.g. allowable system calls
and entrypoints, registered protection domains, etc.) is frozen by the
conclusion of boot stage 2 to help prevent erroneous changes that
could reduce the robustness of the system. The way that it is frozen
is that there are no kernel system calls that are intended to permit
changes to the core protection domain configuration. Thus, once the
kernel protection domain has exited, the only way the core protection
domain configuration can change would be due to undesirable memory
manipulations (e.g. due to a faulty device driver).
#### Boot Stage 3
Primary implementation sources:
- platform/galileo/contiki-main.c
Boot stage 3 performs initialization procedures that are less
tightly-coupled to hardware. For example, it launches Contiki
processes and invokes Contiki configuration routines.
### Privilege Levels
When protection domain support is inactive, all code runs at
ring/privilege level 0. When protection domain support is active,
only exception handlers and system call dispatchers (including
dispatchers for system call returns) run at ring level 0. Code in the
preemptive scheduling context runs at ring level 2 and code in the
cooperative scheduling context runs at ring level 3. Ring levels with
higher numbers are less privileged than those with lower numbers.
Ring level 1 is unused.
### IO and Interrupt Privileges
The kernel protection domain cooperative scheduling context needs
access to IO ports, for device initialization. Some other protection
domains also require such access. The IO Privilege Level (IOPL) that
is assigned to a protection domain using the relevant bits in the
EFLAGS field could be set according to whether IO port access is
required in that protection domain. This is straightforward for TSS,
which includes separate flags settings for each protection domain.
However, this would introduce additional complexity and overhead in
the critical system call and return dispatchers for other plugins.
Instead, the IOPL is always set to block IO access from the
cooperative scheduling context. Port IO instructions in that context
will then generate general protection faults, and the exception
handler decodes and emulates authorized port IO instructions.
Interrupts are handled at ring level 2, since they do not use any
privileged instructions. They do cause the interrupt flag to be
cleared as they are delivered. The interrupt flag can only be
modified by instructions executing at a ring level that is numerically
less than or equal to the IOPL. Each interrupt handler needs to set
the interrupt flag using the IRET instruction when it returns.
Protection domains that require access to port IO (currently just the
kernel protection domain) are configured with an IOPL of 3 whereas
others are configured with an IOPL of 2. That is why interrupts are
configured to run at ring level 2. Interrupts are only enabled in the
application protection domain.
Some interrupt handlers require access to port IO, and all are
permitted such access, since they need it anyway for restoring the
interrupt flag when returning. IO port access is a very powerful
privilege, since it can be used to remap MMIO regions of PCI devices,
reconfigure PCI devices, etc. Thus, further restricting access to IO
ports may improve the robustness of the system, but would increase
complexity and space requirements and possibly necessitate additional
context switches, since IO port access is controlled by the combined
settings of IOPL as well as an optional IO bitmap in the TSS.
### Interrupt and Exception Dispatching
Primary implementation sources:
- cpu/x86/init/common/interrupt.h
Separate stacks are allocated for dispatching interrupts and
exceptions. However, to save space, the main bodies of some interrupt
and exception handlers are run on the main stack. A handler may
expect to have access to data from the interrupt or exception stack,
so the interrupt or exception dispatcher copies that data prior to
pivoting to the main stack and executing the handler.
### Protection Domain Control Structures (PDCSes)
Each protection domain is managed by the kernel and privileged
functions using a PDCS. The structure of the PDCS is partially
hardware-imposed in the cases of the two segment-based plugins, since
the PDCS contains the Local Descriptor Table (LDT) and the TSS, if
applicable. In the paging plugin, the PDCS structure is entirely
software-defined. None of the initial protection domain plugins
support re-entrant protection domains due to hardware-imposed
limitations of TSS and to simplify the implementation of the other
plugins by enabling domain-specific information (e.g. system call
return address) to be trivially stored in each PDCS.
### Paging-Based Protection Domains
Primary implementation sources:
- cpu/x86/mm/paging-prot-domains.c
- cpu/x86/mm/syscalls-int.c
- cpu/x86/mm/syscalls-int-asm.S
#### Introduction
Only a single page table is used for all protection domains. A flat
memory model is used. Almost all linear-to-physical address mappings
are identity mappings, with the exceptions being the MMIO and metadata
regions. The X86 port of Contiki currently only supports at most one
MMIO and one metadata range per driver, and the paging-based
protection domain implementation always starts at particular linear
addresses when mapping an MMIO or metadata range. This may reduce
overhead, due to the way protection domain switches are implemented.
#### System Call and Return Dispatching
The system call dispatcher executes at ring level 0, since it uses the
privileged INVLPG or MOV CR3 instructions to invalidate TLB entries.
The dispatcher modifies page table entries to grant only the
permissions required by the protection domain being activated. It
then optionally uses the INVLPG instruction to invalidate any TLB
entries for any page table entries that were modified. If INVLPG is
not used to invalidate specific TLB entries, then CR3 is reloaded to
invalidate the entire TLB (global entries would be excluded, but they
are not used in this implementation).
It is more efficient to always start at a particular linear address
when mapping an MMIO or metadata region, since the page table entries
for that region can be updated to unmap any previous region of that
type, map the new region, and then invalidated to cause the new
settings to take effect. The alternative using an identity
linear-to-physical address mapping for regions would be to unmap the
previous region by editing one set of page table entries and to then
map the new region by editing a different set of page table entries
and to finally perform invalidations for both sets of page table
entries. Another drawback of such an identity address mapping is that
additional page tables may need to be allocated to represent the
various MMIO regions, since page tables are indexed by linear address
and MMIO regions are often at high physical addresses. Note that this
is specific to MMIO regions, since metadata regions are not at
particularly high physical addresses. Additionally, if different base
linear addresses are used, it is necessary to communicate those to the
system call handler code so that the regions can be accessed. This
would require care to prevent an adversary from manipulating the
addresses and it may increase complexity.
The overall process of handling a system call can be illustrated at a
high level as follows. Some minor steps are omitted in the interest
of clarity and brevity.
```
== BEGIN Client protection domain ==========================================
-- BEGIN Caller ------------------------------------------------------------
1. Call system call stub.
--
20. Continue execution...
-- END Caller --------------------------------------------------------------
-- BEGIN System call stub --------------------------------------------------
2. Already in desired (server) protection domain?
- No: Issue software interrupt #100 to request system call.
- Yes: Jump to system call body.
-- END System call stub ----------------------------------------------------
== END Client protection domain ============================================
== BEGIN Ring level 0 ======================================================
-- BEGIN System call dispatcher---------------------------------------------
3. Check that the requested system call is allowed. Get entrypoint.
4. Check that the server protection domain is available (not yet present
in the protection domain call stack) and then mark it as busy.
5. Save the caller return address from the main stack into the client
PDCS.
6. Overwrite the caller return address on the main stack to point to
system call return stub.
7. Push server protection domain onto protection domain call stack.
8. Update the interrupt return stack EIP to start of system call body.
9. Update and invalidate page table entries to grant only the permissions
required by the server protection domain.
10. Update interrupt flag to disable interrupts, since interrupts are only
enabled in app protection domain, which exports no system calls.
11. Perform interrupt return (IRET).
-- END System call dispatcher ----------------------------------------------
-- BEGIN System call return dispatcher -------------------------------------
15. Mark protection domain on top of protection domain call stack as
available.
16. Retrieve the caller return address from the kernel data structure for
the client protection domain and use it to overwrite the EIP in the
interrupt return stack.
17. Update and invalidate page table entries to grant only the permissions
required by the client protection domain.
18. Update interrupt flag to only enable interrupts if returning to app
protection domain cooperative scheduling context.
19. Perform interrupt return (IRET).
-- END System call dispatcher ----------------------------------------------
== END Ring level 0 ========================================================
== BEGIN Server protection domain ==========================================
-- BEGIN System call body --------------------------------------------------
12. Execute the work for the requested system call.
13. Return (to system call return stub, unless invoked from server
protection domain, in which case return is to caller).
-- END System call body ----------------------------------------------------
-- BEGIN System call return stub -------------------------------------------
14. Issue software interrupt #101 to request system call return.
-- END System call return stub ---------------------------------------------
== END Server protection domain ============================================
```
The first step in performing a system call is to invoke a system call
stub that actually issues the software interrupt to request a system
call dispatch. This approach reduces disruption to existing code,
since macros are used to generate separate stubs and corresponding
system call bodies with a single system call signature definition.
#### Memory Layout
The approximate memory layout of the system is depicted below,
starting with the highest physical addresses and proceeding to lower
physical addresses. Optional permissions are denoted with
parentheses. See cpu/x86/quarkX1000_paging.ld for details of how this
memory layout is implemented.
```
| Kernel | App | Other |
... +--------+--------+--------+
+------------------------------------------+ | | | |
| Domain X MMIO | | | | (RW) |
+------------------------------------------+ | | | |
... | | | |
+------------------------------------------+ | | | |
| Domain X DMA-accessible metadata | | | | (RW) |
| (section .dma_bss) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Domain X metadata (section .meta_bss) | | | | (RW) |
+------------------------------------------+ | | | |
... | | | |
+------------------------------------------+ | | | |
| Kernel-private data | | RW | | |
| (sections .prot_dom_bss, .gdt_bss, etc.) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| System call data (section .syscall_bss) | | RW | R | R |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Kernel-owned data (section .kern_bss) | | RW | R | R |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Page-aligned, Kernel-owned data | | RW | R | R |
| (section .page_aligned_kern_bss) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Common data | | RW | RW | RW |
| (sections .data, .rodata*, .bss, etc.) | | | | |
+------------------------------------------+ | | | |
(not-present guard band page) | | | |
+------------------------------------------+ | | | |
| Exception stack | | RW | RW | RW |
| (section .exc_stack) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Interrupt stack | | RW | RW | RW |
| (section .int_stack) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Main stack (section .main_stack) | | RW | RW | RW |
+------------------------------------------+ | | | |
(not-present guard band page) | | | |
+------------------------------------------+ | | | |
| Main code (.text) | | RX | RX | RX |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Bootstrap code (section .boot_text) | | | | |
+------------------------------------------+ | | | |
+------------------------------------------+ | | | |
| Multiboot header | | | | |
+------------------------------------------+ | | | |
...
```
The only protection domain that is permitted to access kernel-owned
data is the kernel protection domain. Some devices can also be
instructed to perform DMA to kernel-owned data, although that is an
incorrect configuration.
Paging only differentiates between memory accesses from ring 3 (user
level) and those from rings 0-2 (supervisor level). To avoid granting
code running in the preemptive scheduling context supervisory write
access to kernel data structures (including the page tables), those
structures are marked read-only (except when the kernel protection
domain is active) and the Write Protect (WP) bit in Control Register 0
(CR0) is cleared only when it is necessary to update a write-protected
structure. Only ring 0 is allowed to modify CR0.
Optional metadata for each protection domain is intended to only be
accessible from the associated protection domain and devices.
Read accesses to executable code have not been observed to be needed
in at least a limited set of tests, but they are permitted, since
paging does not support an execute-only permission setting. On the
other hand, the Execute-Disable feature is used to prevent execution
of non-code memory regions. All non-startup code is mapped in all
protection domains. Limiting the code that is executable within each
protection domain to just the code that is actually needed within that
protection domain could improve the robustness of the system, but it
is challenging to determine all code that may be needed in a given
protection domain (e.g. all needed library routines).
Stack accesses to non-stack memory are not needed, but they are
permitted. However, one page of unmapped linear address space is
placed above and below the stacks to detect erroneous stack accesses
to those linear address regions, which are the types of accesses most
likely to occur during a stack overflow or underflow condition. The
main stack is placed just below the interrupt stack, which is just
below the exception stack. Stack overflows are more common than stack
underflows, which motivates arranging the stacks such that an overflow
from a less-critical stack will not affect a more-critical stack.
Furthermore, the main stack is the most likely to overflow, since the
code that uses it is typically the most voluminous and difficult to
characterize. That provides additional motivation for positioning it
such that an overflow results in an immediate page fault. An
alternative design placing each stack on a separate group of
contiguous pages may improve the robustness of the system by
permitting the insertion of unmapped guard pages around them to
generate page faults in the event an overflow or underflow occurs on
any stack. However, that would consume additional memory.
Data in the .rodata sections is marked read/write, even though it may
be possible to improve the robustness of the system by marking that
data as read-only. Doing so would introduce additional complexity
into the system.
### Hardware-Switched Segment-Based Protection Domains
Primary implementation sources:
- cpu/x86/mm/tss-prot-domains.c
- cpu/x86/mm/tss-prot-domains-asm.S
#### Introduction
One TSS is allocated for each protection domain. Each one is
associated with its own dedicated LDT. The memory resources assigned
to each protection domain are represented as segment descriptors in
the LDT for the protection domain. Additional shared memory resources
are represented as segment descriptors in the GDT.
#### System Call and Return Dispatching
The system call dispatcher runs in the context of the server
protection domain. It is a common piece of code that is shared among
all protection domains. Thus, each TSS, except the application TSS,
has its EIP field initialized to the entrypoint for the system call
dispatcher so that will be the first code to run when the first switch
to that task is performed.
The overall process of handling a system call can be illustrated at a
high level as follows. Some minor steps are omitted from this
illustration in the interest of clarity and brevity.
```
== BEGIN Client protection domain ==========================================
-- BEGIN Caller ------------------------------------------------------------
1. Call system call stub.
--
13. Continue execution...
-- END Caller --------------------------------------------------------------
-- BEGIN System call stub --------------------------------------------------
2. Already in desired (server) protection domain?
- No: Request task switch to server protection domain.
- Yes: Jump to system call body.
--
12. Return to caller.
-- END System call stub ----------------------------------------------------
== END Client protection domain ============================================
== BEGIN Server protection domain ==========================================
-- BEGIN System call dispatcher---------------------------------------------
3. Check that the requested system call is allowed. Get entrypoint.
4. Switch to the main stack.
5. Pop the client return address off the stack to a callee-saved register.
6. Push the address of the system call return dispatcher onto the stack.
7. Jump to system call body.
--
10. Restore the client return address to the stack.
11. Request task switch to client protection domain.
-- END System call dispatcher ----------------------------------------------
-- BEGIN System call body --------------------------------------------------
8. Execute the work for the requested system call.
9. Return (to system call return stub, unless invoked from server
protection domain, in which case return is to caller).
-- END System call body ----------------------------------------------------
== END Server protection domain ============================================
```
An additional exception handler is needed, for the "Device Not
Available" exception. The handler comprises just a CLTS and an IRET
instruction. The CLTS instruction is privileged, which is why it must
be run at ring level 0. This exception handler is invoked when a
floating point instruction is used following a task switch, and its
sole purpose is to enable the floating point instruction to execute
after the exception handler returns. See the TSS resources listed
above for more details regarding interactions between task switching
and floating point instructions.
Each segment register may represent a different data region within
each protection domain, although the FS register is used for two
separate purposes at different times. The segments are defined as
follows:
- CS (code segment) maps all non-startup code with execute-only
permissions in all protection domains. Limiting the code that is
executable within each protection domain to just the code that is
actually needed within that protection domain could improve the
robustness of the system, but it is challenging to determine all
code that may be needed in a given protection domain (e.g. all
needed library routines). Furthermore, that code may not all be
contiguous, and each segment descriptor can only map a contiguous
memory region. Finally, segment-based memory addressing is
relative to an offset of zero from the beginning of each segment,
introducing additional complexity if such fine-grained memory
management were to be used.
- DS (default data segment) typically maps the main stack and all
non-stack data memory that is accessible from all protection
domains. Limiting the data that is accessible via DS within each
protection domain to just the subset of the data that is actually
needed within that protection domain could improve the robustness
of the system, but it is challenging for similar reasons to those
that apply to CS. Access to the main stack via DS is supported so
that code that copies the stack pointer to a register and attempts
to access stack entries via DS works correctly. Disallowing access
to the main stack via DS could improve the robustness of the
system, but that may require modifying code that expects to be able
to access the stack via DS.
- ES is loaded with the same segment descriptor as DS so that string
operations (e.g. the MOVS instruction) work correctly.
- FS usually maps the kernel-owned data region. That region can only
be written via FS in the kernel protection domain. FS contains a
descriptor specifying a read-only mapping in all other protection
domains except the application protection domain, in which FS is
nullified. Requiring that code specifically request access to the
kernel-owned data region by using the FS segment may improve the
robustness of the system by blocking undesired accesses to the
kernel-owned data region via memory access instructions within the
kernel protection domain that implicitly access DS. The reason for
granting read-only access to the kernel-owned data region from most
protection domains is that the system call dispatcher runs in the
context of the server protection domain to minimize overhead, and
it requires access to the kernel-owned data region. It may improve
the robustness of the system to avoid this by running the system
call dispatcher in a more-privileged ring level (e.g. ring 1)
within the protection domain and just granting access to the
kernel-owned data region from that ring. However, that would
necessitate a ring level transition to ring 3 when dispatching the
system call, which would increase overhead. The application
protection domain does not export any system calls, so it does not
require access to the kernel-owned data region.
- FS is temporarily loaded with a segment descriptor that maps just
an MMIO region used by a driver protection domain when such a
driver needs to perform MMIO accesses.
- GS maps an optional region of readable and writable metadata that
can be associated with a protection domain. In protection domains
that are not associated with metadata, GS is nullified.
- SS usually maps just the main stack. This may improve the
robustness of the system by enabling immediate detection of stack
underflows and overflows rather than allowing such a condition to
result in silent data corruption. Interrupt handlers use a stack
segment that covers the main stack and also includes a region above
the main stack that is specifically for use by interrupt handlers.
In like manner, exception handlers use a stack segment that covers
both of the other stacks and includes an additional region. This
is to support the interrupt dispatchers that copy parameters from
the interrupt-specific stack region to the main stack prior to
pivoting to the main stack to execute an interrupt handler body.
The approximate memory layout of the system is depicted below,
starting with the highest physical addresses and proceeding to lower
physical addresses. The memory ranges that are mapped at various
times by each of the segment registers are also depicted. Read the
descriptions of each segment above for more information about what
memory range may be mapped by each segment register at various times
with various protection domain configurations. Parenthetical notes
indicate the protection domains that can use each mapping. The suffix
[L] indicates that the descriptor is loaded from LDT. Optional
mappings are denoted by a '?' after the protection domain label. The
'other' protection domain label refers to protection domains other
than the application and kernel domains.
```
...
+------------------------------------------+ \
| Domain X MMIO | +- FS[L]
+------------------------------------------+ / (other?)
...
+------------------------------------------+ \
| Domain X DMA-accessible metadata | +- GS[L] (other?)
| (section .dma_bss) | |
+------------------------------------------+ /
+------------------------------------------+ \
| Domain X metadata (section .meta_bss) | +- GS[L] (other?)
+------------------------------------------+ /
...
+------------------------------------------+ \
| Kernel-private data | |
| (sections .prot_dom_bss, .gdt_bss, etc.) | +- FS[L] (kern)
+------------------------------------------+ |
+------------------------------------------+ \
| System call data (section .syscall_bss) | |
+------------------------------------------+ +- FS[L] (all)
+------------------------------------------+ |
| Kernel-owned data (section .kern_bss) | |
+------------------------------------------+ /
+------------------------------------------+ \
| Common data | |
| (sections .data, .rodata*, .bss, etc.) | |
+------------------------------------------+ +- DS, ES
+------------------------------------------+ \ | (all)
| Exception stack (section .exc_stack) | | |
|+----------------------------------------+| \ |
|| Interrupt stack (section .int_stack) || | |
||+--------------------------------------+|| \ |
||| Main stack (section .main_stack) ||| +- SS (all) |
+++--------------------------------------+++ / /
+------------------------------------------+ \
| Main code (.text) | +- CS (all)
+------------------------------------------+ /
+------------------------------------------+
| Bootstrap code (section .boot_text) |
+------------------------------------------+
+------------------------------------------+
| Multiboot header |
+------------------------------------------+
...
```
This memory layout is more efficient than the layout that is possible
with paging-based protection domains, since segments have byte
granularity, whereas the minimum unit of control supported by paging
is a 4KiB page. For example, this means that metadata may need to be
padded to be a multiple of the page size. This may also permit
potentially-undesirable accesses to padded areas of code and data
regions that do not entirely fill the pages that they occupy.
Kernel data structure access, including to the descriptor tables
themselves, is normally restricted to the code running at ring level
0, specifically the exception handlers and the system call and return
dispatchers. It is also accessible from the cooperative scheduling
context in the kernel protection domain. Interrupt delivery is
disabled in the kernel protection domain, so the preemptive scheduling
context is not used.
SS, DS, and ES all have the same base address, since the compiler may
assume that a flat memory model is in use. Memory accesses that use a
base register of SP/ESP or BP/EBP or that are generated by certain
other instructions (e.g. PUSH, RET, etc.) are directed to SS by
default, whereas other accesses are directed to DS or ES by default.
The compiler may use an instruction that directs an access to DS or ES
even if the data being accessed is on the stack, which is why these
three segments must use the same base address. However, it is
possible to use a lower limit for SS than for DS and ES for the
following reasons. Compilers commonly provide an option for
preventing the frame pointer, EBP, from being omitted and possibly
used to point to non-stack data. In our tests, compilers never used
ESP to point to non-stack data.
Each task switch ends up saving and restoring more state than is
actually useful to us, but the implementation attempts to minimize
overhead by configuring the register values in each TSS to reduce the
number of register loads that are needed in the system call
dispatcher. Specifically, two callee-saved registers are populated
with base addresses used when computing addresses in the entrypoint
information table as well as a mask corresponding to the ID of the
server protection domain that is used to check whether the requested
system call is exported by the server protection domain. Callee-saved
registers are used, since the task return will update the saved
register values.
Note that this implies that the intervening code run between the task
call and return can modify critical data used by the system call
dispatcher. However, this is analogous to the considerations
associated with sharing a single stack amongst all protection domains
and should be addressed similarly, by only invoking protection domains
that are trusted by the caller to not modify the saved critical
values. This consideration is specific to the TSS-based dispatcher
and is not shared by the ring 0 dispatcher used in the other
plugins.
Data in the .rodata sections is marked read/write, even though it may
be possible to improve the robustness of the system by marking that
data as read-only. Doing so would introduce even more complexity into
the system than would be the case with paging-based protection
domains, since it would require allocating different segment
descriptors for the read-only vs. the read/write data.
#### Supporting Null-Pointer Checks
A lot of code considers a pointer value of 0 to be invalid. However,
segment offsets always start at 0. To accommodate the common software
behavior, at least the first byte of each segment is marked as
unusable. An exception to this is that the first byte of the stack
segments is usable.
#### Interrupt and Exception Dispatching
A distinctive challenge that occurs during interrupt and exception
dispatching is that the state of the segment registers when an
interrupt or exception occurs is somewhat unpredictable. For example,
an exception may occur while MMIO is being performed, meaning that FS
is loaded with the MMIO descriptor instead of the kernel descriptor.
Leaving the segment registers configured in that way could cause
incorrect interrupt or exception handler behavior. Thus, the
interrupt or exception dispatcher must save the current segment
configuration, switch to a configuration that is suitable for the
handler body, and then restore the saved segment configuration after
the handler body returns. Another motivation for this is that the
interrupted code may have corrupted the segment register configuration
in an unexpected manner, since segment register load instructions are
unprivileged. Similar segment register updates must be performed for
similar reasons when dispatching system calls.
### Software-Switched Segment-Based Protection Domains
Primary implementation sources:
- cpu/x86/mm/swseg-prot-domains.c
The requirement to allocate a TSS for each protection domain in the
hardware-switched segments plugin may consume a substantial amount of
space, since the size of each TSS is fixed by hardware to be at least
104 bytes. The software-switched segments plugin saves space by
defining a more compact PDCS. However, the layout and definitions of
the segments is identical to what was described above for the
hardware-switched segments plugin.
The system call and return procedure is mostly identical to that for
paging-based protection domains. However, instead of updating and
invalidating page tables, the dispatchers update the LDT and some of
the segment registers.
### Pointer Validation
Primary implementation sources:
- cpu/x86/mm/syscalls.h
At the beginning of each system call routine, it is necessary to check
that any untrusted pointer that could have been influenced by a caller
(i.e. a stack parameter or global variable) refers to a location above
the return address and to halt otherwise. This is to prevent a
protection domain from calling a different protection domain and
passing a pointer that references a location in the callee's stack
other than its parameters to influence the execution of the callee in
an unintended manner. For example, if an incoming pointer referenced
the return address, it could potentially redirect execution with the
privileges of the callee protection domain.
When the paging-based plugin is in use, it is also necessary to check
that the pointer is either within the stack region or the shared data
region (or a guard band region, since that will generate a fault) to
prevent redirection of data accesses to MMIO or metadata regions. The
other plugins already configure segments to restrict accesses to DS to
just those regions. Pointers provided as inputs to system calls as
defined above should never be dereferenced in any segment other than
DS.
The pointer is both validated and copied to a new storage location,
which must be within the callee's local stack region (excluding the
parameter region). This is to mitigate scenarios such as two pointers
being validated and an adversary later inducing a write through one of
the pointers to the other pointer to corrupt the latter pointer before
it is used.
Any pointer whose value is fixed at link or load time does not need to
be validated prior to use, since no adversary within the defined
threat model is able to influence the link or load process.
### DMA Restrictions
Primary implementation sources:
- cpu/x86/drivers/quarkX1000/imr.c
- cpu/x86/drivers/quarkX1000/imr-conf.c
The CPU is not the only agent with the ability to issue requests to
the interconnect within the SoC. For example, SoC peripherals such as
the Ethernet driver use DMA to efficiently access memory buffers.
This could introduce a risk that DMA could be used to bypass the
memory protections enforced on the CPU by segmentation or paging. For
example, a device driver could instruct a device to access a memory
region to which the kernel has not granted the driver's protection
domain permission to access.
The Isolated Memory Region (IMR) feature is configured to restrict the
memory that can be accessed by system agents other than the CPU [3].
It only allows those system agents to access portions of the Contiki
memory space that are specifically intended to be used with DMA. The
source code for each protection domain specifies that its optional
metadata region needs to be accessible from other system agents
besides the CPU by using ATTR_BSS_DMA instead of ATTR_BSS_META when
allocating storage for the metadata.
Extending the Framework
-----------------------
### Adding a New Protection Domain
The following steps are required. See the existing device drivers for
examples of various types of protection domains and how they are
initialized.
- Allocate storage for the PDCS and the corresponding
client-accessible data structure using the PROT_DOMAINS_ALLOC
macro.
- Apply the ATTR_BSS_META attribute to the metadata structure, if
applicable. Apply the ATTR_BSS_DMA attribute instead if the
metadata structure needs to be DMA-accessible. Pad the metadata
structure to completely fill an integer multiple of the minimum
page size, 4096, when paging-based protection domains are in use.
See the definition of quarkX1000_eth_meta_t for an example.
- Perform the following steps during boot stage 2:
- Initialize the protection domain ID in the client-accessible data
structure using the PROT_DOMAINS_INIT_ID macro.
- Register the domain. See prot-domains.c:prot_domains_init for an
example of registering a non-driver protection domain. See
cpu/x86/drivers/quarkX1000/eth.c:quarkX1000_eth_init for an
example of registering a PCI driver protection domain with an
MMIO region and a metadata region.
### Adding a New System Call
The following steps are required:
- Define the system call procedure using the SYSCALLS_DEFINE or
SYSCALLS_DEFINE_SINGLETON macro. See
cpu/x86/drivers/legacy_pc/uart-16x50.c:uart_16x50_tx for an example
of a non-singleton system call. See
cpu/x86/drivers/quarkX1000/eth.c:quarkX1000_eth_send for an example
of a singleton system call. A singleton system call is one for
which at most one server protection domain will be associated with
it.
- During boot phase 2, associate the system call with one or more
server protection domains using the SYSCALLS_AUTHZ macro.
Usage
-----
To enable protection domain support, add "X86_CONF_PROT_DOMAINS=" to
the command line and specify one of the following options:
- paging
- tss
- swseg
The paging option accepts a sub-option to determine whether the TLB is
fully- or selectively-invalidated during protection domain switches.
By default, full invalidation is selected. Set the
X86_CONF_USE_INVLPG variable to 1 to override the default.
References
----------
[1] J. H. Saltzer, "Protection and the Control of Information Sharing
in Multics," Commun. ACM, vol. 17, no. 7, pp. 388-402, Jul. 1974.
[2] https://github.com/contiki-os/contiki/wiki/Processes
[3] "Intel(R) Quark(TM) SoC X1000 Secure Boot Programmer's Reference
Manual,"
http://www.intel.com/support/processors/quark/sb/CS-035228.htm

View File

@ -1,138 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_MM_GDT_LAYOUT_H_
#define CPU_X86_MM_GDT_LAYOUT_H_
#include "prot-domains.h"
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
/**
* Number of fixed GDT descriptors. Additional descriptors may be defined
* outside of gdt.c.
*/
#define GDT_NUM_FIXED_DESC 7
#elif X86_CONF_PROT_DOMAINS_MULTI_SEG
#define GDT_NUM_FIXED_DESC 11
#else
#define GDT_NUM_FIXED_DESC 3
#endif
#define GDT_IDX_NULL 0
/**
* Flat code segment, used at boot and also for the rest of the system's
* runtime when protection domains are disabled
*/
#define GDT_IDX_CODE_FLAT 1
/**
* Flat data segment, used at boot and also for the rest of the system's
* runtime when protection domains are disabled
*/
#define GDT_IDX_DATA_FLAT 2
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
/** Default (post-boot) code segment */
#define GDT_IDX_CODE 3
/**
* Same bounds and permissions as default code segment, but at the interrupt
* handler privilege level
*/
#define GDT_IDX_CODE_INT 4
/** Stack segment for interrupt handlers */
#define GDT_IDX_STK_INT 5
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
#define GDT_IDX_CODE_EXC GDT_IDX_CODE_FLAT
/** Default data segment used by code at all privilege levels */
#define GDT_IDX_DATA 6
#define GDT_IDX_STK GDT_IDX_DATA
#define GDT_IDX_STK_EXC GDT_IDX_DATA_FLAT
#else
/**
* Same bounds and permissions as default code segment, but at the exception
* handler privilege level
*/
#define GDT_IDX_CODE_EXC 6
/** R/W kernel data descriptor used during boot stage 1 */
#define GDT_IDX_DATA_KERN_EXC 7
/** Default data segment used by code at all privilege levels */
#define GDT_IDX_DATA 8
/**
* Default stack segment, which overlaps with the beginning of the default data
* segment
*/
#define GDT_IDX_STK 9
/** Stack segment for exception handlers */
#define GDT_IDX_STK_EXC 10
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
#define GDT_IDX_TSS(dom_id) (GDT_NUM_FIXED_DESC + (2 * (dom_id)))
#define GDT_IDX_LDT(dom_id) (GDT_NUM_FIXED_DESC + (2 * (dom_id)) + 1)
#else
#define GDT_IDX_LDT(dom_id) (GDT_NUM_FIXED_DESC + (dom_id))
#endif
#endif
#else
#define GDT_IDX_CODE GDT_IDX_CODE_FLAT
#define GDT_IDX_CODE_INT GDT_IDX_CODE_FLAT
#define GDT_IDX_CODE_EXC GDT_IDX_CODE_FLAT
#define GDT_IDX_DATA GDT_IDX_DATA_FLAT
#define GDT_IDX_STK GDT_IDX_DATA_FLAT
#define GDT_IDX_STK_INT GDT_IDX_DATA_FLAT
#define GDT_IDX_STK_EXC GDT_IDX_DATA_FLAT
#endif
#define GDT_SEL(idx, rpl) (((idx) << 3) | (rpl))
#define DT_SEL_GET_IDX(sel) ((sel) >> 3)
#define DT_SEL_GET_RPL(sel) ((sel) & 3)
#define GDT_SEL_NULL GDT_SEL(GDT_IDX_NULL, 0)
#define GDT_SEL_CODE_FLAT GDT_SEL(GDT_IDX_CODE_FLAT, PRIV_LVL_EXC)
#define GDT_SEL_DATA_FLAT GDT_SEL(GDT_IDX_DATA_FLAT, PRIV_LVL_EXC)
#define GDT_SEL_CODE GDT_SEL(GDT_IDX_CODE, PRIV_LVL_USER)
#define GDT_SEL_CODE_INT GDT_SEL(GDT_IDX_CODE_INT, PRIV_LVL_INT)
#define GDT_SEL_CODE_EXC GDT_SEL(GDT_IDX_CODE_EXC, PRIV_LVL_EXC)
#define GDT_SEL_DATA GDT_SEL(GDT_IDX_DATA, PRIV_LVL_EXC)
#define GDT_SEL_DATA_KERN_EXC GDT_SEL(GDT_IDX_DATA_KERN_EXC, PRIV_LVL_EXC)
#define GDT_SEL_STK GDT_SEL(GDT_IDX_STK, PRIV_LVL_USER)
#define GDT_SEL_STK_INT GDT_SEL(GDT_IDX_STK_INT, PRIV_LVL_INT)
#define GDT_SEL_STK_EXC GDT_SEL(GDT_IDX_STK_EXC, PRIV_LVL_EXC)
#define GDT_SEL_TSS(dom_id) GDT_SEL(GDT_IDX_TSS(dom_id), PRIV_LVL_USER)
#define GDT_SEL_LDT(dom_id) GDT_SEL(GDT_IDX_LDT(dom_id), PRIV_LVL_USER)
#endif /* CPU_X86_MM_GDT_LAYOUT_H_ */

View File

@ -1,59 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_LDT_LAYOUT_H_
#define CPU_X86_MM_LDT_LAYOUT_H_
#include "gdt-layout.h"
/* Each LDT can contain up to this many descriptors, but some protection
* domains may not use all of the slots.
*/
#define LDT_NUM_DESC 3
/**
* Provides access to kernel data. Most protection domains are granted at most
* read-only access, but the kernel protection domain is granted read/write
* access.
*/
#define LDT_IDX_KERN 0
/** Maps a device MMIO range */
#define LDT_IDX_MMIO 1
/** Maps domain-defined metadata */
#define LDT_IDX_META 2
#define LDT_SEL(idx, rpl) (GDT_SEL(idx, rpl) | (1 << 2))
#define LDT_SEL_KERN LDT_SEL(LDT_IDX_KERN, PRIV_LVL_USER)
#define LDT_SEL_MMIO LDT_SEL(LDT_IDX_MMIO, PRIV_LVL_USER)
#define LDT_SEL_META LDT_SEL(LDT_IDX_META, PRIV_LVL_USER)
#define LDT_SEL_STK LDT_SEL(LDT_IDX_STK, PRIV_LVL_USER)
#endif /* CPU_X86_MM_LDT_LAYOUT_H_ */

View File

@ -1,248 +0,0 @@
/*
* Copyright (C) 2015, 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 "gdt.h"
#include "helpers.h"
#include "prot-domains.h"
#include "segmentation.h"
#include "stacks.h"
/*---------------------------------------------------------------------------*/
static uint32_t
segment_desc_compute_base(segment_desc_t desc)
{
return (desc.base_hi << 24) | (desc.base_mid << 16) | desc.base_lo;
}
/*---------------------------------------------------------------------------*/
void
prot_domains_reg_multi_seg(volatile struct dom_kern_data ATTR_KERN_ADDR_SPACE *dkd,
uintptr_t mmio, size_t mmio_sz,
uintptr_t meta, size_t meta_sz)
{
segment_desc_t desc;
dom_id_t dom_id = PROT_DOMAINS_GET_DOM_ID(dkd);
uint32_t kern_data_len;
uint32_t tmp;
if((dkd < prot_domains_kern_data) ||
(prot_domains_kern_data_end <= dkd) ||
(((((uintptr_t)dkd) - (uintptr_t)prot_domains_kern_data) %
sizeof(dom_kern_data_t)) != 0)) {
halt();
}
KERN_READL(tmp, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_KERN)].raw_hi);
if(tmp != 0) {
/* This PDCS was previously initialized, which is disallowed. */
halt();
}
/* Initialize descriptors */
if(dom_id == DOM_ID_kern) {
kern_data_len = (uint32_t)&_ebss_kern_addr;
} else {
/* Non-kernel protection domains do not need to access the protection
* domain control structures, and they may contain saved register values
* that are private to each domain.
*/
kern_data_len = (uint32_t)&_ebss_syscall_addr;
}
kern_data_len -= (uint32_t)&_sbss_kern_addr;
segment_desc_init(&desc, (uint32_t)&_sbss_kern_addr, kern_data_len,
/* Every protection domain requires at least read-only access to kernel
data to read dom_client_data structures and to support the system call
dispatcher, if applicable. Only the kernel protection domain is granted
read/write access to the kernel data. */
((dom_id == DOM_ID_kern) ?
SEG_TYPE_DATA_RDWR :
SEG_TYPE_DATA_RDONLY) |
SEG_FLAG(DPL, PRIV_LVL_USER) |
SEG_GRAN_BYTE | SEG_DESCTYPE_NSYS);
KERN_WRITEL(dkd->ldt[LDT_IDX_KERN].raw_lo, desc.raw_lo);
KERN_WRITEL(dkd->ldt[LDT_IDX_KERN].raw_hi, desc.raw_hi);
if(mmio_sz != 0) {
if(SEG_MAX_BYTE_GRAN_LEN < mmio_sz) {
halt();
}
segment_desc_init(&desc, mmio, mmio_sz,
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
} else {
desc.raw = SEG_DESC_NOT_PRESENT;
}
KERN_WRITEL(dkd->ldt[LDT_IDX_MMIO].raw_lo, desc.raw_lo);
KERN_WRITEL(dkd->ldt[LDT_IDX_MMIO].raw_hi, desc.raw_hi);
if(meta_sz != 0) {
if(SEG_MAX_BYTE_GRAN_LEN < meta_sz) {
halt();
}
segment_desc_init(&desc, meta, meta_sz,
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
} else {
desc.raw = SEG_DESC_NOT_PRESENT;
}
KERN_WRITEL(dkd->ldt[LDT_IDX_META].raw_lo, desc.raw_lo);
KERN_WRITEL(dkd->ldt[LDT_IDX_META].raw_hi, desc.raw_hi);
segment_desc_init(&desc,
KERN_DATA_OFF_TO_PHYS_ADDR(dkd->ldt),
sizeof(dkd->ldt),
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
SEG_DESCTYPE_SYS | SEG_TYPE_LDT);
gdt_insert(GDT_IDX_LDT(dom_id), desc);
}
/*---------------------------------------------------------------------------*/
void
prot_domains_gdt_init()
{
int i;
segment_desc_t desc;
segment_desc_init(&desc,
(uint32_t)&_stext_addr,
((uint32_t)&_etext_addr) - (uint32_t)&_stext_addr,
SEG_FLAG(DPL, PRIV_LVL_EXC) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS |
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
/* The general protection fault handler requires read access to CS */
SEG_TYPE_CODE_EXRD
#else
SEG_TYPE_CODE_EX
#endif
);
gdt_insert_boot(GDT_IDX_CODE_EXC, desc);
segment_desc_init(&desc,
(uint32_t)&_sdata_addr,
((uint32_t)&_edata_addr) - (uint32_t)&_sdata_addr,
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
gdt_insert_boot(GDT_IDX_DATA, desc);
segment_desc_init(&desc,
(uint32_t)&_sbss_kern_addr,
((uint32_t)&_ebss_kern_addr) -
(uint32_t)&_sbss_kern_addr,
SEG_FLAG(DPL, PRIV_LVL_EXC) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
gdt_insert_boot(GDT_IDX_DATA_KERN_EXC, desc);
segment_desc_init(&desc,
(uint32_t)DATA_OFF_TO_PHYS_ADDR(stacks_main),
STACKS_SIZE_MAIN,
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_GRAN_BYTE |
SEG_DESCTYPE_NSYS | SEG_TYPE_DATA_RDWR);
gdt_insert_boot(GDT_IDX_STK, desc);
segment_desc_set_limit(&desc, STACKS_SIZE_MAIN + STACKS_SIZE_INT);
SEG_SET_FLAG(desc, DPL, PRIV_LVL_INT);
gdt_insert_boot(GDT_IDX_STK_INT, desc);
segment_desc_set_limit(&desc,
STACKS_SIZE_MAIN +
STACKS_SIZE_INT +
STACKS_SIZE_EXC);
SEG_SET_FLAG(desc, DPL, PRIV_LVL_EXC);
gdt_insert_boot(GDT_IDX_STK_EXC, desc);
/* Not all domains will necessarily be initialized, so this initially marks
* all per-domain descriptors not-present.
*/
desc.raw = SEG_DESC_NOT_PRESENT;
for(i = 0; i < PROT_DOMAINS_ACTUAL_CNT; i++) {
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
gdt_insert_boot(GDT_IDX_TSS(i), desc);
#endif
gdt_insert_boot(GDT_IDX_LDT(i), desc);
}
__asm__ __volatile__ (
"mov %[_default_data_], %%ds\n\t"
"mov %[_default_data_], %%es\n\t"
"mov %[_kern_data_], %%" SEG_KERN "s\n\t"
:
: [_default_data_] "r"(GDT_SEL_DATA),
[_kern_data_] "r"(GDT_SEL_DATA_KERN_EXC));
}
/*---------------------------------------------------------------------------*/
void
multi_segment_launch_kernel(void)
{
/* Update segment registers. */
__asm__ __volatile__ (
"mov %[_data_seg_], %%ds\n\t"
"mov %[_data_seg_], %%es\n\t"
"mov %[_kern_seg_], %%" SEG_KERN "s\n\t"
"mov %[_data_seg_], %%" SEG_META "s\n\t"
:
: [_data_seg_] "r" (GDT_SEL_DATA),
[_kern_seg_] "r" (LDT_SEL_KERN)
);
}
/*---------------------------------------------------------------------------*/
void
prot_domains_enable_mmio(void)
{
__asm__ __volatile__ ("mov %0, %%" SEG_MMIO "s" :: "r" (LDT_SEL_MMIO));
}
/*---------------------------------------------------------------------------*/
void
prot_domains_disable_mmio(void)
{
__asm__ __volatile__ ("mov %0, %%" SEG_KERN "s" :: "r" (LDT_SEL_KERN));
}
/*---------------------------------------------------------------------------*/
uintptr_t
prot_domains_lookup_meta_phys_base(dom_client_data_t ATTR_KERN_ADDR_SPACE *drv)
{
dom_id_t dom_id;
segment_desc_t desc;
volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *dkd;
KERN_READL(dom_id, drv->dom_id);
dkd = prot_domains_kern_data + dom_id;
KERN_READL(desc.raw_lo, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_META)].raw_lo);
KERN_READL(desc.raw_hi, dkd->ldt[DT_SEL_GET_IDX(LDT_SEL_META)].raw_hi);
return segment_desc_compute_base(desc);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,195 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_MULTI_SEGMENT_H_
#define CPU_X86_MM_MULTI_SEGMENT_H_
#include <stdint.h>
#include <stdlib.h>
#include "helpers.h"
#include "ldt-layout.h"
#ifdef __clang__
#define __SEG_FS
#define __seg_fs __attribute__((address_space(257)))
#define __SEG_GS
#define __seg_gs __attribute__((address_space(256)))
#endif
#ifdef __SEG_FS
#define ATTR_MMIO_ADDR_SPACE __seg_fs
#define ATTR_KERN_ADDR_SPACE __seg_fs
#else
#define ATTR_KERN_ADDR_SPACE
#endif
#ifdef __SEG_GS
#define ATTR_META_ADDR_SPACE __seg_gs
#endif
void prot_domains_reg_multi_seg(volatile struct dom_kern_data ATTR_KERN_ADDR_SPACE *dkd,
uintptr_t mmio, size_t mmio_sz,
uintptr_t meta, size_t meta_sz);
void multi_segment_launch_kernel(void);
#define MULTI_SEGMENT_ENTER_ISR(exc) \
"mov $" EXP_STRINGIFY(GDT_SEL_DATA) ", %%eax\n\t" \
/* Refresh DS and ES in case the userspace code corrupted them. */ \
"mov %%eax, %%ds\n\t" \
"mov %%eax, %%es\n\t" \
/* Refresh SEG_KERN. */ \
"mov $" EXP_STRINGIFY(LDT_SEL_KERN) ", %%eax\n\t" \
"mov %%eax, %%" SEG_KERN "s\n\t" \
".if " #exc "\n\t" \
/* It is possible that a routine performing MMIO is being interrupted. */ \
/* Thus, it is necessary to save and restore the MMIO segment register */ \
/* (in a callee-saved register). */ \
"mov %%" SEG_MMIO "s, %%ebp\n\t" \
"mov $" EXP_STRINGIFY(GDT_SEL_DATA_KERN_EXC) ", %%eax\n\t" \
"mov %%eax, %%" SEG_KERN "s\n\t" \
".endif\n\t"
#define MULTI_SEGMENT_LEAVE_ISR(exc) \
".if " #exc "\n\t" \
"mov %%ebp, %%" SEG_MMIO "s\n\t" \
".endif\n\t"
/**
* The MMIO region is tightly bounded within a segment, so its base offset is
* always 0.
*/
#define PROT_DOMAINS_MMIO(dcd) 0
/**
* The metadata region is tightly bounded within a segment, so its base offset
* is always 0.
*/
#define PROT_DOMAINS_META(dcd) 0
#define SEG_MMIO "f" /**< For MMIO accesses, when enabled. */
#define SEG_KERN "f" /**< For kernel data accesses */
#define SEG_META "g" /**< For metadata accesses */
#define _SEG_READL(seg, dst, src) \
__asm__ __volatile__ ( \
"movl %%" seg "s:%[src_], %[dst_]" : [dst_]"=r"(dst) : [src_]"m"(src))
#define _SEG_READW(seg, dst, src) \
__asm__ __volatile__ ( \
"movw %%" seg "s:%[src_], %[dst_]" : [dst_]"=r"(dst) : [src_]"m"(src))
#define _SEG_READB(seg, dst, src) \
__asm__ __volatile__ ( \
"movb %%" seg "s:%[src_], %[dst_]" : [dst_]"=q"(dst) : [src_]"m"(src))
#define _SEG_WRITEL(seg, dst, src) \
__asm__ __volatile__ ( \
"movl %[src_], %%" seg "s:%[dst_]" \
: [dst_]"=m"(dst) : [src_]"r"((uint32_t)(src)))
#define _SEG_WRITEW(seg, dst, src) \
__asm__ __volatile__ ( \
"movw %[src_], %%" seg "s:%[dst_]" \
: [dst_]"=m"(dst) : [src_]"r"((uint16_t)(src)))
#define _SEG_WRITEB(seg, dst, src) \
__asm__ __volatile__ ( \
"movb %[src_], %%" seg "s:%[dst_]" \
: [dst_]"=m"(dst) : [src_]"q"((uint8_t)(src)))
#ifndef __SEG_FS
#define MMIO_READL(dst, src) _SEG_READL(SEG_MMIO, dst, src)
#define MMIO_READW(dst, src) _SEG_READW(SEG_MMIO, dst, src)
#define MMIO_READB(dst, src) _SEG_READB(SEG_MMIO, dst, src)
#define MMIO_WRITEL(dst, src) _SEG_WRITEL(SEG_MMIO, dst, src)
#define MMIO_WRITEW(dst, src) _SEG_WRITEW(SEG_MMIO, dst, src)
#define MMIO_WRITEB(dst, src) _SEG_WRITEB(SEG_MMIO, dst, src)
#define KERN_READL(dst, src) _SEG_READL(SEG_KERN, dst, src)
#define KERN_READW(dst, src) _SEG_READW(SEG_KERN, dst, src)
#define KERN_READB(dst, src) _SEG_READB(SEG_KERN, dst, src)
#define KERN_WRITEL(dst, src) _SEG_WRITEL(SEG_KERN, dst, src)
#define KERN_WRITEW(dst, src) _SEG_WRITEW(SEG_KERN, dst, src)
#define KERN_WRITEB(dst, src) _SEG_WRITEB(SEG_KERN, dst, src)
#endif
#ifndef __SEG_GS
#define META_READL(dst, src) _SEG_READL(SEG_META, dst, src)
#define META_READW(dst, src) _SEG_READW(SEG_META, dst, src)
#define META_READB(dst, src) _SEG_READB(SEG_META, dst, src)
#define META_WRITEL(dst, src) _SEG_WRITEL(SEG_META, dst, src)
#define META_WRITEW(dst, src) _SEG_WRITEW(SEG_META, dst, src)
#define META_WRITEB(dst, src) _SEG_WRITEB(SEG_META, dst, src)
#endif
#define MEMCPY_FROM_META(dst, src, sz) \
{ \
uintptr_t __dst = (uintptr_t)(dst); \
uintptr_t __src = (uintptr_t)(src); \
size_t __sz = (size_t)(sz); \
__asm__ __volatile__ ( \
"rep movsb %%" SEG_META "s:(%%esi), %%es:(%%edi)\n\t" \
: "+D"(__dst), "+S"(__src), "+c"(__sz)); \
}
#define MEMCPY_TO_META(dst, src, sz) \
{ \
uintptr_t __dst = (uintptr_t)(dst); \
uintptr_t __src = (uintptr_t)(src); \
size_t __sz = (size_t)(sz); \
__asm__ __volatile__ ( \
"push %%es\n\t" \
"push %%" SEG_META "s\n\t" \
"pop %%es\n\t" \
"rep movsb\n\t" \
"pop %%es\n\t" \
: "+D"(__dst), "+S"(__src), "+c"(__sz)); \
}
/** Compute physical address from offset into kernel data space */
#define KERN_DATA_OFF_TO_PHYS_ADDR(x) \
(((uintptr_t)&_sbss_kern_addr) + (uintptr_t)(x))
/** Compute physical address from offset into default data space */
#define DATA_OFF_TO_PHYS_ADDR(x) \
(((uintptr_t)&_sdata_addr) + (uintptr_t)(x))
/** Compute kernel data offset from physical address in kernel data space */
#define PHYS_ADDR_TO_KERN_DATA_OFF(x) \
(((uintptr_t)(x)) - (uintptr_t)&_sbss_kern_addr)
/**
* In multi-segment protection domain implementations, it is sufficient to just
* compare incoming pointers against the frame pointer. All incoming pointers
* are dereferenced in the main data segment, which only maps the stacks and
* the shared data section. Since the shared data section is at a higher
* address range than the stacks, the frame pointer check is sufficient.
*/
#define PROT_DOMAINS_CHECK_INCOMING_PTR PROT_DOMAINS_CHECK_INCOMING_PTR_EBP
void prot_domains_enable_mmio(void);
void prot_domains_disable_mmio(void);
#endif /* CPU_X86_MM_MULTI_SEGMENT_H_ */

View File

@ -1,297 +0,0 @@
/*
* Copyright (C) 2015, 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 <string.h>
#include "dma.h"
#include "gdt.h"
#include "gdt-layout.h"
#include "helpers.h"
#include "idt.h"
#include "paging.h"
#include "prot-domains.h"
#include "segmentation.h"
#include "stacks.h"
#include "syscalls.h"
#include "tss.h"
/*#define DBG_PAGE_ALLOC*/
/* Enable PAE-mode paging */
#define CR4_PAE BIT(5)
/* Extended Feature Enables MSR */
#define MSR_EFER 0xC0000080
/* Enable Execute Disable bit support */
#define EFER_NXE BIT(11)
/* Root page-directory-pointer table */
static pdpt_t root_pgtbl __attribute__((aligned(32))) ATTR_BSS_KERN;
/* Although the following page tables must be page-aligned, it is infeasible to
* apply the "aligned(4096)" attribute for the reasons described in the linker
* script.
*/
/* Second-level page directory */
static page_table_t
second_lvl_pgtbl ATTR_BSS_KERN_PAGE_ALIGNED;
/* Leaf-level page table */
static page_table_t leaf_pgtbl ATTR_BSS_KERN_PAGE_ALIGNED;
#define LINEAR_ADDR_BOUND (MIN_PAGE_SIZE * ENTRIES_PER_PAGE_TABLE)
/*---------------------------------------------------------------------------*/
void
prot_domains_reg(dom_client_data_t *dcd,
uintptr_t mmio,
size_t mmio_sz,
uintptr_t meta,
size_t meta_sz,
bool pio)
{
dom_id_t dom_id = dcd->dom_id;
volatile struct dom_kern_data *dkd =
prot_domains_kern_data + dom_id;
/* All addresses and sizes must be page-aligned */
if((PROT_DOMAINS_ACTUAL_CNT <= dom_id) ||
((mmio & (MIN_PAGE_SIZE - 1)) != 0) ||
((mmio_sz & (MIN_PAGE_SIZE - 1)) != 0) ||
((meta & (MIN_PAGE_SIZE - 1)) != 0) ||
((meta_sz & (MIN_PAGE_SIZE - 1)) != 0) ||
(PROT_DOMAINS_MAX_MMIO_SZ < mmio_sz) ||
(LINEAR_ADDR_BOUND < (PROT_DOMAINS_META_LINEAR_BASE + meta_sz))) {
halt();
}
if((dkd->flags & PROT_DOMAINS_FLAG_INITED) == PROT_DOMAINS_FLAG_INITED) {
halt();
}
dkd->mmio = mmio;
dkd->mmio_sz = mmio_sz;
dkd->meta = meta;
dkd->meta_sz = meta_sz;
dkd->flags = PROT_DOMAINS_FLAG_INITED;
if(pio) {
dkd->flags |= PROT_DOMAINS_FLAG_PIO;
}
}
/*---------------------------------------------------------------------------*/
static void __attribute__((regparm(3)))
set_ptes(uintptr_t start_la, uintptr_t start_pa, uintptr_t end_pa,
pte_t template)
{
#ifdef DBG_PAGE_ALLOC
#warning Checking page allocations at runtime.
if(((start_la & (MIN_PAGE_SIZE - 1)) != 0) ||
((start_pa & (MIN_PAGE_SIZE - 1)) != 0) ||
((start_la & (MIN_PAGE_SIZE - 1)) != 0) ||
((end_pa & (MIN_PAGE_SIZE - 1)) != 0) ||
(LINEAR_ADDR_BOUND <= (start_la + (end_pa - start_pa)))) {
halt();
}
#endif
while(start_pa < end_pa) {
template.addr = start_pa >> 12;
leaf_pgtbl[start_la >> MIN_PAGE_SIZE_SHAMT] = template;
#ifdef X86_CONF_USE_INVLPG
__asm__("invlpg %0" :: "m" (*(uint8_t *)start_la));
#endif
start_la += MIN_PAGE_SIZE;
start_pa += MIN_PAGE_SIZE;
}
}
/*---------------------------------------------------------------------------*/
static void __attribute__((fastcall))
set_ptes_identity_map(uintptr_t start_pa, uintptr_t end_pa, pte_t template)
{
set_ptes(start_pa, start_pa, end_pa, template);
}
/*---------------------------------------------------------------------------*/
static inline uint32_t __attribute__((always_inline))
prot_domains_switch(dom_id_t from_id, dom_id_t to_id,
interrupt_stack_t *intr_stk)
{
volatile dom_kern_data_t *from, *to;
from = prot_domains_kern_data + from_id;
to = prot_domains_kern_data + to_id;
if((from_id == DOM_ID_kern) ||
(to_id == DOM_ID_kern)) {
pte_t to_kern_data_pte = { .raw = 0 };
to_kern_data_pte.present = 1;
to_kern_data_pte.exec_disable = 1;
/* The kernel data region should always be accessible to supervisory code,
* but it is only accessible to user mode in the kernel protection domain.
*/
to_kern_data_pte.user_accessible = 1;
if(to_id == DOM_ID_kern) {
to_kern_data_pte.writable = 1;
}
set_ptes_identity_map((uintptr_t)&_sbss_kern_addr,
(uintptr_t)&_ebss_syscall_addr,
to_kern_data_pte);
if(to_id != DOM_ID_kern) {
to_kern_data_pte.user_accessible = 0;
to_kern_data_pte.writable = 0;
}
set_ptes_identity_map((uintptr_t)&_ebss_syscall_addr,
(uintptr_t)&_ebss_kern_addr,
to_kern_data_pte);
}
if(to->mmio_sz != 0) {
pte_t pte = { .raw = 0 };
pte.present = 1;
pte.exec_disable = 1;
pte.user_accessible = 1;
pte.writable = 1;
/* disable caching of MMIO accesses */
pte.pcd = 1;
set_ptes(PROT_DOMAINS_MMIO_LINEAR_BASE,
to->mmio,
to->mmio + to->mmio_sz,
pte);
}
if(to->mmio_sz < from->mmio_sz) {
pte_t pte = { .raw = 0 };
set_ptes_identity_map(PROT_DOMAINS_MMIO_LINEAR_BASE + to->mmio_sz,
PROT_DOMAINS_MMIO_LINEAR_BASE + from->mmio_sz,
pte);
}
if(to->meta_sz != 0) {
pte_t pte = { .raw = 0 };
pte.present = 1;
pte.exec_disable = 1;
pte.user_accessible = 1;
pte.writable = 1;
set_ptes(PROT_DOMAINS_META_LINEAR_BASE,
to->meta,
to->meta + to->meta_sz,
pte);
}
if(to->meta_sz < from->meta_sz) {
pte_t pte = { .raw = 0 };
set_ptes_identity_map(PROT_DOMAINS_META_LINEAR_BASE + to->mmio_sz,
PROT_DOMAINS_META_LINEAR_BASE + from->mmio_sz,
pte);
}
#ifndef X86_CONF_USE_INVLPG
__asm__ __volatile__ ("mov %%cr3, %%eax\n\t"
"mov %%eax, %%cr3\n\t" ::: "eax");
#endif
return 0;
}
/*---------------------------------------------------------------------------*/
void
prot_domains_gdt_init(void)
{
gdt_copy_desc_change_dpl(GDT_IDX_DATA, GDT_IDX_DATA_FLAT, PRIV_LVL_USER);
gdt_copy_desc_change_dpl(GDT_IDX_STK_INT, GDT_IDX_STK_EXC, PRIV_LVL_INT);
}
/*---------------------------------------------------------------------------*/
void
prot_domains_impl_init(void)
{
pte_t pte = { .raw = 0 };
syscalls_int_init();
/* Initialize page table: */
pte.present = 1;
pte.addr = ((uint32_t)second_lvl_pgtbl) >> MIN_PAGE_SIZE_SHAMT;
root_pgtbl[0] = pte;
pte.writable = 1;
pte.user_accessible = 1;
pte.addr = ((uint32_t)leaf_pgtbl) >> MIN_PAGE_SIZE_SHAMT;
second_lvl_pgtbl[0] = pte;
/* Map code sections: */
pte.writable = 0;
set_ptes_identity_map((uintptr_t)&_stext_addr, (uintptr_t)&_etext_addr, pte);
/* Map data sections: */
pte.writable = 1;
pte.exec_disable = 1;
set_ptes_identity_map((uintptr_t)stacks_main,
(uintptr_t)stacks_main +
STACKS_SIZE_MAIN +
STACKS_SIZE_EXC +
STACKS_SIZE_INT,
pte);
set_ptes_identity_map((uintptr_t)&_sdata_addr, (uintptr_t)&_edata_addr, pte);
/* Enable XD bit support */
__asm__ __volatile__ ("wrmsr" :: "c" (MSR_EFER), "a" (EFER_NXE), "d" (0));
/* Enable PAE */
__asm__ __volatile__ ("mov %%cr4, %%eax\n\t"
"or %0, %%eax\n\t"
"mov %%eax, %%cr4\n\t"
:
: "r" (CR4_PAE)
: "eax");
/* Load CR3 */
__asm__ __volatile__ ("mov %0, %%cr3" :: "r" (root_pgtbl));
}
/*---------------------------------------------------------------------------*/
uintptr_t
prot_domains_lookup_meta_phys_base(dom_client_data_t *drv)
{
return prot_domains_kern_data[drv->dom_id].meta;
}
/*---------------------------------------------------------------------------*/
/* Enable inter-procedural optimization with procedures in the following file:
*/
#include "syscalls-int.c"

View File

@ -1,114 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_PAGING_PROT_DOMAINS_H_
#define CPU_X86_MM_PAGING_PROT_DOMAINS_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "dma.h"
#include "helpers.h"
#include "paging.h"
#include "syscalls-int.h"
struct dom_kern_data {
/** Base physical address of optional MMIO region */
uintptr_t mmio;
/** Number of (contiguous) pages in MMIO region */
size_t mmio_sz;
/** Base physical address of optional metadata region */
uintptr_t meta;
/** Number of (contiguous) pages in metadata region */
size_t meta_sz;
/** Flags are defined with the prefix PROT_DOMAINS_FLAG in prot-domains.h */
uint32_t flags;
/**
* Original return address from call stack when this protection domain
* invoked some other protection domain. This serves to control the return
* entrypoint. The callee is not permitted to modify this value (unless the
* callee is the kernel protection domain).
*/
uintptr_t orig_ret_addr;
/* align to next-larger power of 2 to enable usage of shifting instead of
* multiplication to index an array of these structures.
*/
} __attribute__((aligned(32)));
/** Linear base address at which to map the MMIO region. */
#define PROT_DOMAINS_MMIO_LINEAR_BASE (MIN_PAGE_SIZE + (uintptr_t)&_ebss_kern_addr)
/** Maximum supported size of MMIO region */
#define PROT_DOMAINS_MAX_MMIO_SZ 0x4000
/** Linear base address at which to map the metadata region */
#define PROT_DOMAINS_META_LINEAR_BASE \
(MIN_PAGE_SIZE + (PROT_DOMAINS_MMIO_LINEAR_BASE + PROT_DOMAINS_MAX_MMIO_SZ))
#define PROT_DOMAINS_META_OFF_TO_PHYS(off, meta_phys_base) \
((meta_phys_base) + ((off) - PROT_DOMAINS_META_LINEAR_BASE))
/** Any MMIO region mapping always starts at a particular linear address. */
#define PROT_DOMAINS_MMIO(dcd) PROT_DOMAINS_MMIO_LINEAR_BASE
/**
* Any metadata region mapping always starts at a particular linear address.
*/
#define PROT_DOMAINS_META(dcd) PROT_DOMAINS_META_LINEAR_BASE
#define PROT_DOMAINS_ENTER_ISR(exc) \
PROT_DOMAINS_ENTER_ISR_COMMON(exc)
#define PROT_DOMAINS_LEAVE_ISR(exc) PROT_DOMAINS_LEAVE_ISR_COMMON(exc)
/* Enable paging */
#define CR0_PG BIT(31)
/* Enable write protection in supervisor mode */
#define CR0_WP BIT(16)
/* Enable protected mode */
#define CR0_PE BIT(0)
/**
* \brief Enable or disable write protection enforcement in supervisor mode.
* When disabled, supervisory code (i.e. code running at ring levels
* 0-2) is permitted to write to pages that are marked read-only in
* page tables.
*
* \param en Set to true to enable write protection enforcement.
*/
static inline void prot_domains_set_wp(bool en)
{
uint32_t cr0_val = CR0_PG | CR0_PE;
if(en) {
cr0_val |= CR0_WP;
}
__asm__ __volatile__ ("mov %0, %%cr0" :: "r"(cr0_val));
}
#endif /* CPU_X86_MM_PAGING_PROT_DOMAINS_H_ */

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_PAGING_H_
#define CPU_X86_MM_PAGING_H_
#include <stdint.h>
/**
* Page table entry format for PAE mode page table. See Intel Combined Manual,
* Vol. 3, Section 4.4 for more details.
*/
typedef union pte {
struct {
uint64_t present : 1;
uint64_t writable : 1;
uint64_t user_accessible : 1;
uint64_t pwt : 1; /**< Specify write-through cache policy */
uint64_t pcd : 1; /**< Disable caching */
uint64_t accessed : 1;
uint64_t dirty : 1;
uint64_t : 5;
uint64_t addr : 51;
uint64_t exec_disable : 1;
};
uint64_t raw;
} pte_t;
#define ENTRIES_PER_PDPT 4
#define ENTRIES_PER_PAGE_TABLE 512
typedef pte_t pdpt_t[ENTRIES_PER_PDPT];
typedef pte_t page_table_t[ENTRIES_PER_PAGE_TABLE];
#define MIN_PAGE_SIZE_SHAMT 12
#define MIN_PAGE_SIZE (1 << MIN_PAGE_SIZE_SHAMT)
#endif /* CPU_X86_MM_PAGING_H_ */

View File

@ -1,78 +0,0 @@
/*
* Copyright (C) 2015, 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 "prot-domains.h"
#include "gdt.h"
#include <stdio.h>
#include "interrupt.h"
#include <stdint.h>
#include <assert.h>
#include "syscalls.h"
#include "stacks.h"
static dom_kern_data_t __attribute__((section(".kern_prot_dom_bss")))
ATTR_KERN_ADDR_SPACE PROT_DOMAINS_PDCS_NM(kern_dcd);
PROT_DOMAINS_ALLOC_IMPL(kern_dcd);
static dom_client_data_t ATTR_BSS_KERN kern_dcd;
static dom_kern_data_t __attribute__((section(".app_prot_dom_bss")))
ATTR_KERN_ADDR_SPACE PROT_DOMAINS_PDCS_NM(app_dcd);
PROT_DOMAINS_ALLOC_IMPL(app_dcd);
static dom_client_data_t ATTR_BSS_KERN app_dcd;
/*---------------------------------------------------------------------------*/
void
prot_domains_init(void)
{
segment_desc_t desc;
gdt_lookup(GDT_IDX_CODE_EXC, &desc);
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
/* The exception code segment needs to be readable so that the general
* protection fault handler can decode instructions, but the interrupt and
* user level code segments should not be.
*/
SEG_SET_FLAG(desc, TYPE, SEG_TYPE_CODE_EX);
#endif
SEG_SET_FLAG(desc, DPL, PRIV_LVL_INT);
gdt_insert(GDT_IDX_CODE_INT, desc);
SEG_SET_FLAG(desc, DPL, PRIV_LVL_USER);
gdt_insert(GDT_IDX_CODE, desc);
PROT_DOMAINS_INIT_ID(kern_dcd);
prot_domains_reg(&kern_dcd, 0, 0, 0, 0, true);
PROT_DOMAINS_INIT_ID(app_dcd);
prot_domains_reg(&app_dcd, 0, 0, 0, 0, false);
prot_domains_impl_init();
}
/*---------------------------------------------------------------------------*/

View File

@ -1,376 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_PROT_DOMAINS_H_
#define CPU_X86_MM_PROT_DOMAINS_H_
#if !__ASSEMBLER__
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "helpers.h"
#endif
#define X86_CONF_PROT_DOMAINS__NONE 0
#define X86_CONF_PROT_DOMAINS__PAGING 1
#define X86_CONF_PROT_DOMAINS__TSS 2
#define X86_CONF_PROT_DOMAINS__SWSEG 3
#define X86_CONF_PROT_DOMAINS_MULTI_SEG \
((X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS) || \
(X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG))
/** Privilege level (ring) for exception handlers and other supervisory code */
#define PRIV_LVL_EXC 0
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
/** Privilege level for interrupt handlers */
#define PRIV_LVL_INT 2
/** Default privilege level */
#define PRIV_LVL_USER 3
#else
#define PRIV_LVL_INT PRIV_LVL_EXC
#define PRIV_LVL_USER PRIV_LVL_EXC
#endif
#define DOM_ID_kern 0
#define DOM_ID_app 1
/** I/O Privilege Level */
#define EFLAGS_IOPL(pl) ((pl) << 12)
/** Interrupt Enable Flag */
#define EFLAGS_IF (1u << 9)
#if !__ASSEMBLER__
/** Protection domain ID */
typedef uint32_t dom_id_t;
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
#include "paging-prot-domains.h"
#elif X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
#include "tss-prot-domains.h"
#elif X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
#include "swseg-prot-domains.h"
#endif
#ifndef ATTR_META_ADDR_SPACE
#define ATTR_META_ADDR_SPACE
#endif
#ifndef ATTR_MMIO_ADDR_SPACE
#define ATTR_MMIO_ADDR_SPACE
#endif
#ifndef ATTR_KERN_ADDR_SPACE
#define ATTR_KERN_ADDR_SPACE
#endif
#ifndef MMIO_READL
#define MMIO_READL(dst, src) dst = (src)
#define MMIO_READW(dst, src) dst = (src)
#define MMIO_READB(dst, src) dst = (src)
#define MMIO_WRITEL(dst, src) MMIO_READL(dst, src)
#define MMIO_WRITEW(dst, src) MMIO_READW(dst, src)
#define MMIO_WRITEB(dst, src) MMIO_READB(dst, src)
#endif
#ifndef KERN_READL
#define KERN_READL(dst, src) dst = (src)
#define KERN_READW(dst, src) dst = (src)
#define KERN_READB(dst, src) dst = (src)
#define KERN_WRITEL(dst, src) KERN_READL(dst, src)
#define KERN_WRITEW(dst, src) KERN_READW(dst, src)
#define KERN_WRITEB(dst, src) KERN_READB(dst, src)
#endif
#ifndef META_READL
#define META_READL(dst, src) dst = (src)
#define META_READW(dst, src) dst = (src)
#define META_READB(dst, src) dst = (src)
#define META_WRITEL(dst, src) META_READL(dst, src)
#define META_WRITEW(dst, src) META_READw(dst, src)
#define META_WRITEB(dst, src) META_READB(dst, src)
#endif
#ifndef MEMCPY_FROM_META
#define MEMCPY_FROM_META(dst, src, sz) \
memcpy((void *)(dst), (const void *)(src), (sz))
#define MEMCPY_TO_META(dst, src, sz) MEMCPY_FROM_META(dst, src, sz)
#endif
/* The following symbols are defined in the linker script */
/** Bounds for .text section */
extern uint32_t _stext_addr, _etext_addr;
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
/** Metadata that should not be DMA-accessible */
#define ATTR_BSS_META __attribute__((section(".meta_bss"))) ATTR_META_ADDR_SPACE
/** Kernel-owned data */
#define ATTR_BSS_KERN __attribute__((section(".kern_bss"))) ATTR_KERN_ADDR_SPACE
/** Code that should only be executable during bootup */
#define ATTR_CODE_BOOT __attribute__((section(".boot_text")))
/**
* Domain-defined metadata must be page-aligned, which is implemented by the
* linker script for variables with this attribute.
*/
#define ATTR_BSS_KERN_PAGE_ALIGNED \
__attribute__((section(".page_aligned_kern_bss")))
/** Bounds for .kern_data, .syscall_data, and .prot_dom_data sections */
extern uint32_t _sbss_kern_addr, _ebss_kern_addr;
/** End of .syscall_data section */
extern uint32_t _ebss_syscall_addr;
/** Bounds for other data sections */
extern uint32_t _sdata_addr, _edata_addr;
#ifndef SEG_KERN
#define SEG_KERN "d"
#endif
/**
* If set, this protection domain is already in the call stack and is not
* available for nested invocations.
*/
#define PROT_DOMAINS_FLAG_BUSY BIT(0)
/** If set, this protection domain requires port I/O access. */
#define PROT_DOMAINS_FLAG_PIO BIT(1)
/** If set, this protection domain is initialized. */
#define PROT_DOMAINS_FLAG_INITED BIT(2)
/**
* Data associated with each protection domain that should be fully accessible
* only to the kernel, with limited accesses and modifications permitted from
* other domains. Includes storage for system data structures.
*/
typedef struct dom_kern_data dom_kern_data_t;
extern volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE prot_domains_kern_data[];
extern volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE prot_domains_kern_data_end[];
#define PROT_DOMAINS_ACTUAL_CNT \
(prot_domains_kern_data_end - prot_domains_kern_data)
#define PROT_DOMAINS_GET_DOM_ID(dkd) \
((dom_id_t)((dkd) - prot_domains_kern_data))
void prot_domains_syscall_dispatcher(void);
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__TSS
/**
* Data associated with each protection domain that is owned by clients of that
* domain and used to identify the domain.
*/
struct dom_client_data {
dom_id_t dom_id;
} __attribute__((packed));
#endif
#ifndef PROT_DOMAINS_ALLOC_IMPL
#define PROT_DOMAINS_ALLOC_IMPL(nm)
#endif
/** Allocate the client-owned protection domain data structure. */
#define PROT_DOMAINS_PDCS_NM(nm) _pdcs_##nm
#define PROT_DOMAINS_ALLOC(typ, nm) \
static dom_kern_data_t __attribute__((section(".prot_dom_bss"))) \
ATTR_KERN_ADDR_SPACE PROT_DOMAINS_PDCS_NM(nm); \
PROT_DOMAINS_ALLOC_IMPL(nm); \
static typ ATTR_BSS_KERN nm
#define PROT_DOMAINS_INIT_ID(nm) \
KERN_WRITEL((nm).dom_id, PROT_DOMAINS_GET_DOM_ID(&PROT_DOMAINS_PDCS_NM(nm)))
/**
* Perform early initialization during boot stage 0 to prepare for boot stage 1
*/
void prot_domains_gdt_init() ATTR_CODE_BOOT;
/**
* Perform initialization during boot stage 1 to prepare for kernel launch
*/
void prot_domains_init();
void prot_domains_impl_init();
/* Return from cpu_boot_stage1 will invoke prot_domains_launch_kernel due to
* that return address being pushed on the stack by cpu_boot_stage0.
*/
#define prot_domains_leave_boot_stage1()
/* Return from main will invoke prot_domains_launch_app due to that return
* address being pushed on the stack by cpu_boot_stage0.
*/
#define prot_domains_leave_main()
void prot_domains_launch_kernel(void);
/* Whenever changing this, update syscalls-int-asm.S:prot_domains_launch_kernel
* to match:
*/
#define PROT_DOMAINS_INIT_RET_ADDR_CNT 2
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
void prot_domains_launch_app(void);
#else
void app_main(void);
#define prot_domains_launch_app app_main
#endif
#else
#define ATTR_BSS_META
#define ATTR_BSS_KERN
#define ATTR_CODE_BOOT
struct dom_client_data {
uintptr_t mmio; /**< MMIO range base address */
uintptr_t meta; /**< Domain-defined metadata base address */
};
/** Retrieve the MMIO base address for the specified protection domain. */
#define PROT_DOMAINS_MMIO(dcd) ((dcd).mmio)
/** Retrieve the metadata base address for the specified protection domain. */
#define PROT_DOMAINS_META(dcd) ((dcd).meta)
#define PROT_DOMAINS_ALLOC(typ, nm) static typ nm
#define PROT_DOMAINS_INIT_ID(nm)
#define prot_domains_gdt_init()
#define prot_domains_init()
int main(void);
#define prot_domains_leave_boot_stage1 main
#define prot_domains_leave_main ENABLE_IRQ(); app_main
#define PROT_DOMAINS_INIT_RET_ADDR_CNT 0
#endif
/**
* Protection domain data readable by the client. It is used to control
* execution, so it should be protected from modifications by clients.
* Otherwise, there is a risk that one client could modify one of these
* structures used by another client to issue a system call, which could then
* cause the latter client to perform an unintended system call.
*/
typedef struct dom_client_data dom_client_data_t;
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define prot_domains_reg(dcd, mmio_, mmio_sz, meta_, meta_sz, pio) \
(dcd)->mmio = (mmio_); \
(dcd)->meta = (meta_)
#else
/**
* \brief Register a protection domain, which involves creating the
* necessary system data structures for it.
*
* \param dcd Client-accessible domain information
* \param mmio Optional base address for per-domain memory-mapped IO region
* \param mmio_sz Size of MMIO region
* \param meta Optional base address for per-domain metadata
* \param meta_sz Size of metadata
* \param pio Set to true if protection domain requires port IO access
*/
void prot_domains_reg(dom_client_data_t ATTR_KERN_ADDR_SPACE *dcd,
uintptr_t mmio,
size_t mmio_sz,
uintptr_t meta,
size_t meta_sz,
bool pio);
#endif
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define prot_domains_copy_dcd(dst, src) *(dst) = *(src)
#else
static inline void
/**
* It is necessary to make a local copy of a dom_client_data structure when a
* multi-segment protection domain implementation is in use, segment attributes
* are not supported by the compiler, and a dom_client_data structure needs to
* be passed by value into some function. Otherwise, the compiler will not know
* to access the non-default segment in which *src is stored and will attempt
* to copy it out of the default data segment.
*/
prot_domains_copy_dcd(struct dom_client_data *dst,
struct dom_client_data ATTR_KERN_ADDR_SPACE *src)
{
KERN_READL(dst->dom_id, src->dom_id);
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
KERN_READL(dst->tss_sel, src->tss_sel);
#endif
}
#endif
#if !X86_CONF_PROT_DOMAINS_MULTI_SEG
#define prot_domains_enable_mmio()
#define prot_domains_disable_mmio()
#define KERN_DATA_OFF_TO_PHYS_ADDR(x) ((uintptr_t)(x))
#define DATA_OFF_TO_PHYS_ADDR(x) ((uintptr_t)(x))
#endif
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define prot_domains_lookup_meta_phys_base(drv) 0
#else
/** Lookup base physical address of metadata region for specified domain */
uintptr_t prot_domains_lookup_meta_phys_base(dom_client_data_t ATTR_KERN_ADDR_SPACE *drv);
#endif
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__PAGING
#define PROT_DOMAINS_META_OFF_TO_PHYS(off, meta_phys_base) \
((meta_phys_base) + (off))
#endif
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define PROT_DOMAINS_ENTER_ISR(...)
#define PROT_DOMAINS_LEAVE_ISR(...)
#else
#define PROT_DOMAINS_ENTER_ISR_COMMON(exc) \
".if !" #exc "\n\t" \
/* Save the current stack pointer into a callee-saved register. */ \
"mov %%esp, %%ebx\n\t" \
/* Pivot to the main stack of the interrupted context. */ \
/* Interrupts never have an error code, so the offset is always 44. */ \
/* No interrupt handlers use anything from the original interrupt stack, */ \
/* so there is no need to copy anything from it to the main stack. */ \
"mov 44(%%esp), %%esp\n\t" \
".endif\n\t"
#define PROT_DOMAINS_LEAVE_ISR_COMMON(exc) \
/* Restore the interrupt/exception stack pointer. */ \
".if !" #exc "\n\t" \
"mov %%ebx, %%esp\n\t" \
".endif\n\t"
#endif
#ifdef X86_CONF_PROT_DOMAINS_MULTI_SEG
/* include GDT section definitions used when allocating protection domains: */
#include "gdt.h"
#endif
#endif /* !__ASSEMBLER__ */
#endif /* CPU_X86_MM_PROT_DOMAINS_H_ */

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_SEGMENTATION_H_
#define CPU_X86_MM_SEGMENTATION_H_
#include <stdint.h>
#define SEG_FLAG(lbl, val) \
(((val) & (~0u >> (32 - SEG_WIDTH_##lbl))) << SEG_SHAMT_##lbl)
#define SEG_SET_FLAG(desc, lbl, val) \
(desc).flags = ((desc).flags & ~SEG_FLAG(lbl, ~0u)) | SEG_FLAG(lbl, val)
#define SEG_WIDTH_TYPE 4
#define SEG_SHAMT_TYPE 0
#define SEG_WIDTH_DESCTYPE 1
#define SEG_SHAMT_DESCTYPE 4
#define SEG_WIDTH_DPL 2
#define SEG_SHAMT_DPL 5
#define SEG_WIDTH_PRESENT 1
#define SEG_SHAMT_PRESENT 7
#define SEG_WIDTH_LIMIT_HI 4
#define SEG_SHAMT_LIMIT_HI 8
#define SEG_WIDTH_AVL 1
#define SEG_SHAMT_AVL 12
#define SEG_WIDTH_LONG_MODE 1
#define SEG_SHAMT_LONG_MODE 13
/* also used to indicate default operand and address size */
#define SEG_WIDTH_DIRECTION 1
#define SEG_SHAMT_DIRECTION 14
#define SEG_WIDTH_GRAN 1
#define SEG_SHAMT_GRAN 15
#define SEG_TYPE_DATA_RDONLY SEG_FLAG(TYPE, 0x00) /* Read only */
#define SEG_TYPE_DATA_RDWR SEG_FLAG(TYPE, 0x02) /* Read/Write */
#define SEG_TYPE_CODE_EXRD SEG_FLAG(TYPE, 0x0A) /* Execute/Read */
#define SEG_TYPE_CODE_EX SEG_FLAG(TYPE, 0x08) /* Execute only */
#define SEG_TYPE_LDT SEG_FLAG(TYPE, 0x02)
#define SEG_TYPE_TSS32_AVAIL SEG_FLAG(TYPE, 0x09)
#define SEG_DESCTYPE_SYS SEG_FLAG(DESCTYPE, 0)
#define SEG_DESCTYPE_NSYS SEG_FLAG(DESCTYPE, 1)
#define SEG_PRESENT SEG_FLAG(PRESENT, 1)
#define SEG_DEFL_OPSZ_32BIT SEG_FLAG(DIRECTION, 1)
#define SEG_GRAN_BYTE SEG_FLAG(GRAN, 0)
#define SEG_GRAN_PAGE SEG_FLAG(GRAN, 1)
/**
* Maximum length of segment that can be regulated with a byte-granularity
* segment limit.
*/
#define SEG_MAX_BYTE_GRAN_LEN (1 << 20)
/**
* Segment descriptor. See Intel Combined Manual,
* Vol. 3, Section 3.4.5 for more details.
*/
typedef union segment_desc {
struct {
uint32_t lim_lo : 16;
uint32_t base_lo : 16;
uint32_t base_mid : 8;
uint32_t flags : 16;
uint32_t base_hi : 8;
};
struct {
uint32_t raw_lo, raw_hi;
};
uint64_t raw;
} segment_desc_t;
#define SEG_DESC_NOT_PRESENT 0
/* The next two functions are invoked by boot code, so they must always be
* inlined to avoid being placed in a different address space than the initial,
* flat address space.
*/
static inline void __attribute__((always_inline))
segment_desc_set_limit(segment_desc_t *c_this, uint32_t len)
{
uint32_t limit = len - 1;
SEG_SET_FLAG(*c_this, LIMIT_HI, limit >> 16); /* set limit bits 19:16 */
c_this->lim_lo = limit; /* set limit bits 15:0 */
}
/**
* \brief Initialize a segment descriptor.
* \param c_this Segment descriptor to be initialized.
* \param base Base address of region to be covered by segment descriptor.
* \param len Length to be specified by segment descriptor. The units may
* be bytes or pages, depending on the flags.
* \param flags Flags to be added to the default flags: present, default
* operand size of 32 bits, and high limit bits.
*/
static inline void __attribute__((always_inline))
segment_desc_init(segment_desc_t *c_this,
uint32_t base, uint32_t len, uint16_t flags)
{
c_this->raw = 0;
/* Create the high 32 bit segment */
c_this->base_mid = base >> 16; /* set base bits 23:16 */
c_this->base_hi = base >> 24; /* set base bits 31:24 */
/* Create the low 32 bit segment */
c_this->base_lo = base; /* set base bits 15:0 */
c_this->flags = SEG_FLAG(PRESENT, 1) | SEG_DEFL_OPSZ_32BIT | flags;
/* This must be done after setting the other flags, or else it
* would be partially overridden.
*/
segment_desc_set_limit(c_this, len);
}
#endif /* CPU_X86_MM_SEGMENTATION_H_ */

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2015, 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 "stacks.h"
uint8_t stacks_main[STACKS_SIZE_MAIN]
__attribute__((section(".main_stack"), aligned(4)));
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
uint8_t stacks_int[STACKS_SIZE_INT]
__attribute__((section(".int_stack"), aligned(4)));
uint8_t stacks_exc[STACKS_SIZE_EXC]
__attribute__((section(".exc_stack"), aligned(4)));
#endif

View File

@ -1,109 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_STACKS_H_
#define CPU_X86_MM_STACKS_H_
#include "prot-domains.h"
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__NONE
#define STACKS_SIZE_INT 0
#else
/**
* The necessary amount of space for the interrupt and exception stacks is
* determined by the amount of data pushed on the stack by the CPU when
* delivering an interrupt or exception, and by the additional data pushed
* on the stack by the interrupt dispatcher. See interrupt.h for more details.
*/
#define STACKS_SIZE_INT (14 * 4)
#endif
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
/**
* The system call and return dispatchers use this stack, so its size was
* determined by observing their behavior. It is possible that the dispatchers
* could overflow the stack and overwrite data on the other stacks. An
* alternative design that would facilitate detection of such overflows would
* place the exception handler stack on a separate page surrounded by guard
* bands, but that would consume a substantial amount of additional memory.
*
* All stack sizes should be a multiple of 4 to accommodate a 4-byte alignment.
*/
#ifdef __clang__
#define STACKS_SIZE_EXC 512
#else
#define STACKS_SIZE_EXC 256
#endif
#elif X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
#ifdef __clang__
#define STACKS_SIZE_EXC 512
#else
#define STACKS_SIZE_EXC 256
#endif
#elif X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__TSS
/**
* This should be large enough to execute the exception handler with the
* largest stack requirement: double_fault_handler:
* - 1 word for the return address from calling double_fault_handler
* - 1 word for the saved frame pointer in double_fault_handler
* - 2 words that GCC has been observed to skip on the stack to align it
* to a preferred boundary
* - 1 word for the return address for calling halt
*/
#define STACKS_SIZE_EXC (STACKS_SIZE_INT + (6 * 4))
#else
#define STACKS_SIZE_EXC STACKS_SIZE_INT
#endif
/**
* The combined size of the stacks should be an even multiple of the 4K page
* size so that they precisely fill some number of pages when paging-based
* protection domains are in use. The stacks are arranged contiguously by
* the linker scripts. See those and README.md for more details.
*/
#define STACKS_SIZE_MAIN (8192 - (STACKS_SIZE_INT + STACKS_SIZE_EXC))
#if !__ASSEMBLER__
/**
* Stack for exception handlers. Also used for system call and return
* dispatchers when paging-based protection domains are enabled.
*/
extern uint8_t stacks_exc[STACKS_SIZE_EXC];
/** Stack for interrupt handlers. */
extern uint8_t stacks_int[STACKS_SIZE_INT];
/** Main C stack. */
extern uint8_t stacks_main[STACKS_SIZE_MAIN];
#define STACKS_INIT_TOP \
((uintptr_t)stacks_main + STACKS_SIZE_MAIN - \
(PROT_DOMAINS_INIT_RET_ADDR_CNT * sizeof(uintptr_t)))
#endif
#endif /* CPU_X86_MM_STACKS_H_ */

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2015, 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 "gdt.h"
#include "helpers.h"
#include "multi-segment.h"
#include "prot-domains.h"
/*---------------------------------------------------------------------------*/
void
prot_domains_reg(dom_client_data_t ATTR_KERN_ADDR_SPACE *dcd,
uintptr_t mmio, size_t mmio_sz,
uintptr_t meta, size_t meta_sz,
bool pio)
{
volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *dkd;
dom_id_t dom_id;
KERN_READL(dom_id, dcd->dom_id);
if(PROT_DOMAINS_ACTUAL_CNT <= dom_id) {
halt();
}
dkd = prot_domains_kern_data + dom_id;
prot_domains_reg_multi_seg(dkd, mmio, mmio_sz, meta, meta_sz);
KERN_WRITEL(dkd->flags, pio ? PROT_DOMAINS_FLAG_PIO : 0);
}
/*---------------------------------------------------------------------------*/
static inline void __attribute__((always_inline))
prot_domains_switch(dom_id_t from_id, dom_id_t to_id,
interrupt_stack_t *intr_stk)
{
__asm__ __volatile__ (
"lldt %[_ldt_]\n\t"
"mov %[_meta_seg_], %%eax\n\t"
"lsl %%eax, %%ecx\n\t"
"jz 1f\n\t" /* ZF will only be set if the segment descriptor is valid. */
"xor %%eax, %%eax\n\t" /* Nullify metadata selector */
"1: mov %%eax, %%" SEG_META "s\n\t"
"mov %[_kern_seg_], %%eax\n\t"
"mov %%eax, %%" SEG_KERN "s\n\t"
:
: [_ldt_] "r" ((uint16_t)GDT_SEL_LDT(to_id)),
[_meta_seg_] "i" (LDT_SEL_META),
[_kern_seg_] "i" (LDT_SEL_KERN)
: "cc", "eax", "ecx"
);
}
/*---------------------------------------------------------------------------*/
/* Enable inter-procedural optimization with procedures in the following file:
*/
#include "syscalls-int.c"

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_SWSEG_PROT_DOMAINS_H_
#define CPU_X86_MM_SWSEG_PROT_DOMAINS_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "ldt-layout.h"
#include "paging.h"
#include "segmentation.h"
#include "syscalls-int.h"
struct dom_kern_data {
/** Local Descriptor Table with per-domain descriptors */
segment_desc_t ldt[LDT_NUM_DESC];
/** Flags are defined with the prefix PROT_DOMAINS_FLAG in prot-domains.h */
uint32_t flags;
/**
* Original return address from call stack when this protection domain
* invoked some other protection domain. This serves to control the return
* entrypoint. The callee is not permitted to modify this value (unless the
* callee is the kernel protection domain).
*/
uintptr_t orig_ret_addr;
/* This structure is precisely 32 bytes in length, a power of 2. If its size
* changes, add an alignment attribute to keep it aligned at a power of 2 so
* that dereferencing arrays of these structures uses shift instructions
* instead of multiplication. Shifting is faster than multiplication.
*/
};
/* relies on dom_kern_data: */
#include "multi-segment.h"
#define PROT_DOMAINS_ENTER_ISR(exc) \
MULTI_SEGMENT_ENTER_ISR(exc) \
PROT_DOMAINS_ENTER_ISR_COMMON(exc)
#define PROT_DOMAINS_LEAVE_ISR(exc) \
PROT_DOMAINS_LEAVE_ISR_COMMON(exc) \
MULTI_SEGMENT_LEAVE_ISR(exc)
#define prot_domains_impl_init syscalls_int_init
#define prot_domains_set_wp(en)
/* Allocate one additional GDT entry for each protection domain. Note that
* the particular storage allocated by this statement may actually be used for
* some other protection domain, depending on how the linker happens to arrange
* all of the GDT storage. The GDT_IDX_LDT macro in gdt-layout.h determine
* which storage is used for each protection domain. Thus, this storage should
* not be referenced directly by its variable name.
*/
#define PROT_DOMAINS_ALLOC_IMPL(nm) \
static segment_desc_t ATTR_BSS_GDT_MID _gdt_storage_##nm
#endif /* CPU_X86_MM_SWSEG_PROT_DOMAINS_H_ */

View File

@ -1,133 +0,0 @@
/*
* Copyright (C) 2015, 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 "syscalls-int.h"
#include "prot-domains.h"
#include "gdt-layout.h"
#include "stacks.h"
/* Must match definitions (plus the trailing 's') in multi-segment.h */
#define SEG_MMIO fs
#define SEG_KERN fs
.text
/* Invoke the system call return dispatcher from the default privilege
* level
*/
.global prot_domains_sysret_stub
prot_domains_sysret_stub:
int $PROT_DOMAINS_SYSRET_DISPATCH_INT
.macro save_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
/* Save (and restore, in restore_segs) MMIO segment register into
* callee-saved register in case a system call was invoked from a region in
* which MMIO is enabled.
*/
push %SEG_MMIO
#endif
.endm
.macro restore_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
pop %SEG_MMIO
#endif
.endm
/* Refresh most of the segment registers in case they were corrupted by
* userspace code to prevent that from corrupting the operation of the
* privileged code.
*/
.macro load_kern_segs
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__SWSEG
mov $GDT_SEL_DATA, %eax
mov %eax, %ds
mov %eax, %es
mov $GDT_SEL_DATA_KERN_EXC, %eax
mov %eax, %SEG_KERN
#endif
.endm
/* Invoke the system call dispatcher C routine */
.global prot_domains_syscall_dispatcher
prot_domains_syscall_dispatcher:
mov %esp, %ecx /*< interrupt_stack_t *intr_stk */
/* EDX already set to "dom_client_data_t to_dcd" by syscall stub */
save_segs
push %eax /*< syscalls_entrypoint_t *syscall */
load_kern_segs
call prot_domains_syscall_dispatcher_impl
/* fastcall convention, so callee pops arguments */
restore_segs
iret
/* Invoke the system call return dispatcher C routine */
.global prot_domains_sysret_dispatcher
prot_domains_sysret_dispatcher:
mov %esp, %ecx /*< interrupt_stack_t *intr_stk */
save_segs
load_kern_segs
call prot_domains_sysret_dispatcher_impl
restore_segs
/* Zero caller-saved registers in case they contain secrets. The system call
* handlers and dispatchers need to preserve the callee-saved registers.
*/
xor %eax, %eax
xor %ecx, %ecx
xor %edx, %edx
iret
.global prot_domains_launch_kernel
prot_domains_launch_kernel:
#if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
mov $GDT_SEL_DATA, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov %eax, %gs
#else
mov $GDT_SEL_LDT(DOM_ID_kern), %eax
lldt %ax
call multi_segment_launch_kernel
#endif
/* init interrupt return stack: */
pushl $GDT_SEL_STK
lea stacks_main, %eax
/* matches STACKS_INIT_TOP, plus 4 since an address has been consumed: */
add $(STACKS_SIZE_MAIN - 4), %eax
pushl %eax
pushl $EFLAGS_IOPL(PRIV_LVL_INT)
pushl $GDT_SEL_CODE
pushl $0 /* will be overwritten by syscall_dispatcher_impl */
/* fastcall convention: */
mov %esp, %ecx
call prot_domains_launch_kernel_impl
iretl

View File

@ -1,318 +0,0 @@
/*
* Copyright (C) 2015, 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 "prot-domains.h"
#include "tss.h"
#include "helpers.h"
#include "stacks.h"
#include "idt.h"
#include "syscalls.h"
#include "gdt.h"
#include "gdt-layout.h"
#include "interrupt.h"
/**
* Current protection domain. Not protected, since it is just a convenience
* variable to avoid unneeded protection domain switches.
*/
dom_id_t cur_dom = DOM_ID_app;
/* defined in syscalls-int-asm.S */
void prot_domains_sysret_dispatcher(void);
/* Maximum depth of inter-domain call stack */
#define MAX_INTER_DOM_CALL_STK_SZ 4
/* Protected call stack for inter-domain system calls. The stack grows up. */
static volatile dom_id_t ATTR_BSS_KERN
inter_dom_call_stk[MAX_INTER_DOM_CALL_STK_SZ];
/* Pointer to the next (free) slot in the inter-domain call stack */
static int ATTR_BSS_KERN inter_dom_call_stk_ptr;
/*---------------------------------------------------------------------------*/
static inline void __attribute__((always_inline))
update_eflags(dom_id_t from_id, dom_id_t to_id, interrupt_stack_t *intr_stk)
{
if((to_id == DOM_ID_app) &&
(DT_SEL_GET_RPL(intr_stk->cs) == PRIV_LVL_USER)) {
/* Only enable interrupts in the application protection domain cooperative
* scheduling context.
*/
intr_stk->eflags |= EFLAGS_IF;
} else {
intr_stk->eflags &= ~EFLAGS_IF;
}
}
/*---------------------------------------------------------------------------*/
static inline void __attribute__((always_inline))
dispatcher_tail(dom_id_t from_id, dom_id_t to_id, interrupt_stack_t *intr_stk)
{
cur_dom = to_id;
prot_domains_switch(from_id, to_id, intr_stk);
prot_domains_set_wp(true);
update_eflags(from_id, to_id, intr_stk);
}
/*---------------------------------------------------------------------------*/
int main(void);
static inline void __attribute__((always_inline))
syscall_dispatcher_tail(interrupt_stack_t *intr_stk,
dom_id_t to_id,
uint32_t syscall_eip)
{
dom_id_t from_id;
uint32_t tmp;
volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *from_dkd, *to_dkd;
uint32_t loc_call_stk_ptr;
to_dkd = prot_domains_kern_data + to_id;
/* This implementation of protection domains is non-reentrant. For example,
* it stores the return address taken from the stack of a caller domain
* while dispatching a system call and stores it in a single field in the
* kernel data associated with that protection domain. That model does not
* permit reentrancy.
*/
KERN_READL(tmp, to_dkd->flags);
if((tmp & PROT_DOMAINS_FLAG_BUSY) == PROT_DOMAINS_FLAG_BUSY) {
halt();
}
tmp |= PROT_DOMAINS_FLAG_BUSY;
KERN_WRITEL(to_dkd->flags, tmp);
/* Update the interrupt stack so that the IRET instruction will return to the
* system call entrypoint.
*/
intr_stk->eip = syscall_eip;
KERN_READL(loc_call_stk_ptr, inter_dom_call_stk_ptr);
/* Lookup the information for the caller */
KERN_READL(from_id, inter_dom_call_stk[loc_call_stk_ptr - 1]);
from_dkd = prot_domains_kern_data + from_id;
/* Save the current return address from the unprivileged stack to a protected
* location in the kernel-owned data structure. This enforces return
* entrypoint control.
*/
KERN_WRITEL(from_dkd->orig_ret_addr, *(uintptr_t *)intr_stk->esp);
/* Update the unprivileged stack so that when the system call body is
* complete, it will invoke the system call return stub.
*/
*((uintptr_t *)intr_stk->esp) = (uintptr_t)prot_domains_sysret_stub;
if(MAX_INTER_DOM_CALL_STK_SZ <= loc_call_stk_ptr) {
halt();
}
KERN_WRITEL(inter_dom_call_stk[loc_call_stk_ptr], to_id);
loc_call_stk_ptr++;
KERN_WRITEL(inter_dom_call_stk_ptr, loc_call_stk_ptr);
dispatcher_tail(from_id, to_id, intr_stk);
}
/*---------------------------------------------------------------------------*/
void __attribute__((fastcall))
prot_domains_syscall_dispatcher_impl(interrupt_stack_t *intr_stk,
dom_id_t to_id,
syscalls_entrypoint_t *syscall)
{
uint32_t tmp;
uint32_t syscall_eip;
if(PROT_DOMAINS_ACTUAL_CNT <= to_id) {
halt();
}
/* Get the approved entrypoint for the system call being invoked */
if(!((((uintptr_t)syscalls_entrypoints) <= (uintptr_t)syscall) &&
(((uintptr_t)syscall) < (uintptr_t)syscalls_entrypoints_end) &&
(((((uintptr_t)syscall) - (uintptr_t)syscalls_entrypoints)
% sizeof(syscalls_entrypoint_t)) == 0))) {
/* Assert is not usable when switching protection domains */
halt();
}
KERN_READL(tmp, syscall->doms);
if((BIT(to_id) & tmp) == 0) {
halt();
}
KERN_READL(syscall_eip, syscall->entrypoint);
prot_domains_set_wp(false);
syscall_dispatcher_tail(intr_stk, to_id, syscall_eip);
}
/*---------------------------------------------------------------------------*/
int main(void);
void __attribute__((fastcall))
prot_domains_launch_kernel_impl(interrupt_stack_t *intr_stk)
{
KERN_WRITEL(inter_dom_call_stk[0], DOM_ID_app);
KERN_WRITEL(inter_dom_call_stk_ptr, 1);
syscall_dispatcher_tail(intr_stk, DOM_ID_kern, (uint32_t)main);
}
/*---------------------------------------------------------------------------*/
void __attribute__((fastcall))
prot_domains_sysret_dispatcher_impl(interrupt_stack_t *intr_stk)
{
dom_id_t from_id, to_id;
uint32_t loc_call_stk_ptr;
uint32_t flags;
KERN_READL(loc_call_stk_ptr, inter_dom_call_stk_ptr);
if(loc_call_stk_ptr <= 1) {
halt();
}
KERN_READL(from_id, inter_dom_call_stk[loc_call_stk_ptr - 1]);
KERN_READL(to_id, inter_dom_call_stk[loc_call_stk_ptr - 2]);
KERN_READL(intr_stk->eip,
prot_domains_kern_data[to_id].orig_ret_addr);
prot_domains_set_wp(false);
KERN_READL(flags, prot_domains_kern_data[from_id].flags);
flags &= ~PROT_DOMAINS_FLAG_BUSY;
KERN_WRITEL(prot_domains_kern_data[from_id].flags, flags);
KERN_WRITEL(inter_dom_call_stk_ptr, loc_call_stk_ptr - 1);
dispatcher_tail(from_id, to_id, intr_stk);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Lookup the current protection domain.
* \return Kernel data structure for the current protection domain.
*/
static volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *
get_current_domain(void)
{
uint32_t loc_call_stk_ptr;
dom_id_t id;
KERN_READL(loc_call_stk_ptr, inter_dom_call_stk_ptr);
KERN_READL(id, inter_dom_call_stk[loc_call_stk_ptr - 1]);
return prot_domains_kern_data + id;
}
/*---------------------------------------------------------------------------*/
/**
* \brief Check whether the protection domain is authorized to perform port
* I/O from the cooperative scheduling context.
* \param dkd Protection domain to check
* \return Result of the check as a Boolean value
*/
static bool
needs_port_io(volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *dkd)
{
uint32_t dkd_flags;
KERN_READL(dkd_flags, dkd->flags);
return (dkd_flags & PROT_DOMAINS_FLAG_PIO) == PROT_DOMAINS_FLAG_PIO;
}
/*---------------------------------------------------------------------------*/
/* Mark the context parameter as volatile so that writes to it will not get
* optimized out. This parameter is not handled like ordinary function
* parameters. It actually partially includes the contents of the exception
* stack, so updates to those locations can affect the operation of the
* subsequent interrupt return.
*/
static void
gp_fault_handler(volatile struct interrupt_context context)
{
uint32_t cs_lim;
uint8_t opcode;
volatile dom_kern_data_t ATTR_KERN_ADDR_SPACE *dkd = get_current_domain();
if (needs_port_io(dkd)) {
__asm__ __volatile__ (
"mov %%cs, %0\n\t"
"lsl %0, %0\n\t"
: "=r"(cs_lim));
if (cs_lim < context.eip) {
halt();
}
/* Load first byte of faulting instruction */
__asm__ __volatile__ (
"movb %%cs:%1, %0"
: "=q"(opcode)
: "m"(*(uint8_t *)context.eip));
switch (opcode) {
case 0xEC: /* inb */
context.eax = (context.eax & ~0xFF) | inb((uint16_t)context.edx);
break;
case 0xED: /* inl */
context.eax = inl((uint16_t)context.edx);
break;
case 0xEE: /* outb */
outb((uint16_t)context.edx, (uint8_t)context.eax);
break;
case 0xEF: /* outl */
outl((uint16_t)context.edx, context.eax);
break;
default:
halt();
}
/* Skip the faulting port I/O instruction that was emulated. */
context.eip++;
} else {
halt();
}
}
/*---------------------------------------------------------------------------*/
void
syscalls_int_init(void)
{
tss_init();
SET_EXCEPTION_HANDLER(13, 1, gp_fault_handler);
/* Register system call dispatchers: */
idt_set_intr_gate_desc(PROT_DOMAINS_SYSCALL_DISPATCH_INT,
(uint32_t)prot_domains_syscall_dispatcher,
GDT_SEL_CODE_EXC,
PRIV_LVL_USER);
idt_set_intr_gate_desc(PROT_DOMAINS_SYSRET_DISPATCH_INT,
(uint32_t)prot_domains_sysret_dispatcher,
GDT_SEL_CODE_EXC,
PRIV_LVL_USER);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,109 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_SYSCALLS_INT_H_
#define CPU_X86_MM_SYSCALLS_INT_H_
/** Software interrupt number for dispatching a system call */
#define PROT_DOMAINS_SYSCALL_DISPATCH_INT 100
/** Software interrupt number for returning from a system call */
#define PROT_DOMAINS_SYSRET_DISPATCH_INT 101
#if !__ASSEMBLER__
#include <stdint.h>
extern dom_id_t cur_dom;
#define SYSCALLS_STUB_EPILOGUE(nm) \
/* Load the system call identifier into EAX, as required by */ \
/* prot_domains_syscall_dispatcher: */ \
" mov $" EXP_STRINGIFY(_syscall_ent_##nm) ", %eax\n\t" \
/* Check whether the server protection domain is already active: */ \
" cmp %edx, cur_dom\n\t" \
/* If so, skip the system call dispatcher and directly invoke the */ \
/* system call body: */ \
" je _syscall_" #nm "\n\t" \
" int $" EXP_STRINGIFY(PROT_DOMAINS_SYSCALL_DISPATCH_INT) "\n\t"
#define SYSCALLS_STUB(nm) \
SYSCALLS_ALLOC_ENTRYPOINT(nm); \
asm ( \
".text\n\t" \
".global " #nm "\n\t" \
#nm ":\n\t" \
/* First, load server protection domain ID into EDX, as required by */ \
/* prot_domains_syscall_dispatcher: */ \
/* Skip past return address on stack to obtain address of protection */ \
/* domain ID parameter: */ \
" mov 4(%esp), %edx\n\t" \
SYSCALLS_STUB_EPILOGUE(nm))
#define SYSCALLS_STUB_SINGLETON(nm, dcd) \
SYSCALLS_ALLOC_ENTRYPOINT(nm); \
asm ( \
".text\n\t" \
".global " #nm "\n\t" \
#nm ":\n\t" \
/* First, load server protection domain ID into EDX, as required by */ \
/* prot_domains_syscall_dispatcher: */ \
" mov %" SEG_KERN "s:" #dcd ", %edx\n\t" \
SYSCALLS_STUB_EPILOGUE(nm))
void syscalls_int_init(void);
void prot_domains_sysret_stub(void);
/* Inter-privilege level interrupt stack with no error code. */
typedef struct interrupt_stack {
uint32_t eip;
uint32_t cs;
uint32_t eflags;
uint32_t esp;
uint32_t ss;
} interrupt_stack_t;
#if 0
/* Declaration only included for documentation purposes: */
/**
* \brief Switch to a different protection domain.
* \param from_id Origin protection domain.
* \param to_id Destination protection domain.
* \return Segment selector for kernel data access (only used for
* multi-segment implementations).
*/
uint32_t prot_domains_switch(dom_id_t from_id,
dom_id_t to_id,
interrupt_stack_t *intr_stk);
#endif
#endif
#endif /* CPU_X86_MM_SYSCALLS_INT_H_ */

View File

@ -1,142 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_MM_SYSCALLS_H_
#define CPU_X86_MM_SYSCALLS_H_
#include "helpers.h"
#include "prot-domains.h"
#include <stdbool.h>
typedef uint32_t dom_id_bitmap_t;
typedef struct syscalls_entrypoint {
uintptr_t entrypoint;
dom_id_bitmap_t doms;
} syscalls_entrypoint_t;
extern syscalls_entrypoint_t ATTR_KERN_ADDR_SPACE syscalls_entrypoints[];
extern syscalls_entrypoint_t ATTR_KERN_ADDR_SPACE syscalls_entrypoints_end[];
#define SYSCALLS_ACTUAL_CNT (syscalls_entrypoints_end - syscalls_entrypoints)
#if X86_CONF_PROT_DOMAINS != X86_CONF_PROT_DOMAINS__NONE
#define SYSCALLS_ALLOC_ENTRYPOINT(nm) \
syscalls_entrypoint_t __attribute__((section(".syscall_bss"))) \
ATTR_KERN_ADDR_SPACE _syscall_ent_##nm
#define SYSCALLS_INIT(nm) \
KERN_WRITEL(_syscall_ent_##nm.entrypoint, (uintptr_t)_syscall_##nm); \
KERN_WRITEL(_syscall_ent_##nm.doms, 0)
#define SYSCALLS_DEFINE(nm, ...) \
void _syscall_##nm(__VA_ARGS__); \
SYSCALLS_STUB(nm); \
void _syscall_##nm(__VA_ARGS__)
#define SYSCALLS_DEFINE_SINGLETON(nm, dcd, ...) \
void _syscall_##nm(__VA_ARGS__); \
SYSCALLS_STUB_SINGLETON(nm, dcd); \
void _syscall_##nm(__VA_ARGS__)
#define SYSCALLS_AUTHZ_UPD(nm, drv, set) \
{ \
dom_id_t _sc_tmp_id; \
dom_id_bitmap_t _sc_tmp_bm; \
KERN_READL(_sc_tmp_id, (drv).dom_id); \
KERN_READL(_sc_tmp_bm, _syscall_ent_##nm.doms); \
if(set) { \
_sc_tmp_bm |= BIT(_sc_tmp_id); \
} else { \
_sc_tmp_bm &= ~BIT(_sc_tmp_id); \
} \
KERN_WRITEL(_syscall_ent_##nm.doms, _sc_tmp_bm); \
}
/**
* Check that any untrusted pointer that could have been influenced by a caller
* (i.e. a stack parameter or global variable) refers to a location at or above
* a certain stack boundary and halt otherwise. This is used to prevent a
* protection domain from calling a different protection domain and passing a
* pointer that references a location in the callee's stack other than its
* parameters.
*
* This also checks that the pointer is either within the stack region or the
* shared data region, which is important for preventing redirection of data
* accesses to MMIO or metadata regions. This check is omitted for multi-
* segment protection domain implementations, since the segment settings
* already enforce this property for pointers dereferenced in DS. Pointers
* that can be influenced by a caller should not be dereferenced in any other
* segment.
*
* The pointer is both validated and copied to a new storage location, which
* must be within the callee's local stack region (excluding the parameter
* region). This is to mitigate scenarios such as two pointers being validated
* and an adversary later inducing a write through one of the pointers to the
* other pointer to corrupt the latter pointer before it is used.
*
* The frame address is adjusted to account for the first word pushed on the
* local frame and the return address, since neither of those should ever be
* referenced by an incoming pointer. In particular, if an incoming pointer
* references the return address, it could potentially redirect execution with
* the privileges of the callee protection domain.
*/
#if X86_CONF_PROT_DOMAINS_MULTI_SEG
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) \
validated = untrusted; \
if(((uintptr_t)(validated)) < \
((2 * sizeof(uintptr_t)) + (uintptr_t)__builtin_frame_address(0))) { \
halt(); \
}
#else
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) \
validated = untrusted; \
if((((uintptr_t)(validated)) < \
((2 * sizeof(uintptr_t)) + (uintptr_t)__builtin_frame_address(0))) || \
(((uintptr_t)&_edata_addr) <= (((uintptr_t)(validated)) + (sz)))) { \
halt(); \
}
#endif
#else
#define SYSCALLS_ALLOC_ENTRYPOINT(nm)
#define SYSCALLS_INIT(nm)
#define SYSCALLS_DEFINE(nm, ...) void nm(__VA_ARGS__)
#define SYSCALLS_DEFINE_SINGLETON(nm, dcd, ...) void nm(__VA_ARGS__)
#define SYSCALLS_AUTHZ_UPD(nm, drv, set)
#define PROT_DOMAINS_VALIDATE_PTR(validated, untrusted, sz) validated = untrusted
#endif
#define SYSCALLS_AUTHZ(nm, drv) SYSCALLS_AUTHZ_UPD(nm, drv, true)
#define SYSCALLS_DEAUTHZ(nm, drv) SYSCALLS_AUTHZ_UPD(nm, drv, false)
#endif /* CPU_X86_MM_SYSCALLS_H_ */

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2015, 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.
*/
.text
/* Initialize the TSS fields in prot_domains_reg accordingly:
* Note: Each of these must be a callee-saved register, so that they are
* restored to their original values prior to the task returning. This will
* result in the same values being loaded when the task is next invoked.
*/
#define CUR_DOM_ID_BITMAP esi
/* Must match SEG_KERN (plus the trailing 's') in multi-segment.h */
#define SEG_KERN fs
.global prot_domains_syscall_dispatcher
prot_domains_syscall_dispatcher:
#define PROT_DOMAINS_SYSCALL eax
mov prot_domains_syscall, %PROT_DOMAINS_SYSCALL
cmp $syscalls_entrypoints, %PROT_DOMAINS_SYSCALL
jl halt
cmp $syscalls_entrypoints_end, %PROT_DOMAINS_SYSCALL
jnl halt
#define SYSCALLS_ENTRYPOINTS_ALIGN_MASK ebp
mov $3, %SYSCALLS_ENTRYPOINTS_ALIGN_MASK
and %PROT_DOMAINS_SYSCALL, %SYSCALLS_ENTRYPOINTS_ALIGN_MASK
jnz halt
/* Compare allowed domains bitmask against current domain ID bitmap. If
* the check fails, then the current domain ID bitmap value will be zeroed
* out, which could cause incorrect behavior in the future. However, the
* response to a failed check is to halt the system, so destroying the
* current domain ID bitmap value will have no effect.
*/
and %SEG_KERN:4(%PROT_DOMAINS_SYSCALL), %CUR_DOM_ID_BITMAP
jz halt
mov prot_domains_main_esp, %esp
/* Must be a callee-saved register: */
#define ORIG_RET_ADDR edi
/* Update the caller's stack to return back to here */
pop %ORIG_RET_ADDR
push $sysret_dispatcher
/* Jump to the system call body */
jmp *%SEG_KERN:(%PROT_DOMAINS_SYSCALL)
sysret_dispatcher:
push %ORIG_RET_ADDR
iret
/* The task will resume here for the next system call, so it is necessary
* to jump back to the top.
*/
jmp prot_domains_syscall_dispatcher
.global dev_not_avail_isr
dev_not_avail_isr:
clts
iret

View File

@ -1,161 +0,0 @@
/*
* 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 <stdint.h>
#include <string.h>
#include "gdt.h"
#include "helpers.h"
#include "idt.h"
#include "prot-domains.h"
#include "stacks.h"
#include "syscalls.h"
#include "tss.h"
uint32_t prot_domains_main_esp;
syscalls_entrypoint_t ATTR_KERN_ADDR_SPACE *prot_domains_syscall;
/*---------------------------------------------------------------------------*/
void app_main(void);
void
prot_domains_reg(dom_client_data_t ATTR_KERN_ADDR_SPACE *dcd,
uintptr_t mmio, size_t mmio_sz,
uintptr_t meta, size_t meta_sz,
bool pio)
{
segment_desc_t desc;
uint32_t eflags;
dom_id_t dom_id;
volatile struct dom_kern_data ATTR_KERN_ADDR_SPACE *dkd;
KERN_READL(dom_id, dcd->dom_id);
dkd = prot_domains_kern_data + dom_id;
prot_domains_reg_multi_seg(dkd, mmio, mmio_sz, meta, meta_sz);
/* Only the kernel protection domain requires port I/O access outside of the
* interrupt handlers.
*/
eflags = EFLAGS_IOPL(pio ? PRIV_LVL_USER : PRIV_LVL_INT);
if(dom_id == DOM_ID_app) {
eflags |= EFLAGS_IF;
}
/* Keep this initialization in sync with the register definitions in
* tss-prot-domains-asm.S.
*/
KERN_WRITEL(dkd->tss.ebp, 0);
KERN_WRITEL(dkd->tss.ebx, 0);
KERN_WRITEL(dkd->tss.esi, BIT(dom_id));
KERN_WRITEL(dkd->tss.eip,
(dom_id == DOM_ID_app) ?
(uint32_t)app_main :
(uint32_t)prot_domains_syscall_dispatcher);
KERN_WRITEL(dkd->tss.cs, GDT_SEL_CODE);
KERN_WRITEL(dkd->tss.ds, GDT_SEL_DATA);
KERN_WRITEL(dkd->tss.es, GDT_SEL_DATA);
KERN_WRITEL(dkd->tss.fs, LDT_SEL_KERN);
KERN_WRITEL(dkd->tss.gs,
(meta_sz == 0) ? GDT_SEL_NULL : LDT_SEL_META);
KERN_WRITEL(dkd->tss.ss, GDT_SEL_STK);
/* This stack pointer is only actually used in application protection domain.
* Other domains enter at system call dispatcher, which switches to main
* stack.
*/
KERN_WRITEL(dkd->tss.esp,
/* Two return addresses have been consumed: */
STACKS_INIT_TOP + (2 * sizeof(uintptr_t)));
KERN_WRITEL(dkd->tss.eflags, eflags);
KERN_WRITEL(dkd->tss.ldt, GDT_SEL_LDT(dom_id));
KERN_WRITEL(dkd->tss.esp2, STACKS_SIZE_MAIN + STACKS_SIZE_INT);
KERN_WRITEL(dkd->tss.ss2, GDT_SEL_STK_INT);
KERN_WRITEL(dkd->tss.esp0,
STACKS_SIZE_MAIN + STACKS_SIZE_INT + STACKS_SIZE_EXC);
KERN_WRITEL(dkd->tss.ss0, GDT_SEL_STK_EXC);
KERN_WRITEW(dkd->tss.t, 0);
KERN_WRITEW(dkd->tss.iomap_base, sizeof(tss_t));
KERN_WRITEL(dkd->tss.cr3, 0);
segment_desc_init(&desc,
KERN_DATA_OFF_TO_PHYS_ADDR((uint32_t)&(dkd->tss)),
sizeof(dkd->tss),
/* It should be possible for code at any privilege level to invoke the task's
* system call dispatcher.
*/
SEG_FLAG(DPL, PRIV_LVL_USER) | SEG_TYPE_TSS32_AVAIL);
gdt_insert(GDT_IDX_TSS(dom_id), desc);
KERN_WRITEW(dcd->tss_sel, GDT_SEL(GDT_IDX_TSS(dom_id), PRIV_LVL_USER));
}
/*---------------------------------------------------------------------------*/
void dev_not_avail_isr(void);
void
prot_domains_impl_init(void)
{
__asm__ __volatile__ ("ltr %0" :: "r" ((uint16_t)GDT_SEL_TSS(DOM_ID_kern)));
__asm__ __volatile__ ("lldt %0" :: "r" ((uint16_t)GDT_SEL_LDT(DOM_ID_kern)));
idt_set_intr_gate_desc(7,
(uint32_t)dev_not_avail_isr,
GDT_SEL_CODE_EXC, PRIV_LVL_EXC);
}
/*---------------------------------------------------------------------------*/
int main();
void
prot_domains_launch_kernel(void)
{
multi_segment_launch_kernel();
/* Activate kernel protection domain, entering the kernel at main. */
__asm__ __volatile__ (
"pushl %[_ss_]\n\t"
"pushl %[_top_of_stk_]\n\t"
"pushl %[_eflags_]\n\t"
"pushl %[_cs_]\n\t"
"pushl %[_kern_start_]\n\t"
"iretl\n\t"
:
: [_ss_] "g" (GDT_SEL_STK),
[_eflags_] "g" (EFLAGS_IOPL(PRIV_LVL_USER)),
[_cs_] "g" (GDT_SEL_CODE),
[_kern_start_] "g" (main),
/* one address has already been consumed */
[_top_of_stk_] "g" (STACKS_INIT_TOP + sizeof(uint32_t))
);
}
/*---------------------------------------------------------------------------*/
void
prot_domains_launch_app()
{
far_pointer_t app_ptr = { 0, GDT_SEL_TSS(DOM_ID_app) };
__asm__ __volatile__ ("ljmp *%0" :: "m" (app_ptr));
}
/*---------------------------------------------------------------------------*/

View File

@ -1,130 +0,0 @@
/*
* 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.
*/
#ifndef CPU_X86_MM_TSS_PROT_DOMAINS_H_
#define CPU_X86_MM_TSS_PROT_DOMAINS_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "ldt-layout.h"
#include "segmentation.h"
#include "tss.h"
struct dom_kern_data {
/** Task State Segment */
tss_t tss;
/** Local Descriptor Table with per-domain descriptors */
segment_desc_t ldt[LDT_NUM_DESC];
} __attribute__((packed));
/* relies on dom_kern_data: */
#include "multi-segment.h"
/* relies on ATTR_KERN_ADDR_SPACE: */
#include "syscalls.h"
/**
* Data associated with each protection domain that is owned by clients of that
* domain and used to identify the domain.
*/
struct dom_client_data {
dom_id_t dom_id;
/** The selector is only 16 bits, but it is padded to 32 bits. */
uint32_t tss_sel;
};
extern uint32_t prot_domains_main_esp;
#define SYSCALLS_STUB_MIDDLE(nm) \
/* If already in the callee protection domain, skip the protection */ \
/* domain switch and directly invoke the system call body */ \
" je _syscall_" #nm "\n\t" \
" movl $" EXP_STRINGIFY(_syscall_ent_##nm) ", prot_domains_syscall\n\t" \
" mov %esp, prot_domains_main_esp\n\t"
#define SYSCALLS_STUB(nm) \
SYSCALLS_ALLOC_ENTRYPOINT(nm); \
asm ( \
".text\n\t" \
".global " #nm "\n\t" \
#nm ":\n\t" \
" str %ax\n\t" \
/* Compare current Task Register selector to selector for callee */ \
/* protection domain, in tss_sel field of dom_client_data */ \
" cmpw %ax, 8(%esp)\n\t" \
SYSCALLS_STUB_MIDDLE(nm) \
/* This will treat the dom_id field as the offset for the call, but */ \
/* that is ignored when performing a far call to a task */ \
" lcall *4(%esp)\n\t" \
" ret\n\t")
#define SYSCALLS_STUB_SINGLETON(nm, dcd) \
SYSCALLS_ALLOC_ENTRYPOINT(nm); \
asm ( \
".text\n\t" \
".global " #nm "\n\t" \
#nm ":\n\t" \
" str %ax\n\t" \
/* Compare current Task Register selector to selector for callee */ \
/* protection domain, in tss_sel field of dom_client_data */ \
" cmpw %ax, %" SEG_KERN "s:(4 + " #dcd ")\n\t" \
SYSCALLS_STUB_MIDDLE(nm) \
/* This will treat the dom_id field as the offset for the call, but */ \
/* that is ignored when performing a far call to a task */ \
" lcall *%" SEG_KERN "s:" #dcd "\n\t" \
" ret\n\t")
#define PROT_DOMAINS_ENTER_ISR(exc) \
MULTI_SEGMENT_ENTER_ISR(exc) \
/* It is possible that the system call dispatcher is being interrupted, */ \
/* and some interrupt handlers perform system calls. Thus, it is */ \
/* necessary to save and restore the system call dispatcher parameters */ \
/* (in callee-saved registers). */ \
"mov prot_domains_main_esp, %%esi\n\t" \
"mov prot_domains_syscall, %%edi\n\t" \
PROT_DOMAINS_ENTER_ISR_COMMON(exc)
#define PROT_DOMAINS_LEAVE_ISR(exc) \
PROT_DOMAINS_LEAVE_ISR_COMMON(exc) \
"mov %%edi, prot_domains_syscall\n\t" \
"mov %%esi, prot_domains_main_esp\n\t" \
MULTI_SEGMENT_LEAVE_ISR(exc)
/* Allocate two additional GDT entries for each protection domain. Note that
* the particular storage allocated by this statement may actually be used for
* some other protection domain, depending on how the linker happens to arrange
* all of the GDT storage. The GDT_IDX_TSS and GDT_IDX_LDT macros in
* gdt-layout.h determine which storage is used for each protection domain.
* Thus, this storage should not be referenced directly by its variable name.
*/
#define PROT_DOMAINS_ALLOC_IMPL(nm) \
static segment_desc_t ATTR_BSS_GDT_MID _gdt_storage_##nm[2]
#endif /* CPU_X86_MM_TSS_PROT_DOMAINS_H_ */

View File

@ -1,70 +0,0 @@
/*
* 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 "gdt.h"
#include "gdt-layout.h"
#include "prot-domains.h"
#include "segmentation.h"
#include "stacks.h"
#include "tss.h"
/* System-wide TSS */
tss_t ATTR_BSS_KERN sys_tss;
static segment_desc_t ATTR_BSS_GDT sys_tss_desc;
/*---------------------------------------------------------------------------*/
/**
* \brief Initialize system-wide TSS.
*/
void
tss_init(void)
{
segment_desc_t seg_desc;
/* Initialize TSS */
KERN_WRITEW(sys_tss.iomap_base, sizeof(sys_tss));
KERN_WRITEL(sys_tss.esp2, ((uint32_t)stacks_int) + STACKS_SIZE_INT);
KERN_WRITEL(sys_tss.ss2, GDT_SEL_STK_INT);
KERN_WRITEL(sys_tss.esp0, ((uint32_t)stacks_exc) + STACKS_SIZE_EXC);
KERN_WRITEL(sys_tss.ss0, GDT_SEL_STK_EXC);
segment_desc_init(&seg_desc,
KERN_DATA_OFF_TO_PHYS_ADDR(&sys_tss), sizeof(sys_tss),
SEG_FLAG(DPL, PRIV_LVL_EXC) |
SEG_DESCTYPE_SYS | SEG_TYPE_TSS32_AVAIL);
gdt_insert(GDT_IDX_OF_DESC(&sys_tss_desc), seg_desc);
__asm__ __volatile__ (
"ltr %0"
:
: "r" ((uint16_t)GDT_SEL_OF_DESC(&sys_tss_desc, 0)));
}
/*---------------------------------------------------------------------------*/

View File

@ -1,70 +0,0 @@
/*
* Copyright (C) 2015, 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_MM_TSS_H_
#define CPU_X86_MM_TSS_H_
#include <stdint.h>
/**
* Task State Segment. Used by the CPU to manage switching between
* different protection domains (tasks). The current task is referenced
* by the Task Register. When the CPU switches away from a task due to
* a far call, etc., it updates the associated in-memory TSS with the
* current state of the task. It then loads CPU state from the TSS for
* the new task. See Intel Combined Manual, Vol. 3, Chapter 7 for more
* details.
*/
typedef struct tss {
uint32_t prev_tsk; /**< The selector of the task that called this one, if applicable */
uint32_t esp0; /**< Stack pointer for ring 0 code in this task */
uint32_t ss0; /**< Stack segment selector for ring 0 code in this task */
uint32_t esp1; /**< Stack pointer for ring 1 code in this task */
uint32_t ss1; /**< Stack segment selector for ring 1 code in this task */
uint32_t esp2; /**< Stack pointer for ring 2 code in this task */
uint32_t ss2; /**< Stack segment selector for ring 2 code in this task */
uint32_t cr3; /**< CR3 for this task when paging is enabled */
uint32_t eip; /**< Stored instruction pointer value */
uint32_t eflags; /**< Settings for EFLAGS register */
/** General purpose register values */
uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
/** Segment register selector values */
uint32_t es, cs, ss, ds, fs, gs;
/** Selector for Local Descriptor Table */
uint32_t ldt;
/** Debug-related flag */
uint16_t t;
/** Offset from base of TSS to base of IO permission bitmap, if one is installed */
uint16_t iomap_base;
} tss_t;
void tss_init(void);
#endif /* CPU_X86_TSS_H_ */

View File

@ -1,108 +0,0 @@
/*
* 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.
*/
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
SECTIONS {
/*
OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that
are used by BIOS/EFI, the bootloader and memory-mapped I/O.
The UEFI GenFw program inserts a 0x220-byte offset between the image base and
the .text section. We add that same offset here to align the symbols in the
UEFI DLL with those in the final UEFI binary to make debugging easier. We also
apply 32-byte alignments to sections rather than more conventional 4K-byte
alignments to avoid symbols being shifted from the intermediate DLL to the
final UEFI image as would occur if the GenFw program shifted the .text section
from a higher, 4K-aligned offset to the 0x220-byte offset from the image base.
Such shifting may make debugging more difficult by preventing the DLL from
being a directly-useful source of symbol information. The debugging symbols
are not included in the final UEFI image. The GenFw program uses a minimum
section alignment of 32 bytes, so smaller alignment granularities may also
result in symbol perturbation.
*/
. = 1M + 0x220;
.text : ALIGN (32)
{
KEEP(*(.multiboot))
*(.boot_text)
*(.text*)
}
/*
The alignment directive must be placed after the colon so that the desired
alignment is indicated in the ELF section metadata. This metadata is used
by the UEFI GenFw program. It is necessary to avoid specifying a smaller
alignment value in the ELF metadata for some section "B" that follows some
section "A" with an ending address that is not aligned on a 32-byte boundary.
In that case, GenFw may place section "B" at a lower starting address in the
EFI binary than section "B" had in the input ELF file. This may result in
incorrect program behavior. Note that this situation is not directly visible
in the EFI binary metadata, since GenFw combines the ELF .rodata, .data, and
.bss sections into a single .data section in the EFI binary.
*/
.rodata : ALIGN (32)
{
*(.rodata*)
_sdata_kern_startup_func = .;
KEEP(*(.kern_startup_func))
_edata_kern_startup_func = .;
_sdata_shared_isr = .;
KEEP(*(.shared_isr_data*))
_edata_shared_isr = .;
}
.data : ALIGN (32)
{
*(.data*)
}
.bss : ALIGN (32)
{
*(COMMON)
*(.main_stack)
*(.bss*)
*(.gdt_bss_start)
/*
The other GDT-related sections defined in gdt.h are only used when
protection domain support is enabled. Thus, they do not need to be
included here.
*/
_ebss_gdt_addr = .;
}
_ebss_pre_dma_addr = ALIGN(32);
}

View File

@ -1,47 +0,0 @@
/*
* 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.
*/
SECTIONS {
.bss.dma (NOLOAD) : AT(_ebss_pre_dma_addr) ALIGN (32)
{
/* IMRs are used to restrict DMA, and they require 1K physical address alignment. */
. += ALIGN(_ebss_pre_dma_addr, 1K) - ALIGN(_ebss_pre_dma_addr, 32);
*(.dma_bss)
}
_sbss_dma_addr = LOADADDR(.bss.dma) + ALIGN(_ebss_pre_dma_addr, 1K) - ALIGN(_ebss_pre_dma_addr, 32);
/*
Effectively pointing beyond the end of .bss.dma is acceptable, since
.bss.dma is the last section in memory.
*/
_ebss_dma_addr = ALIGN(LOADADDR(.bss.dma) + SIZEOF(.bss.dma), 1K);
}

View File

@ -1,194 +0,0 @@
/*
* Copyright (C) 2015, 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.
*/
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
/*
The TSS-based protection domain implementation does not explicitly reference
these symbols, so we list them here to prevent them from being garbage-
collected.
*/
EXTERN(stacks_int)
EXTERN(stacks_exc)
PHDRS {
boot_text PT_LOAD;
text PT_LOAD;
data PT_LOAD;
}
SECTIONS {
/*
OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that
are used by BIOS/EFI, the bootloader and memory-mapped I/O.
The UEFI GenFw program inserts a 0x220 byte offset between the image base and
the .text section. We add that same offset here to align the symbols in the
UEFI DLL with those in the final UEFI binary to make debugging easier.
*/
. = 1M + 0x220;
/*
The GenFw program in the EDK2 UEFI toolchain outputs UEFI images with a
section alignment of at least 32 bytes. Thus, it is desirable to use at
least that alignment granularity to avoid symbols being shifted from the
intermediate DLL to the final UEFI image. Such shifting may make
debugging more difficult by preventing the DLL from being a useful
source of symbol information. The debugging symbols are not included in
the final UEFI image.
*/
.text.boot : ALIGN (32)
{
*(.multiboot)
/*
The initial bootstrap code expects to operate in a flat address
space with an identity mapping between linear and physical
addresses.
*/
*(.boot_text)
} :boot_text
/* The post-boot code segments define tight bounds around the code
section, so this directive resets the virtual address to 0. */
. = 0;
/* The virtual address differs from the load address. */
.text : AT(LOADADDR(.text.boot) + ALIGN(SIZEOF(.text.boot), 32)) ALIGN (32)
{
/*
These BYTE directives emit a UD2 instruction to cause execution to
halt if the control flow ever deviates to address 0. This also
prevents other code from being placed at address 0. Some code
considers a function pointer to address 0 to be a null function
pointer.
*/
BYTE(0x0F);
BYTE(0x0B);
*(.text*)
/*
An alternative design to eliminate the need for ALIGN directives
within the AT directives in later sections could have padded
each section out to a 32-byte boundary. However, that would have
enabled unneeded software accesses to the padding past the end of actual
code/data in each section, since segments are also configured based on
the values of the SIZEOF expressions. As a general principle, accesses
should be as restricted as is feasible.
*/
} :text
_stext_addr = LOADADDR(.text);
_etext_addr = LOADADDR(.text) + SIZEOF(.text);
. = 0;
.data : AT(ALIGN(_etext_addr, 32)) ALIGN (32)
{
*(.main_stack)
*(.int_stack)
*(.exc_stack)
*(.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.
*/
_sdata_shared_isr = .;
KEEP(*(.shared_isr_data*))
_edata_shared_isr = .;
} :data
.bss : ALIGN (32)
{
*(COMMON)
*(.bss*)
}
_sdata_addr = LOADADDR(.data);
_edata_addr = LOADADDR(.bss) + SIZEOF(.bss);
. = 0;
.bss.kern (NOLOAD) : AT(ALIGN(_edata_addr, 32)) ALIGN (32)
{
/*
This directive prevents any data from being allocated at address
zero, since the address 0 is commonly used to represent null
pointers.
*/
LONG(0);
*(.kern_bss)
syscalls_entrypoints = .;
*(.syscall_bss)
syscalls_entrypoints_end = .;
}
_ebss_syscall_addr = LOADADDR(.bss.kern) + SIZEOF(.bss.kern);
.bss.kern_priv (NOLOAD) : ALIGN (32)
{
prot_domains_kern_data = .;
/*
The kernel and app protection domain control structures must always
be placed in the first two slots in this order, so that they have
well-known protection domain IDs:
*/
*(.kern_prot_dom_bss)
*(.app_prot_dom_bss)
*(.prot_dom_bss)
prot_domains_kern_data_end = .;
*(.gdt_bss_start)
KEEP(*(.gdt_bss_mid))
*(.gdt_bss)
_ebss_gdt_addr = .;
}
_sbss_kern_addr = LOADADDR(.bss.kern);
_ebss_kern_addr = LOADADDR(.bss.kern_priv) + SIZEOF(.bss.kern_priv);
. = _ebss_kern_addr;
.bss.meta (NOLOAD) : AT(ALIGN(_ebss_kern_addr, 32)) ALIGN (32)
{
*(.meta_bss)
}
/* .bss.meta may be empty, so this uses .bss.kern_priv as a base instead: */
_ebss_pre_dma_addr = ALIGN(ALIGN(_ebss_kern_addr, 32) + SIZEOF(.bss.meta), 32);
}

View File

@ -1,210 +0,0 @@
/*
* 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.
*/
OUTPUT_FORMAT("elf32-i386")
ENTRY(start)
SECTIONS {
/*
OS-Dev Wiki says it is common for kernels to start at 1M. Addresses before that
are used by BIOS/EFI, the bootloader and memory-mapped I/O.
The UEFI GenFw program inserts a 0x220-byte offset between the image base and
the .text section. We add that same offset here to align the symbols in the
UEFI DLL with those in the final UEFI binary to make debugging easier.
*/
. = 1M + 0x220;
.text.boot : ALIGN (32)
{
*(.multiboot)
*(.boot_text)
/*
Fill out the section to the next 4K boundary so that the UEFI GenFw
program does not shift the following .text section forward into the
gap and perturb the symbols. This only works if the size of this
section is less than 4K - 0x220 bytes.
*/
. = 4K - 0x220;
}
/*
It is actually desired that each of the following sections be page-
aligned. However, the UEFI GenFw program ratchets up its alignment
granularity to the maximum granularity discovered in its input file.
Using page-alignment perturbs the symbols, hindering debugging. Thus,
this file simply pads each section out to the desired page alignment and
declares a section alignment granularity of 32 bytes.
*/
.text : ALIGN (32)
{
*(.text*)
. = ALIGN(4K);
}
_stext_addr = ADDR(.text);
_etext_addr = ADDR(.text) + SIZEOF(.text);
.data.stack : ALIGN (32)
{
/*
Introduce a guard band page before the stacks to facilitate stack
overflow detection. This approach wastes a page of memory for each
guard band, but has the advantage of enabling an identity mapping
for all linear to physical addresses except those in the MMIO
regions. The guard bands are marked not-present in the page tables
to facilitate stack overflow detection.
This padding must be placed inside of the section, or else it will
get dropped when the UEFI GenFw program generates the UEFI binary.
*/
. += 4K;
/*
Place the main stack first so that an overflow is detected and does
not overwrite the interrupt or supervisor stacks. Usage of the
interrupt and stack is predictable, since it is only used by short
trampoline code sequences that quickly pivot to the main stack.
*/
*(.main_stack)
*(.int_stack)
*(.exc_stack)
/*
The combined sizes of the stacks is an even multiple of 4K, so there
is no need to align the location counter here.
*/
/*
Introduce a guard band page after the stacks to detect stack underflow.
Note that an underflow that only affects the interrupt and supervisor
stacks will not generate a page fault. Detecting such conditions by
placing the interrupt and supervisor stacks on separate pages would
substantially increase memory usage.
*/
. += 4K;
}
.data : ALIGN (32)
{
/*
The UEFI GenFw program treats all sections that are alloc and read-
only as code sections. By that criteria, .rodata would be a code
section, but making such data executable is undesirable. Thus, this
script lumps in .rodata with other data. It may be desirable in the
future to actually write-protect this data.
*/
*(.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.
*/
_sdata_shared_isr = .;
KEEP(*(.shared_isr_data*))
_edata_shared_isr = .;
. = ALIGN(4K);
}
.bss : ALIGN (32)
{
*(COMMON)
*(.bss*)
. = ALIGN(4K);
}
_sdata_addr = ADDR(.data);
_edata_addr = ADDR(.bss) + SIZEOF(.bss);
.bss.kern (NOLOAD) : ALIGN (32)
{
/*
Page-aligned data is output first.
It is infeasible to apply a page-alignment attribute to them in the
source code, because that increases the alignment of this section to
be page-aligned, which causes problems when generating a UEFI binary
as described above.
*/
*(.page_aligned_kern_bss)
*(.kern_bss)
syscalls_entrypoints = .;
*(.syscall_bss)
syscalls_entrypoints_end = .;
. = ALIGN(4K);
}
_ebss_syscall_addr = ADDR(.bss.kern) + SIZEOF(.bss.kern);
.bss.kern_priv (NOLOAD) : ALIGN (32)
{
prot_domains_kern_data = .;
/*
The kernel and app protection domain control structures must always
be placed in the first two slots in this order, so that they have
well-known protection domain IDs:
*/
*(.kern_prot_dom_bss)
*(.app_prot_dom_bss)
*(.prot_dom_bss)
prot_domains_kern_data_end = .;
*(.gdt_bss_start)
*(.gdt_bss_mid)
*(.gdt_bss)
_ebss_gdt_addr = .;
. = ALIGN(4K);
}
_sbss_kern_addr = ADDR(.bss.kern);
_ebss_kern_addr = ADDR(.bss.kern_priv) + SIZEOF(.bss.kern_priv);
.bss.meta (NOLOAD) : ALIGN (32)
{
*(.meta_bss)
. = ALIGN(4K);
}
_ebss_pre_dma_addr = ALIGN(32);
}

View File

@ -1,46 +0,0 @@
/*
* 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_ */

View File

@ -1,72 +0,0 @@
/*
* Copyright (C) 2015, 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 <Uefi.h>
#include <Protocol/LoadedImage.h>
#define MAX_MEM_DESC 128
void start(void);
/* The section attribute below is copied from ATTR_BOOT_CODE in prot-domains.h.
* prot-domains.h includes stdlib.h which defines NULL. The UEFI headers also
* define NULL, which induces a warning when the compiler detects the conflict.
* To avoid that, we avoid including prot-domains.h from this file.
*/
EFI_STATUS EFIAPI __attribute__((section(".boot_text")))
uefi_start(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_MEMORY_DESCRIPTOR mem_map[MAX_MEM_DESC];
UINTN mem_map_len = sizeof(mem_map);
UINTN mem_map_key;
UINTN mem_map_desc_sz;
UINT32 mem_map_rev;
EFI_STATUS res;
res = SystemTable->BootServices->GetMemoryMap(&mem_map_len,
mem_map,
&mem_map_key,
&mem_map_desc_sz,
&mem_map_rev);
if(res != EFI_SUCCESS) {
return EFI_ABORTED;
}
res = SystemTable->BootServices->ExitBootServices(ImageHandle, mem_map_key);
if(res != EFI_SUCCESS) {
return EFI_ABORTED;
}
start();
/* Should not be reachable: */
return EFI_SUCCESS;
}

View File

@ -1,27 +0,0 @@
#!/bin/bash
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# This script will always run on its own basepath, no matter where you call it from.
pushd ${SCRIPT_DIR}
if [ "$(uname -m)" = "x86_64" ]; then
export ARCH=X64
fi
# Download the UEFI tool and library sources:
if [ -e edk2 ]; then
make -C edk2/BaseTools/Source/C/Common clean
make -C edk2/BaseTools/Source/C/GenFw clean
else
git clone --depth=1 https://github.com/tianocore/edk2 || exit
fi
# Build common sources required by the GenFw tool:
make -C edk2/BaseTools/Source/C/Common || exit
# Build the GenFw tool that is used to generate UEFI binaries:
make -C edk2/BaseTools/Source/C/GenFw || exit
# Create a makefile that indicates to the Contiki build system that UEFI support
# should be built:
echo "EN_UEFI = 1" > Makefile.uefi
popd

View File

@ -1,59 +0,0 @@
GDB ?= gdb
OPENOCD_SCRIPTS = $(CONTIKI)/arch/platform/galileo/bsp/openocd-scripts
.PHONY: debug $(CONTIKI_PROJECT)
# Multiboot ELF binary
MULTIBOOT_SFX = $(TARGET)
MULTIBOOT = $(CONTIKI_PROJECT).$(MULTIBOOT_SFX)
# UEFI binary
UEFI_DLL_SFX = $(TARGET).dll
UEFI_DLL = $(CONTIKI_PROJECT).$(UEFI_SFX)
# The GenFw program is unable to process absolute symbols like _stext_addr,
# etc., that are defined in quarkX1000_dma.ld and quarkX1000_multi_seg.ld
# and used to configure segments in multi-segment.c, etc. Furthermore,
# relocating the UEFI image during load would result in those symbols not
# pointing to the expected image locations. So, relocation data is omitted
# from the intermediate UEFI DLL. This will only result in a
# correctly-functioning build if the UEFI firmware does not attempt to
# relocate the UEFI image, so it may be desirable in the future to revisit
# this design. To emit relocation data, '-Xlinker --emit-relocs' should be
# appended to the following line.
UEFI_LDFLAGS = -Xlinker --entry=uefi_start
UEFI_SFX = $(TARGET).efi
UEFI = $(CONTIKI_PROJECT).$(UEFI_SFX)
# Suffixes for final (non-intermediate) files to be built
FINAL_SFXS = $(MULTIBOOT_SFX)
ifeq ($(EN_UEFI),1)
FINAL_SFXS += $(UEFI_SFX)
endif
debug: $(MULTIBOOT)
@openocd -s $(OPENOCD_SCRIPTS) -f debug.cfg &> $(shell pwd)/LOG_OPENOCD &
@$(GDB) $< -ex "target remote :3333"
CUSTOM_RULE_LINK=1
%.$(MULTIBOOT_SFX): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
$(TRACE_LD)
$(Q)$(LD) $(LDFLAGS) $(MULTIBOOT_LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \
${filter %.a,$^} $(TARGET_LIBFILES) -o $@
%.$(UEFI_DLL_SFX): %.co $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) contiki-$(TARGET).a
$(TRACE_LD)
$(Q)$(LD) $(LDFLAGS) $(UEFI_LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \
${filter %.a,$^} $(TARGET_LIBFILES) -o $@
%.$(UEFI_SFX): %.$(UEFI_DLL_SFX)
$(Q)$(GEN_FW) -o $@ -e UEFI_APPLICATION $^
# The Intel Galileo firmware has been observed to not relocate the image
# if its base is set to the 1M boundary. This makes debugging easier,
# since the symbols in the intermediate DLL then correspond to the load
# addresses.
$(Q)$(GEN_FW) -o $@ --rebase 0x100000 $@
$(CONTIKI_PROJECT): $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS))
@$(SIZE) $^
CLEAN += $(addprefix $(CONTIKI_PROJECT).,$(FINAL_SFXS))

View File

@ -1,43 +0,0 @@
BSP_PATH=$(CONTIKI)/arch/platform/galileo/bsp
LIBC_PATH=$(BSP_PATH)/libc
LIBC=$(LIBC_PATH)/i586-elf
LIBGCC_PATH = /usr/lib/gcc/$(shell gcc -dumpmachine)/$(shell gcc -dumpversion)
CONTIKI_TARGET_DIRS = . core/sys/ drivers/ net/
CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o}
CONTIKI_SOURCEFILES += contiki-main.c clock.c rtimer-arch.c eth-proc.c eth-conf.c galileo-gpio.c
GALILEO_GEN ?= 2
CFLAGS += -DGALILEO_GEN=$(GALILEO_GEN)
CONTIKI_SOURCEFILES += galileo-gen$(GALILEO_GEN)-pinmux.c
ifeq ($(GALILEO_GEN),2)
CONTIKI_SOURCEFILES += gpio-pcal9535a.c pwm-pca9685.c
else
CONTIKI_SOURCEFILES += cy8c9540a.c
endif
ifeq ($(CONTIKI_WITH_IPV6),1)
CONTIKI_SOURCEFILES += nbr-table.c packetbuf.c linkaddr.c link-stats.c
endif
PROJECT_SOURCEFILES += newlib-syscalls.c
CONTIKI_CPU=$(CONTIKI)/arch/cpu/x86
include $(CONTIKI)/arch/cpu/x86/Makefile.x86_quarkX1000
CFLAGS += -fno-stack-protector -I$(LIBC)/include
ifeq (clang,$(findstring clang,$(CC)))
CFLAGS += -nostdlibinc
else
CFLAGS += -nostdinc -isystem $(LIBGCC_PATH)/include -isystem $(LIBGCC_PATH)/include-fixed
endif
LDFLAGS += -nostdlib -L$(LIBC)/lib -L$(LIBGCC_PATH)/32
TARGET_LIBFILES += -lm -lc -lgcc
-include $(LIBC_PATH)/Makefile.libc
ifndef BUILT_LIBC
$(error Build the C library by executing $(LIBC_PATH)/build_newlib.sh)
endif

View File

@ -1,285 +0,0 @@
Intel Galileo Board
===================
This README file contains general information about the Intel Galileo board
support. In the following lines you will find information about supported
features as well as instructions on how to build, run and debug applications
for this platform. The instructions were only test in Linux environment.
Requirements
------------
In order to build and debug the following packages must be installed in your
system:
* gcc
* gdb
* openocd
Moreover, in order to debug via JTAG or serial console, you will some extra
devices as described in [1] and [2].
Features
--------
This section presents the features currently supported (e.g. device drivers
and Contiki APIs) by the Galileo port.
Device drivers:
* Programmable Interrupt Controller (PIC)
* Programmable Intergal Timer (PIT)
* Real-Time Clock (RTC)
* UART
* Ethernet
* I2C
* GPIO (default pinmux configuration is listed in
platform/galileo/drivers/galileo-pinmux.c)
* Intel Quark X1000 SoC message bus
* Isolated Memory Regions (IMRs)
Contiki APIs:
* Clock module
* Timer, Stimer, Etimer, Ctimer, and Rtimer libraries
Standard APIs:
* Stdio library (stdout and stderr only). Console output through UART 1
device (connected to Galileo Gen2 FTDI header)
Optional support for protection domains is also implemented and is
described in cpu/x86/mm/README.md.
Preparation
-----------
Prerequisites on all Ubuntu Linux systems include texinfo and uuid-dev.
Additional prerequisites on 64-bit Ubuntu Linux systems include
gcc-multilib and g++-multilib.
Docker can optionally be used to prepare an Ubuntu-based, containerized build
environment. This has been tested with Docker installed on Microsoft Windows 10.
If not using a containerized environment, proceed to the "Building" section
below.
Using a Docker-based environment on Windows requires that the repository has
been checked out with Git configured to preserve UNIX-style line endings. This
can be accomplished by changing the 'core.autocrlf' setting prior to cloning
the repository [5]:
```
git config --global core.autocrlf input
```
Note that this is a global setting, so it may affect other Git operations.
The drive containing the repository needs to be shared with Docker containers
for the following steps to work [6]. Note that this is a global setting that
affects other containers that may be present on the host.
Open Microsoft PowerShell and navigate to the base directory of the repository.
Run the following command to create the build environment:
```
docker build -t contiki-galileo-build platform/galileo/bsp/docker
```
This creates a container named 'contiki-galileo-build' based on Ubuntu and
installs development tools in the container.
The build commands shown below can be run within the newly-created container. To
obtain a shell, run the following command in PowerShell from the base directory
of the repository.
```
docker run -t -i -v ${Pwd}:/contiki contiki-galileo-build
```
This command mounts the current directory and its subdirectories at the path
'/contiki' within the container. Changes to those files in the container are
visible to the host and vice versa. However, changes to the container
filesystem are not automatically persisted when the container is stopped.
The containerized build environment does not currently support building the Grub
bootloader nor debugging using the instructions in this document.
See the Docker Overview for more information about working with containers [7].
Building
--------
To build applications for this platform you should first build newlib (in
case it wasn't already built). To build newlib you can run the following
command:
```
$ ./platform/galileo/bsp/libc/build_newlib.sh
```
Once newlib is built, you are ready to build applications. By default, the
following steps will use gcc as the C compiler and to invoke the linker. To
use LLVM clang instead, change the values for both the CC and LD variables in
cpu/x86/Makefile.x86_common to 'clang'.
To build applications for the Galileo platform you should set the TARGET
variable to 'galileo'. For instance, building the hello-world application
should look like this:
```
$ cd examples/hello-world/ && make TARGET=galileo
```
This will generate the 'hello-world.galileo' file which is a multiboot-
compliant [3] ELF image. This image contains debugging information and it
should be used in your daily development.
You can also build a "Release" image by setting the BUILD_RELEASE variable to
1. This will generate a Contiki stripped-image optimized for size.
```
$ cd examples/hello-world/ && make TARGET=galileo BUILD_RELEASE=1
```
To also generate an '<application>.galileo.efi' file which is a UEFI [4] image,
you can run the following command prior to building applications:
```
$ cpu/x86/uefi/build_uefi.sh
```
To restrict DMA so that peripherals are blocked from accessing memory
regions that do not contain any data that needs to be DMA-accessible,
specify X86_CONF_RESTRICT_DMA=1 as a command-line argument to the make
command that is used to build the image. This will configure and lock
the IMRs.
Galileo Gen. 2 is targeted by default. Specify GALILEO_GEN=1 on the build
command line to target first generation boards.
Running
-------
You will need a multiboot-compliant bootloader to boot Contiki images in that
format. However, this is not needed for booting UEFI images.
In the bsp directory, we provide a helper script which builds the Grub
bootloader with multiboot support. To build the bootloader, just run the
following command:
```
$ platform/galileo/bsp/grub/build_grub.sh
```
Once Grub is built, we have three main steps to run Contiki applications:
prepare SDcard, connect to console, and boot image. Below follows
detailed instructions.
### Prepare SDcard
The instructions in this section are for a native Linux development environment,
so equivalent operations should be substituted when using some other environment
(e.g. Windows Explorer can be used to perform equivalent operations when using
Docker on Windows as a development environment).
Mount the sdcard in directory /mnt/sdcard.
Create UEFI boot directory:
```
$ mkdir -p /mnt/sdcard/efi/boot
```
#### Approach for Multiboot-compliant ELF Image
Copy Contiki binary image to sdcard
```
$ cp examples/hello-world/hello-world.galileo /mnt/sdcard
```
Copy grub binary to sdcard
```
$ cp platform/galileo/bsp/grub/bin/grub.efi /mnt/sdcard/efi/boot/bootia32.efi
```
#### Approach for UEFI Image
Copy Contiki binary image to sdcard:
```
$ cp examples/hello-world/hello-world.galileo.efi /mnt/sdcard/efi/boot/bootia32.efi
```
### Connect to the console output
Connect the serial cable to your computer as shown in [8] for first generation
boards and [2] for second generation boards.
Choose a terminal emulator such as PuTTY. Make sure you use the SCO keyboard
mode (on PuTTY that option is at Terminal -> Keyboard, on the left menu).
Connect to the appropriate serial port using a baud rate of 115200.
### Boot Contiki Image
Turn on your board. After a few seconds you should see the following text
in the screen:
```
Press [Enter] to directly boot.
Press [F7] to show boot menu options.
```
Waiting for the system to select the default boot device may be sufficient.
However, if this does not boot Contiki or Grub (depending on what is installed
as the UEFI boot image) then perform the following procedure after rebooting
and waiting for the boot message to appear: Press <F7> and select the option
"UEFI Misc Device" within the menu.
No additional steps should be required to boot a Contiki UEFI image.
Run the following additional commands to boot a multiboot-compliant image:
```
$ multiboot /hello-world.galileo
$ boot
```
### Verify that Contiki is Running
This should boot the Contiki image, resulting in the following messages being
sent to the serial console:
```
Starting Contiki
Hello, world
```
Debugging
---------
This section describes how to debug Contiki via JTAG. The following
instructions consider you have the devices: Flyswatter2 and ARM-JTAG-20-10
adapter (see [1]).
Attach the Flyswatter2 to your host computer with an USB cable. Connect the
Flyswatter2 and ARM-JTAG-20-10 adapter using the 20-pins head. Connect the
ARM-JTAG-20-10 adapter to Galileo Gen2 JTAG port using the 10-pins head.
Once everything is connected, run Contiki as described in "Running" section,
but right after loading Contiki image (multiboot command), run the following
command:
```
$ make TARGET=galileo debug
```
The 'debug' rule will run OpenOCD and gdb with the right parameters. OpenOCD
will run in background and its output will be redirected to a log file in the
application's path called LOG_OPENOCD. Once gdb client is detached, OpenOCD
is terminated.
If you use a gdb front-end, you can define the "GDB" environment
variable and your gdb front-end will be used instead of default gdb.
For instance, if you want to use cgdb front-end, just run the command:
```
$ make BOARD=galileo debug GDB=cgdb
```
References
----------
[1] https://communities.intel.com/message/211778
[2] https://software.intel.com/en-us/articles/intel-galileo-gen-2-board-assembly-using-eclipse-and-intel-xdk-iot-edition
[3] https://www.gnu.org/software/grub/manual/multiboot/multiboot.html
[4] http://www.uefi.org/
[5] https://www.git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
[6] https://docs.docker.com/docker-for-windows/#/shared-drives
[7] https://docs.docker.com/engine/understanding-docker/
[8] https://software.intel.com/en-us/articles/intel-galileo-gen-1-board-assembly-using-eclipse-and-intel-xdk-iot-edition

View File

@ -1,8 +0,0 @@
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y \
gcc-multilib g++-multilib git make patch texinfo uuid-dev wget \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /contiki
ENV TARGET galileo
CMD ["/bin/bash", "-l"]

View File

@ -1,60 +0,0 @@
#!/bin/bash
set -e
JOBS=5
HEAD="bac5d1a64ab4191058a8fd4c05f6b3b339e249e7"
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
prepare() {
if [[ ! -d ./src ]]; then
git clone git://git.savannah.gnu.org/grub.git src
fi
pushd src
git checkout $HEAD
git clean -fdx
popd
}
build() {
pushd src
./autogen.sh
./configure --with-platform=efi --target=i386
make -j${JOBS}
./grub-mkimage -p /EFI/BOOT -d ./grub-core/ -O i386-efi -o grub.efi \
boot efifwsetup efi_gop efinet efi_uga lsefimmap lsefi lsefisystab \
exfat fat multiboot2 multiboot terminal part_msdos part_gpt normal \
all_video aout configfile echo file fixvideo fshelp gfxterm gfxmenu \
gfxterm_background gfxterm_menu legacycfg video_bochs video_cirrus \
video_colors video_fb videoinfo video
popd
}
setup() {
mkdir -p bin
cp src/grub.efi bin/
}
cleanup() {
rm -rf ./src
rm -rf ./bin
}
# This script will always run on its own basepath, no matter where you call it from.
pushd ${SCRIPT_DIR}
case $1 in
-c | --cleanup)
cleanup
;;
*)
prepare && build && setup
;;
esac
popd

View File

@ -1,119 +0,0 @@
#!/bin/bash
set -e
JOBS=5
TARGET=i586-elf
VERSION=2.2.0-1
MD5=94114fdc1d8391cdbc2653d89249cccf
PKG_NAME=newlib
SRC_DIR=${PKG_NAME}-${VERSION}
PATCH_DIR=../patches
TARBALL=${SRC_DIR}.tar.gz
DIST_SITE=ftp://sources.redhat.com/pub/newlib
SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
# This script will always run on its own basepath, no matter where you call it from.
pushd ${SCRIPT_DIR}
prepare() {
# If the source tarball doesn't exist of its md5 checksum doesn't match, download it.
if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then
wget -c ${DIST_SITE}/${TARBALL}
fi
if [ ! -e ./${TARBALL} ] || [ "$(md5sum ./${TARBALL} | cut -d' ' -f1)" != $MD5 ]; then
echo "Error obtaining tarball."
exit 1
fi
# Clean up the previous source dir, if any.
if [[ -d ./${SRC_DIR} ]]; then
rm -rf ./${SRC_DIR}
fi
# Clean up the previous install dir, if any.
if [[ -d ./${TARGET} ]]; then
rm -rf ./${TARGET}
fi
tar xf ${TARBALL}
cd ${SRC_DIR}
for i in `ls ${PATCH_DIR}/*.patch`; do patch -p0 < ${i}; done
}
build() {
export AR_FOR_TARGET=ar
export AS_FOR_TARGET=as
export CC_FOR_TARGET=cc
export GCC_FOR_TARGET=gcc
export CXX_FOR_TARGET=c++
export RAW_CXX_FOR_TARGET=c++
export GCJ_FOR_TARGET=gcj
export GFORTRAN_FOR_TARGET=gfortran
export GOC_FOR_TARGET=gccgo
export DLLTOOL_FOR_TARGET=dlltool
export LD_FOR_TARGET=ld
export LIPO_FOR_TARGET=lipo
export NM_FOR_TARGET=nm
export OBJDUMP_FOR_TARGET=objdump
export RANLIB_FOR_TARGET=ranlib
export READELF_FOR_TARGET=readelf
export STRIP_FOR_TARGET=strip
export WINDRES_FOR_TARGET=windres
export WINDMC_FOR_TARGET=windmc
export COMPILER_AS_FOR_TARGET=as
export COMPILER_LD_FOR_TARGET=ld
export COMPILER_NM_FOR_TARGET=nm
export CFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables"
export CXXFLAGS_FOR_TARGET="-Os -m32 -march=i586 -mtune=i586 -fno-stack-protector -DPREFER_SIZE_OVER_SPEED -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-unwind-tables"
mkdir -p install
./configure --target=${TARGET} \
--prefix=`pwd`/install \
--enable-newlib-nano-formatted-io \
--enable-newlib-nano-malloc \
--enable-multithread \
--disable-newlib-fvwrite-in-streamio \
--disable-newlib-fseek-optimization \
--disable-newlib-wide-orient \
--disable-newlib-unbuf-stream-opt \
--disable-libstdcxx \
--disable-multilib \
--disable-newlib-mb \
--disable-newlib-supplied-syscalls
make -j${JOBS} all && make install
cd ..
echo "BUILT_LIBC = newlib" > Makefile.libc
}
setup() {
cp -r ./${SRC_DIR}/install/${TARGET} .
}
cleanup() {
rm -rf ./${SRC_DIR}*
}
# By default we always call prepare, build and setup.
prepare
build
setup
# But we only cleanup if -c is used.
case $1 in
-c | --cleanup)
cleanup
shift
;;
*)
# unknown option
;;
esac
popd

View File

@ -1,11 +0,0 @@
--- newlib/libc/include/sys/config.h 2015-01-14 07:25:15.000000000 -0200
+++ newlib/libc/include/sys/config.h 2015-03-13 14:21:33.247980336 -0300
@@ -94,9 +94,6 @@
#define HAVE_GETDATE
#define _HAVE_SYSTYPES
#define _READ_WRITE_RETURN_TYPE _ssize_t
-#define __LARGE64_FILES 1
-/* we use some glibc header files so turn on glibc large file feature */
-#define _LARGEFILE64_SOURCE 1
#endif
#endif

View File

@ -1,13 +0,0 @@
--- newlib/configure.host 2015-03-12 17:59:39.380318464 -0300
+++ newlib/configure.host 2015-03-12 17:55:05.933645678 -0300
@@ -810,6 +810,10 @@
z8k-*-*)
syscall_dir=syscalls
;;
+ i586-*-elf)
+ newlib_cflags="${newlib_cflags} -DREENTRANT_SYSCALLS_PROVIDED"
+ syscall_dir=syscalls
+ ;;
*)
newlib_cflags="${newlib_cflags} -DMISSING_SYSCALL_NAMES"
syscall_dir=

View File

@ -1,19 +0,0 @@
--- newlib/libc/stdio/nano-vfprintf_local.h 2014-07-04 10:21:43.000000000 -0700
+++ newlib/libc/stdio/nano-vfprintf_local.h 2015-07-17 12:51:12.974269921 -0700
@@ -230,5 +230,5 @@ _printf_float (struct _reent *data,
FILE *fp,
int (*pfunc)(struct _reent *, FILE *,
_CONST char *, size_t len),
- va_list *ap) _ATTRIBUTE((__weak__));
+ va_list *ap);
#endif
--- newlib/libc/stdio/nano-vfscanf_local.h 2014-07-04 10:21:44.000000000 -0700
+++ newlib/libc/stdio/nano-vfscanf_local.h 2015-07-17 12:51:33.967362409 -0700
@@ -173,6 +173,6 @@ _scanf_i (struct _reent *rptr,
extern int
_scanf_float (struct _reent *rptr,
struct _scan_data_t *pdata,
- FILE *fp, va_list *ap) _ATTRIBUTE((__weak__));
+ FILE *fp, va_list *ap);
#endif

View File

@ -1,11 +0,0 @@
source [find interface/ftdi/flyswatter2.cfg];
source [find board/quark_x10xx_board.cfg];
quark_x10xx.cpu configure -event gdb-attach {
halt
}
quark_x10xx.cpu configure -event gdb-detach {
resume
shutdown
}

View File

@ -1,64 +0,0 @@
/*
* Copyright (C) 2015, 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 CONTIKI_CONF_H
#define CONTIKI_CONF_H
/* Include the default configuration file early here so that this file can
* unconfigure the IP buffer size. That will allow uipopt.h to define a
* default IP buffer size that is larger and more useful.
*/
#include "contiki-default-conf.h"
#undef UIP_CONF_BUFFER_SIZE
#include <inttypes.h>
#define CLOCK_CONF_SECOND 128
typedef unsigned long clock_time_t;
typedef uint64_t rtimer_clock_t;
#define RTIMER_ARCH_SECOND 1024
#define RTIMER_CLOCK_DIFF(a, b) ((int64_t)((a) - (b)))
/* We define the following macros and types otherwise Contiki does not
* compile.
*/
#define CCIF
#define CLIF
#define UIP_CONF_LLH_LEN 14
#define UIP_CONF_LL_802154 0
#define LINKADDR_CONF_SIZE 6
typedef unsigned short uip_stats_t;
#endif /* CONTIKI_CONF_H */

View File

@ -1,138 +0,0 @@
/*
* 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 <stdio.h>
#include "contiki.h"
#include "contiki-net.h"
#include "cpu.h"
#include "eth.h"
#include "eth-conf.h"
#include "galileo-pinmux.h"
#include "gpio.h"
#include "helpers.h"
#include "i2c.h"
#include "imr-conf.h"
#include "interrupt.h"
#include "irq.h"
#include "pci.h"
#include "prot-domains.h"
#include "shared-isr.h"
#include "uart.h"
PROCINIT( &etimer_process
, &tcpip_process
#if WITH_DNS
, &resolv_process
#endif
);
extern int _sdata_kern_startup_func, _edata_kern_startup_func;
/*---------------------------------------------------------------------------*/
void
app_main(void)
{
printf("Starting Contiki\n");
process_init();
procinit_init();
ctimer_init();
eth_init();
autostart_start(autostart_processes);
while(1) {
process_run();
}
halt();
}
/*---------------------------------------------------------------------------*/
static void
gp_fault_handler(struct interrupt_context context)
{
fprintf(stderr, "General protection exception @%08x (ec: %u)\n",
context.eip, context.error_code);
halt();
}
/*---------------------------------------------------------------------------*/
/* Kernel entrypoint */
int
main(void)
{
uintptr_t *func_ptr;
#ifdef X86_CONF_RESTRICT_DMA
quarkX1000_imr_conf();
#endif
irq_init();
quarkX1000_uart_init();
/* Initialize UART connected to Galileo Gen1 3.5mm audio-style jack or
* Galileo Gen2 FTDI header
*/
quarkX1000_uart_init_port(QUARK_X1000_UART_1, 115200);
SET_EXCEPTION_HANDLER(13, 1, gp_fault_handler);
clock_init();
rtimer_init();
pci_root_complex_init();
quarkX1000_eth_init();
quarkX1000_i2c_init();
quarkX1000_i2c_configure(QUARKX1000_I2C_SPEED_STANDARD,
QUARKX1000_I2C_ADDR_MODE_7BIT);
/* The GPIO subsystem must be initialized prior to configuring pinmux, because
* the pinmux configuration automatically performs GPIO configuration for the
* relevant pins.
*/
quarkX1000_gpio_init();
/* use default pinmux configuration */
if(galileo_pinmux_initialize() < 0) {
fprintf(stderr, "Failed to initialize pinmux\n");
}
shared_isr_init();
/* The ability to remap interrupts is not needed after this point and should
* thus be disabled according to the principle of least privilege.
*/
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;
}
/*---------------------------------------------------------------------------*/

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 2015, 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 "sys/clock.h"
#include "sys/etimer.h"
#include "contiki-conf.h"
#include "drivers/legacy_pc/rtc.h"
#if CLOCK_CONF_SECOND == 2
#define FREQ RTC_2_HZ
#elif CLOCK_CONF_SECOND == 4
#define FREQ RTC_4_HZ
#elif CLOCK_CONF_SECOND == 8
#define FREQ RTC_8_HZ
#elif CLOCK_CONF_SECOND == 16
#define FREQ RTC_16_HZ
#elif CLOCK_CONF_SECOND == 32
#define FREQ RTC_32_HZ
#elif CLOCK_CONF_SECOND == 64
#define FREQ RTC_64_HZ
#elif CLOCK_CONF_SECOND == 128
#define FREQ RTC_128_HZ
#elif CLOCK_CONF_SECOND == 256
#define FREQ RTC_256_HZ
#elif CLOCK_CONF_SECOND == 512
#define FREQ RTC_512_HZ
#elif CLOCK_CONF_SECOND == 1024
#define FREQ RTC_1024_HZ
#elif CLOCK_CONF_SECOND == 2048
#define FREQ RTC_2048_HZ
#elif CLOCK_CONF_SECOND == 4096
#define FREQ RTC_4096_HZ
#elif CLOCK_CONF_SECOND == 8192
#define FREQ RTC_8192_HZ
#else
#define FREQ -1
#error "RTC is being used thus CLOCK_CONF_SECOND has to be a value defined by rtc_frequency_t."
#endif
static volatile clock_time_t tick_count = 0;
static void
update_ticks(void)
{
clock_time_t expire = etimer_next_expiration_time();
tick_count++;
/* Notify etimer library if the next event timer has expired */
if(expire != 0 && tick_count >= expire) {
etimer_request_poll();
}
}
/*---------------------------------------------------------------------------*/
void
clock_init(void)
{
rtc_init(FREQ, update_ticks);
}
/*---------------------------------------------------------------------------*/
clock_time_t
clock_time(void)
{
return tick_count;
}
/*---------------------------------------------------------------------------*/
unsigned long
clock_seconds(void)
{
return tick_count / CLOCK_CONF_SECOND;
}
/*---------------------------------------------------------------------------*/
void
clock_wait(clock_time_t t)
{
clock_time_t initial = tick_count;
while(tick_count < t + initial);
}
/*---------------------------------------------------------------------------*/
void
clock_set_seconds(unsigned long sec)
{
/* Stubbed function */
}
/*---------------------------------------------------------------------------*/
void
clock_delay_usec(uint16_t t)
{
/* Stubbed function */
}

View File

@ -1,37 +0,0 @@
/*
* Copyright (C) 2015, 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 MTARCH_H_
#define MTARCH_H_
struct mtarch_thread {
};
#endif /* MTARCH_H_ */

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2015, 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 "sys/rtimer.h"
#include "contiki-conf.h"
#include "drivers/legacy_pc/pit.h"
static volatile rtimer_clock_t tick_count = 0;
static rtimer_clock_t trigger = UINT64_MAX;
static void
update_ticks(void)
{
if(++tick_count >= trigger) {
/* Disable trigger by assigning it to the maximum value */
trigger = UINT64_MAX;
rtimer_run_next();
}
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_init(void)
{
pit_init(RTIMER_ARCH_SECOND, update_ticks);
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
rtimer_arch_now()
{
return tick_count;
}
/*---------------------------------------------------------------------------*/
void
rtimer_arch_schedule(rtimer_clock_t t)
{
trigger = t;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2015, 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 RTIMER_ARCH_H
#define RTIMER_ARCH_H
rtimer_clock_t rtimer_arch_now();
#endif /* RTIMER_ARCH_H */

View File

@ -1,131 +0,0 @@
/*
* 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.
*/
#include "cy8c9540a.h"
#include <assert.h>
#include "i2c.h"
#include <stdio.h>
/* Change this to 0x21 if J2 is set to 1-2
* (covering the pin marked with the white triangle). */
#define I2C_ADDR 0x20
#define REG_PORT_SEL 0x18
#define REG_PORT_DIR 0x1C
#define PORT_CNT 6
/* Cache the current state of each port to obviate the need for reading before
* writing to output ports when simply updating a single pin.
*/
static uint8_t out_cache[PORT_CNT];
/*---------------------------------------------------------------------------*/
static void
write_reg(uint8_t reg, uint8_t data)
{
uint8_t pkt[] = { reg, data };
assert(quarkX1000_i2c_polling_write(pkt, sizeof(pkt), I2C_ADDR) == 0);
}
/*---------------------------------------------------------------------------*/
static uint8_t
read_reg(uint8_t reg)
{
uint8_t data;
assert(quarkX1000_i2c_polling_write(&reg, 1, I2C_ADDR) == 0);
assert(quarkX1000_i2c_polling_read(&data, 1, I2C_ADDR) == 0);
return data;
}
/*---------------------------------------------------------------------------*/
void
cy8c9540a_init(void)
{
uint8_t status;
/* has to init after I2C master */
assert(quarkX1000_i2c_is_available());
status = read_reg(0x2E);
if((status >> 4) != 4) {
fprintf(stderr, "Failed to communicate with CY8C9540A. Perhaps jumper J2 "
"is not set to 2-3? Halting.\n");
halt();
}
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set the direction (in or out) for the indicated GPIO pin.
*/
void
cy8c9540a_set_port_dir(cy8c9540a_bit_addr_t addr, cy8c9540a_port_dir_t dir)
{
uint8_t mask;
assert(addr.port < PORT_CNT);
write_reg(REG_PORT_SEL, addr.port);
mask = read_reg(REG_PORT_DIR);
mask &= ~(1 << addr.pin);
mask |= ((uint8_t)dir) << addr.pin;
write_reg(REG_PORT_DIR, mask);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Set the drive mode for the indicated GPIO pin.
*/
void
cy8c9540a_set_drive_mode(cy8c9540a_bit_addr_t addr,
cy8c9540a_drive_mode_t drv_mode)
{
assert(addr.port < PORT_CNT);
write_reg(REG_PORT_SEL, addr.port);
write_reg((uint8_t)drv_mode, 1 << addr.pin);
}
/*---------------------------------------------------------------------------*/
bool
cy8c9540a_read(cy8c9540a_bit_addr_t addr)
{
assert(addr.port < PORT_CNT);
return ((read_reg(addr.port) >> addr.pin) & 1) == 1;
}
/*---------------------------------------------------------------------------*/
void
cy8c9540a_write(cy8c9540a_bit_addr_t addr, bool val)
{
assert(addr.port < PORT_CNT);
out_cache[addr.port] &= ~(1 << addr.pin);
out_cache[addr.port] |= ((uint8_t)val) << addr.pin;
write_reg(8 + addr.port, out_cache[addr.port]);
}
/*---------------------------------------------------------------------------*/

View File

@ -1,72 +0,0 @@
/*
* 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 PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_
#define PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_
#include <stdbool.h>
#include <stdint.h>
/* Driver for Cypress Semiconductors CY8C9540A device used for GPIO, PWM, and
* pinmuxing on the first generation Intel Galileo.
*/
/* The numeric value of each drive mode corresponds to the device register
* address for selecting that mode. Only a subset of the available modes are
* listed here.
*/
typedef enum cy8c9540a_drive_mode {
CY8C9540A_DRIVE_PULL_UP = 0x1D,
CY8C9540A_DRIVE_PULL_DOWN = 0x1E,
CY8C9540A_DRIVE_STRONG = 0x21,
CY8C9540A_DRIVE_HI_Z = 0x23
} cy8c9540a_drive_mode_t;
typedef enum cy8c9540a_port_dir {
CY8C9540A_PORT_DIR_OUT = 0,
CY8C9540A_PORT_DIR_IN = 1
} cy8c9540a_port_dir_t;
typedef struct cy8c9540a_bit_addr {
uint8_t port;
int pin;
} cy8c9540a_bit_addr_t;
#define CY8C9540A_BIT_ADDR_INVALID_PORT 0xFF
void cy8c9540a_init(void);
void cy8c9540a_set_port_dir(cy8c9540a_bit_addr_t addr,
cy8c9540a_port_dir_t dir);
void cy8c9540a_set_drive_mode(cy8c9540a_bit_addr_t addr,
cy8c9540a_drive_mode_t drv_mode);
bool cy8c9540a_read(cy8c9540a_bit_addr_t addr);
void cy8c9540a_write(cy8c9540a_bit_addr_t addr, bool val);
#endif /* PLATFORM_GALILEO_DRIVERS_CY8C9540A_H_ */

View File

@ -1,282 +0,0 @@
/*
* 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.
*/
#include "galileo-pinmux.h"
#include <assert.h>
#include "cy8c9540a.h"
#include "gpio.h"
#include <stdio.h>
static cy8c9540a_bit_addr_t mux_bit_addrs[] = {
{ 3, 4 }, /* IO0 */
{ 3, 5 }, /* IO1 */
{ 1, 7 }, /* IO2 */
{ 1, 6 }, /* IO3 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO4 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO5 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO6 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO7 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO8 */
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 }, /* IO9 */
{ 3, 6 }, /* IO10 */
{ 3, 7 }, /* IO11 */
{ 5, 2 }, /* IO12 */
{ 5, 3 }, /* IO13 */
{ 3, 1 }, /* A0 */
{ 3, 0 }, /* A1 */
{ 0, 7 }, /* A2 */
{ 0, 6 }, /* A3 */
{ 0, 5 }, /* A4 (also controlled by I2C mux) */
{ 0, 4 }, /* A5 (also controlled by I2C mux) */
};
static cy8c9540a_bit_addr_t i2c_mux_bit_addr = { 1, 5 };
/*---------------------------------------------------------------------------*/
static void
flatten_pin_num(galileo_pin_group_t grp, unsigned *pin)
{
if(grp == GALILEO_PIN_GRP_ANALOG) {
*pin += GALILEO_NUM_DIGITAL_PINS;
}
assert(*pin < GALILEO_NUM_PINS);
}
/*---------------------------------------------------------------------------*/
/* See galileo-gpio.c for the declaration of this function. */
int
galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus)
{
assert(pin < GALILEO_NUM_PINS);
*sus = false;
switch(pin) {
case 2:
return 6;
case 3:
return 7;
case 10:
return 2;
default:
return -1; /* GPIO pin may be connected to the CY8C9540A chip, but not the
CPU. */
}
}
/*---------------------------------------------------------------------------*/
static cy8c9540a_bit_addr_t cy8c9540a_gpio_mapping[] = {
{ 4, 6 },
{ 4, 7 },
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 },
{ CY8C9540A_BIT_ADDR_INVALID_PORT, 0 },
{ 1, 4 },
{ 0, 1 },
{ 1, 0 },
{ 1, 3 },
{ 1, 2 },
{ 0, 3 },
{ 0, 0 }, /* This driver configures IO10 to connect to CPU GPIO when setting
IO10 to a digital mode, but hardware exists to alternately
connect it to this pin of the CY8C9540A chip. */
{ 1, 1 },
{ 3, 2 },
{ 3, 3 },
{ 4, 0 },
{ 4, 1 },
{ 4, 2 },
{ 4, 3 },
{ 4, 4 },
{ 4, 5 }
};
/* Map a board-level GPIO pin number to the address of the CY8C9540A pin that
* implements it.
*/
cy8c9540a_bit_addr_t
galileo_brd_to_cy8c9540a_gpio_pin(unsigned pin)
{
assert(pin < GALILEO_NUM_PINS);
return cy8c9540a_gpio_mapping[pin];
}
/*---------------------------------------------------------------------------*/
/* The I2C mux control must be set high to be able to access A4 and A5.
*/
static void
set_i2c_mux(bool val)
{
cy8c9540a_write(i2c_mux_bit_addr, val);
}
/*---------------------------------------------------------------------------*/
static void
select_gpio_pwm(unsigned flat_pin, bool pwm)
{
bool mux_val;
cy8c9540a_bit_addr_t mux_bit_addr;
mux_bit_addr = mux_bit_addrs[flat_pin];
if(mux_bit_addr.port != CY8C9540A_BIT_ADDR_INVALID_PORT) {
mux_val = pwm || !(flat_pin == 2 || flat_pin == 3 || flat_pin == 10);
cy8c9540a_write(mux_bit_addr, mux_val);
}
if((GALILEO_NUM_DIGITAL_PINS + 4) <= flat_pin) {
/* This single control switches away from both I2C pins. */
set_i2c_mux(true);
}
}
/*---------------------------------------------------------------------------*/
static void
select_gpio(galileo_pin_group_t grp, unsigned pin, bool out)
{
bool sus;
int cpu_pin;
cy8c9540a_bit_addr_t gpio_bit_addr;
flatten_pin_num(grp, &pin);
select_gpio_pwm(pin, false);
cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus);
if(cpu_pin == -1) {
gpio_bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin);
cy8c9540a_set_port_dir(gpio_bit_addr,
out?
CY8C9540A_PORT_DIR_OUT :
CY8C9540A_PORT_DIR_IN);
cy8c9540a_set_drive_mode(gpio_bit_addr,
out?
CY8C9540A_DRIVE_STRONG :
CY8C9540A_DRIVE_HI_Z);
} else {
quarkX1000_gpio_config(cpu_pin,
out? QUARKX1000_GPIO_OUT : QUARKX1000_GPIO_IN);
}
}
/*---------------------------------------------------------------------------*/
void
galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin)
{
select_gpio(grp, pin, false);
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin)
{
select_gpio(grp, pin, true);
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_pwm(unsigned pin)
{
switch(pin) {
case 3:
case 5:
case 6:
case 9:
case 10:
case 11:
break;
default:
fprintf(stderr, "%s: invalid pin: %d.\n", __FUNCTION__, pin);
halt();
}
select_gpio_pwm(pin, true);
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_serial(unsigned pin)
{
assert(pin == 0 || pin == 1);
cy8c9540a_write(mux_bit_addrs[pin], false);
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_i2c(void)
{
set_i2c_mux(false);
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_spi(void)
{
unsigned pin;
for(pin = 11; pin <= 13; pin++) {
cy8c9540a_write(mux_bit_addrs[pin], false);
}
}
/*---------------------------------------------------------------------------*/
void galileo_pinmux_select_analog(unsigned pin)
{
assert(pin < GALILEO_NUM_ANALOG_PINS);
pin += GALILEO_NUM_DIGITAL_PINS;
cy8c9540a_write(mux_bit_addrs[pin], false);
if(4 <= pin) {
/* This single control switches away from both I2C pins. */
set_i2c_mux(true);
}
}
/*---------------------------------------------------------------------------*/
int
galileo_pinmux_initialize(void)
{
int i;
cy8c9540a_init();
/* Configure all mux control pins as outputs. */
for(i = 0; i < GALILEO_NUM_PINS; i++) {
if(mux_bit_addrs[i].port == CY8C9540A_BIT_ADDR_INVALID_PORT) {
continue;
}
cy8c9540a_set_port_dir(mux_bit_addrs[i], CY8C9540A_PORT_DIR_OUT);
cy8c9540a_set_drive_mode(mux_bit_addrs[i], CY8C9540A_DRIVE_STRONG);
}
cy8c9540a_set_port_dir(i2c_mux_bit_addr, CY8C9540A_PORT_DIR_OUT);
cy8c9540a_set_drive_mode(i2c_mux_bit_addr, CY8C9540A_DRIVE_STRONG);
/* Activate default pinmux configuration. */
galileo_pinmux_select_serial(0);
galileo_pinmux_select_serial(1);
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 2);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 3);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 4);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 5);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 6);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 7);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 8);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 9);
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 10);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 11);
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 12);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 13);
galileo_pinmux_select_analog(0);
galileo_pinmux_select_analog(1);
galileo_pinmux_select_analog(2);
galileo_pinmux_select_analog(3);
galileo_pinmux_select_i2c();
return 0;
}
/*---------------------------------------------------------------------------*/

View File

@ -1,724 +0,0 @@
/*
* 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 "galileo-pinmux.h"
#include <assert.h>
#include "gpio.h"
#include "gpio-pcal9535a.h"
#include "i2c.h"
#include "pwm-pca9685.h"
#include <stdio.h>
typedef enum {
GALILEO_PINMUX_FUNC_A,
GALILEO_PINMUX_FUNC_B,
GALILEO_PINMUX_FUNC_C,
GALILEO_PINMUX_FUNC_D
} GALILEO_PINMUX_FUNC;
#define GPIO_PCAL9535A_0_I2C_ADDR 0x25
#define GPIO_PCAL9535A_1_I2C_ADDR 0x26
#define GPIO_PCAL9535A_2_I2C_ADDR 0x27
#define PWM_PCA9685_0_I2C_ADDR 0x47
#define PINMUX_NUM_FUNCS 4
#define PINMUX_NUM_PATHS 4
typedef enum {
NONE,
EXP0,
EXP1,
EXP2,
PWM0
} MUX_CHIP;
typedef enum {
PIN_LOW = 0x00,
PIN_HIGH = 0x01,
DISABLED = 0xFF
} PIN_LEVEL;
struct pin_config {
uint8_t pin_num;
GALILEO_PINMUX_FUNC func;
};
struct mux_pin {
MUX_CHIP chip;
uint8_t pin;
PIN_LEVEL level;
uint32_t cfg;
};
struct mux_path {
uint8_t io_pin;
GALILEO_PINMUX_FUNC func;
struct mux_pin path[PINMUX_NUM_PATHS];
};
struct pinmux_internal_data {
struct gpio_pcal9535a_data exp0;
struct gpio_pcal9535a_data exp1;
struct gpio_pcal9535a_data exp2;
struct pwm_pca9685_data pwm0;
};
static struct pinmux_internal_data data;
static struct mux_path galileo_pinmux_paths[GALILEO_NUM_PINS * PINMUX_NUM_FUNCS] = {
{0, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO3 out */
{ EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{0, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO3 in */
{ EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{0, GALILEO_PINMUX_FUNC_C, {
{ EXP1, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART0_RXD */
{ EXP1, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{0, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{1, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO4 out */
{ EXP0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{1, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO4 in */
{ EXP0, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT)},
{ EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{1, GALILEO_PINMUX_FUNC_C, {
{ EXP1, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT)}, /* UART0_TXD */
{ EXP0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{1, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{2, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO5 out */
{ EXP1, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP1, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{2, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 13, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO5 in */
{ EXP1, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP1, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{2, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 13, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART1_RXD */
{ EXP1, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP1, 3, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{2, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{3, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO6 out */
{ PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{3, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO6 in */
{ PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{3, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* UART1_TXD */
{ PWM0, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{3, GALILEO_PINMUX_FUNC_D, {
{ PWM0, 0, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED1 */
{ PWM0, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{4, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS4 out */
{ EXP1, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{4, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS4 in */
{ EXP1, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{4, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{4, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{5, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO8 (out) */
{ EXP0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{5, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO8 (in) */
{ EXP0, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{5, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 2, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED3 */
{ EXP0, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{5, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{6, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO9 (out) */
{ EXP0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{6, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO9 (in) */
{ EXP0, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{6, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 4, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED5 */
{ EXP0, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{6, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{7, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS0 (out) */
{ EXP1, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{7, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 6, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* GPIO_SUS0 (in) */
{ EXP1, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{7, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{7, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{8, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS1 (out) */
{ EXP1, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{8, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 8, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* GPIO_SUS1 (in) */
{ EXP1, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{8, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{8, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{9, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS2 (out) */
{ EXP0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{9, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS2 (in) */
{ EXP0, 6, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{9, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 6, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED7 */
{ EXP0, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{9, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{10, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO2 (out) */
{ EXP0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{10, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO2 (in) */
{ EXP0, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{10, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* PWM.LED11 */
{ EXP0, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{10, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{11, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS3 (out) */
{ PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{11, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS3 (in) */
{ PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 8, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{11, GALILEO_PINMUX_FUNC_C, {
{ EXP1, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* PWM.LED9 */
{ PWM0, 8, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{11, GALILEO_PINMUX_FUNC_D, {
{ EXP1, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* SPI1_MOSI */
{ PWM0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{12, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO7 (out) */
{ EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{12, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 10, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* GPIO7 (in) */
{ EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{12, GALILEO_PINMUX_FUNC_C, {
{ EXP1, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* SPI1_MISO */
{ EXP1, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{12, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{13, GALILEO_PINMUX_FUNC_A, {
{ EXP1, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS5 (out) */
{ EXP0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{13, GALILEO_PINMUX_FUNC_B, {
{ EXP1, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* GPIO_SUS5 (in) */
{ EXP0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{13, GALILEO_PINMUX_FUNC_C, {
{ EXP1, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* SPI1_CLK */
{ EXP0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{13, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{14, GALILEO_PINMUX_FUNC_A, {
{ EXP2, 0, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_0 (out)/ADC.IN0 */
{ EXP2, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{14, GALILEO_PINMUX_FUNC_B, {
{ EXP2, 0, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_0 (in)/ADC.IN0 */
{ EXP2, 1, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{14, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{14, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{15, GALILEO_PINMUX_FUNC_A, {
{ EXP2, 2, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_2 (out)/ADC.IN1 */
{ EXP2, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{15, GALILEO_PINMUX_FUNC_B, {
{ EXP2, 2, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_2 (in)/ADC.IN1 */
{ EXP2, 3, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{15, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{15, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{16, GALILEO_PINMUX_FUNC_A, {
{ EXP2, 4, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_4 (out)/ADC.IN2 */
{ EXP2, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{16, GALILEO_PINMUX_FUNC_B, {
{ EXP2, 4, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_4 (in)/ADC.IN2 */
{ EXP2, 5, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{16, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{16, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{17, GALILEO_PINMUX_FUNC_A, {
{ EXP2, 6, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P0_6 (out)/ADC.IN3 */
{ EXP2, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{17, GALILEO_PINMUX_FUNC_B, {
{ EXP2, 6, PIN_LOW, (QUARKX1000_GPIO_IN ) }, /* EXP2.P0_6 (in)/ADC.IN3 */
{ EXP2, 7, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{17, GALILEO_PINMUX_FUNC_C, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{17, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{18, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_0 (out)/ADC.IN4 */
{ EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP2, 8, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{18, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 14, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_0 (in)/ADC.IN4 */
{ EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP2, 8, PIN_LOW, (QUARKX1000_GPIO_IN ) },
{ EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{18, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 14, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* I2C SDA */
{ EXP2, 9, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP2, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{18, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{19, GALILEO_PINMUX_FUNC_A, {
{ PWM0, 15, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_2 (out)/ADC.IN5 */
{ EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP2, 10, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{19, GALILEO_PINMUX_FUNC_B, {
{ PWM0, 15, PIN_LOW, (QUARKX1000_GPIO_OUT) }, /* EXP2.P1_2 (in)/ADC.IN5 */
{ EXP2, 12, PIN_HIGH, (QUARKX1000_GPIO_OUT) },
{ EXP2, 10, PIN_LOW, (QUARKX1000_GPIO_IN ) },
{ EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) }}},
{19, GALILEO_PINMUX_FUNC_C, {
{ PWM0, 15, PIN_HIGH, (QUARKX1000_GPIO_OUT) }, /* I2C SCL */
{ EXP2, 11, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ EXP2, 12, PIN_LOW, (QUARKX1000_GPIO_OUT) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
{19, GALILEO_PINMUX_FUNC_D, {
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }, /* NONE */
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) },
{ NONE, 0, DISABLED, (QUARKX1000_GPIO_IN ) }}},
};
static int
galileo_pinmux_set_pin(uint8_t pin, GALILEO_PINMUX_FUNC func)
{
struct mux_path *mux_path;
uint8_t index, i;
if(pin >= GALILEO_NUM_PINS) {
return -1;
}
index = PINMUX_NUM_FUNCS * pin;
index += func;
mux_path = &galileo_pinmux_paths[index];
for(i = 0; i < PINMUX_NUM_PATHS; i++) {
struct gpio_pcal9535a_data *exp = NULL;
switch(mux_path->path[i].chip) {
case EXP0:
exp = &data.exp0;
break;
case EXP1:
exp = &data.exp1;
break;
case EXP2:
exp = &data.exp2;
break;
case PWM0:
if(pwm_pca9685_set_duty_cycle(&data.pwm0, mux_path->path[i].pin, mux_path->path[i].level ? 100 : 0) < 0) {
return -1;
}
continue;
case NONE:
continue;
}
assert(exp != NULL);
if(gpio_pcal9535a_write(exp, mux_path->path[i].pin, mux_path->path[i].level) < 0) {
return -1;
}
if(gpio_pcal9535a_config(exp, mux_path->path[i].pin, mux_path->path[i].cfg) < 0) {
return -1;
}
}
return 0;
}
static void
flatten_pin_num(galileo_pin_group_t grp, unsigned *pin)
{
if(grp == GALILEO_PIN_GRP_ANALOG) {
*pin += GALILEO_NUM_DIGITAL_PINS;
}
assert(*pin < GALILEO_NUM_PINS);
}
/* See galileo-gpio.c for the declaration of this function. */
int
galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus)
{
static const int SUS = 0x100;
unsigned pins[GALILEO_NUM_DIGITAL_PINS] = {
3, 4, 5, 6,
SUS | 4, 8, 9, SUS | 0,
SUS | 1, SUS | 2, 2, SUS | 3,
7, SUS | 5
};
int cpu_pin;
/* GPIOs in the analog pin space are implemented by EXP2, not the CPU. */
assert(pin < GALILEO_NUM_DIGITAL_PINS);
cpu_pin = pins[pin];
*sus = (cpu_pin & SUS) == SUS;
return cpu_pin & ~SUS;
}
void
galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin)
{
bool sus;
int cpu_pin;
flatten_pin_num(grp, &pin);
assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_B) == 0);
cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus);
/* GPIO_SUS pins are currently unsupported. */
assert(!sus);
quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_IN);
}
void
galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin)
{
bool sus;
int cpu_pin;
flatten_pin_num(grp, &pin);
assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_A) == 0);
cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus);
/* GPIO_SUS pins are currently unsupported. */
assert(!sus);
quarkX1000_gpio_config(cpu_pin, QUARKX1000_GPIO_OUT);
}
void
galileo_pinmux_select_pwm(unsigned pin)
{
GALILEO_PINMUX_FUNC func = GALILEO_PINMUX_FUNC_C;
switch(pin) {
case 3:
func = GALILEO_PINMUX_FUNC_D;
break;
case 5:
case 6:
case 9:
case 10:
case 11:
break;
default:
fprintf(stderr, "%s: invalid pin: %d.\n", __FUNCTION__, pin);
halt();
}
assert(galileo_pinmux_set_pin(pin, func) == 0);
}
void
galileo_pinmux_select_serial(unsigned pin)
{
assert(pin < 4);
assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_C) == 0);
}
void
galileo_pinmux_select_i2c(void)
{
assert(galileo_pinmux_set_pin(18, GALILEO_PINMUX_FUNC_C) == 0);
assert(galileo_pinmux_set_pin(19, GALILEO_PINMUX_FUNC_C) == 0);
}
void
galileo_pinmux_select_spi(void)
{
assert(galileo_pinmux_set_pin(11, GALILEO_PINMUX_FUNC_D) == 0);
assert(galileo_pinmux_set_pin(12, GALILEO_PINMUX_FUNC_C) == 0);
assert(galileo_pinmux_set_pin(13, GALILEO_PINMUX_FUNC_C) == 0);
}
void
galileo_pinmux_select_analog(unsigned pin)
{
assert(pin < GALILEO_NUM_ANALOG_PINS);
pin += GALILEO_NUM_DIGITAL_PINS;
assert(galileo_pinmux_set_pin(pin, GALILEO_PINMUX_FUNC_B) == 0);
}
int
galileo_pinmux_initialize(void)
{
/* has to init after I2C master */
if(!quarkX1000_i2c_is_available()) {
return -1;
}
if(gpio_pcal9535a_init(&data.exp0, GPIO_PCAL9535A_0_I2C_ADDR) < 0) {
return -1;
}
if(gpio_pcal9535a_init(&data.exp1, GPIO_PCAL9535A_1_I2C_ADDR) < 0) {
return -1;
}
if(gpio_pcal9535a_init(&data.exp2, GPIO_PCAL9535A_2_I2C_ADDR) < 0) {
return -1;
}
if(pwm_pca9685_init(&data.pwm0, PWM_PCA9685_0_I2C_ADDR) < 0) {
return -1;
}
/* Activate default pinmux configuration. */
/* Some of the following lines are commented out due to the GPIO_SUS pins
* being currently unsupported.
*/
galileo_pinmux_select_serial(0);
galileo_pinmux_select_serial(1);
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 2);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 3);
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 4);*/
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 5);
galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 6);
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 7);*/
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 8);*/
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 9);*/
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 10);
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 11);*/
galileo_pinmux_select_dout(GALILEO_PIN_GRP_DIGITAL, 12);
/*galileo_pinmux_select_din(GALILEO_PIN_GRP_DIGITAL, 13);*/
galileo_pinmux_select_analog(0);
galileo_pinmux_select_analog(1);
galileo_pinmux_select_analog(2);
galileo_pinmux_select_analog(3);
galileo_pinmux_select_i2c();
return 0;
}

View File

@ -1,102 +0,0 @@
/*
* 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.
*/
#include "galileo-gpio.h"
#include <assert.h>
#include "gpio.h"
#if GALILEO_GEN == 1
#include "cy8c9540a.h"
#endif
/* Must be implemented in board-specific pinmux file to map a board-level GPIO
* pin number to the corresponding CPU GPIO pin number.
*
* For gen. 1 boards, the value -1 may be returned to indicate that the
* specified GPIO pin is not connected to any CPU pin. For gen. 2 boards, the
* return value should always be a positive number. An assertion within the
* function should check the validity of the pin number.
*/
int galileo_brd_to_cpu_gpio_pin(unsigned pin, bool *sus);
#if GALILEO_GEN == 1
cy8c9540a_bit_addr_t galileo_brd_to_cy8c9540a_gpio_pin(unsigned pin);
#endif
static int
brd_to_cpu_pin(unsigned pin)
{
int cpu_pin;
bool sus;
cpu_pin = galileo_brd_to_cpu_gpio_pin(pin, &sus);
assert(!sus);
return cpu_pin;
}
void galileo_gpio_config(uint8_t pin, int flags)
{
assert(quarkX1000_gpio_config(brd_to_cpu_pin(pin), flags) == 0);
}
/**
* \brief Read from GPIO.
* \param pin Board-level IO pin number.
*/
void galileo_gpio_read(uint8_t pin, uint8_t *value)
{
#if GALILEO_GEN == 1
cy8c9540a_bit_addr_t bit_addr;
#endif
int cpu_pin = brd_to_cpu_pin(pin);
#if GALILEO_GEN == 1
if(cpu_pin == -1) {
bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin);
*value = cy8c9540a_read(bit_addr);
return;
}
#endif
assert(quarkX1000_gpio_read(cpu_pin, value) == 0);
}
void galileo_gpio_write(uint8_t pin, uint8_t value)
{
#if GALILEO_GEN == 1
cy8c9540a_bit_addr_t bit_addr;
#endif
int cpu_pin = brd_to_cpu_pin(pin);
#if GALILEO_GEN == 1
if(cpu_pin == -1) {
bit_addr = galileo_brd_to_cy8c9540a_gpio_pin(pin);
cy8c9540a_write(bit_addr, value);
return;
}
#endif
assert(quarkX1000_gpio_write(cpu_pin, value) == 0);
}

View File

@ -1,40 +0,0 @@
/*
* 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 PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_
#define PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_
#include <stdint.h>
void galileo_gpio_config(uint8_t pin, int flags);
void galileo_gpio_read(uint8_t pin, uint8_t *value);
void galileo_gpio_write(uint8_t pin, uint8_t value);
#endif /* PLATFORM_GALILEO_DRIVERS_GALILEO_GPIO_H_ */

View File

@ -1,83 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_GALILEO_PINMUX_H_
#define CPU_X86_DRIVERS_GALILEO_PINMUX_H_
#include <stdint.h>
typedef enum galileo_pin_group {
GALILEO_PIN_GRP_ANALOG,
GALILEO_PIN_GRP_DIGITAL
} galileo_pin_group_t;
#define GALILEO_NUM_ANALOG_PINS 6
#define GALILEO_NUM_DIGITAL_PINS 14
#define GALILEO_NUM_PINS (GALILEO_NUM_ANALOG_PINS + GALILEO_NUM_DIGITAL_PINS)
int galileo_pinmux_initialize(void);
/**
* \brief Set the indicated pin to be a digital input.
* \param grp Indicates whether the pin is in the analog or digital group.
* \param pin Index of pin within group.
*/
void galileo_pinmux_select_din(galileo_pin_group_t grp, unsigned pin);
/**
* \brief Set the indicated pin to be a digital output.
*/
void galileo_pinmux_select_dout(galileo_pin_group_t grp, unsigned pin);
/**
* \brief Set the indicated pin to be a PWM pin. Only a subset of the pins
* support PWM output. This implicitly operates on the digital pin
* group.
*/
void galileo_pinmux_select_pwm(unsigned pin);
/**
* \brief Connect the indicated pin to a serial port. This implicitly operates
* on the digital pin group. Galileo Gen. 2 supports UART0 on pins 0 and
* 1 and UART1 on pins 2 and 3.
*/
void galileo_pinmux_select_serial(unsigned pin);
/**
* \brief Connect analog pins 4 (SDA) and 5 (SCL) to I2C.
*/
void galileo_pinmux_select_i2c(void);
/**
* \brief Connect digital pins 11 (MOSI), 12 (MISO), and 13 (CLK) to SPI.
*/
void galileo_pinmux_select_spi(void);
/**
* \brief Set the indicated pin to be an ADC input. This implicitly operates
* on the analog pin group.
*/
void galileo_pinmux_select_analog(unsigned pin);
#endif /* CPU_X86_DRIVERS_GALILEO_PINMUX_H_ */

View File

@ -1,357 +0,0 @@
/*
* Copyright (C) 2015, 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 "contiki.h"
#include "gpio.h"
#include "gpio-pcal9535a.h"
#include "i2c.h"
#include "stdio.h"
#define REG_INPUT_PORT0 0x00
#define REG_INPUT_PORT1 0x01
#define REG_OUTPUT_PORT0 0x02
#define REG_OUTPUT_PORT1 0x03
#define REG_POL_INV_PORT0 0x04
#define REG_POL_INV_PORT1 0x05
#define REG_CONF_PORT0 0x06
#define REG_CONG_PORT1 0x07
#define REG_OUT_DRV_STRENGTH_PORT0_L 0x40
#define REG_OUT_DRV_STRENGTH_PORT0_H 0x41
#define REG_OUT_DRV_STRENGTH_PORT1_L 0x42
#define REG_OUT_DRV_STRENGTH_PORT1_H 0x43
#define REG_INPUT_LATCH_PORT0 0x44
#define REG_INPUT_LATCH_PORT1 0x45
#define REG_PUD_EN_PORT0 0x46
#define REG_PUD_EN_PORT1 0x47
#define REG_PUD_SEL_PORT0 0x48
#define REG_PUD_SEL_PORT1 0x49
#define REG_INT_MASK_PORT0 0x4A
#define REG_INT_MASK_PORT1 0x4B
#define REG_INT_STATUS_PORT0 0x4C
#define REG_INT_STATUS_PORT1 0x4D
#define REG_OUTPUT_PORT_CONF 0x4F
#define READ_PORT_TIMEOUT (CLOCK_SECOND / 100)
#define READ_PORT_TRIES 5
static int
read_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf)
{
int r;
uint8_t tries = READ_PORT_TRIES;
buf->byte[0] = reg;
buf->byte[1] = 0;
if(quarkX1000_i2c_write(buf->byte, 1, data->i2c_slave_addr) < 0) {
return -1;
}
do {
clock_wait(READ_PORT_TIMEOUT);
r = quarkX1000_i2c_read(buf->byte, 2, data->i2c_slave_addr);
if(r == 0) {
break;
}
} while(tries--);
if(r < 0) {
return -1;
}
return 0;
}
static int
write_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf)
{
uint8_t cmd[] = { reg, buf->byte[0], buf->byte[1] };
if(quarkX1000_i2c_polling_write(cmd, sizeof(cmd), data->i2c_slave_addr) < 0) {
return -1;
}
return 0;
}
static int
setup_pin_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.dir;
uint16_t bit_mask, new_value = 0;
bit_mask = 1 << pin;
if((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) {
new_value = 1 << pin;
}
port->all &= ~bit_mask;
port->all |= new_value;
return write_port_regs(data, REG_CONF_PORT0, port);
}
static int
setup_pin_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port;
uint16_t bit_mask, new_value = 0;
if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
port = &data->reg_cache.pud_sel;
bit_mask = 1 << pin;
if((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) {
new_value = 1 << pin;
}
port->all &= ~bit_mask;
port->all |= new_value;
if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) {
return -1;
}
}
port = &data->reg_cache.pud_en;
bit_mask = 1 << pin;
if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
new_value = 1 << pin;
}
port->all &= ~bit_mask;
port->all |= new_value;
return write_port_regs(data, REG_PUD_EN_PORT0, port);
}
static int
setup_pin_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv;
uint16_t bit_mask, new_value = 0;
bit_mask = 1 << pin;
if((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) {
new_value = 1 << pin;
}
port->all &= ~bit_mask;
port->all |= new_value;
if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) {
return -1;
}
data->out_pol_inv = port->all;
return 0;
}
int
gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.output;
uint16_t bit_mask, new_value;
if(!quarkX1000_i2c_is_available()) {
return -1;
}
bit_mask = 1 << pin;
new_value = (value << pin) & bit_mask;
new_value ^= (data->out_pol_inv & bit_mask);
new_value &= bit_mask;
port->all &= ~bit_mask;
port->all |= new_value;
return write_port_regs(data, REG_OUTPUT_PORT0, port);
}
int
gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value)
{
union gpio_pcal9535a_port_data buf;
if(!quarkX1000_i2c_is_available()) {
return -1;
}
if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) {
return -1;
}
*value = (buf.all >> pin) & 0x01;
return 0;
}
int
gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
if(!quarkX1000_i2c_is_available()) {
return -1;
}
if(setup_pin_dir(data, pin, flags) < 0) {
return -1;
}
if(setup_pin_polarity(data, pin, flags) < 0) {
return -1;
}
if(setup_pin_pullupdown(data, pin, flags) < 0) {
return -1;
}
return 0;
}
static int
setup_port_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.dir;
port->all = ((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) ? 0xFFFF : 0x0;
return write_port_regs(data, REG_CONF_PORT0, port);
}
static int
setup_port_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port;
if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
port = &data->reg_cache.pud_sel;
port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) ? 0xFFFF : 0x0;
if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) {
return -1;
}
}
port = &data->reg_cache.pud_en;
port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) ? 0xFFFF : 0x0;
return write_port_regs(data, REG_PUD_EN_PORT0, port);
}
static int
setup_port_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv;
port->all = ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) ? 0xFFFF : 0x0;
if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) {
return -1;
}
data->out_pol_inv = port->all;
return 0;
}
int
gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value)
{
union gpio_pcal9535a_port_data *port = &data->reg_cache.output;
uint16_t bit_mask, new_value;
if(!quarkX1000_i2c_is_available()) {
return -1;
}
port->all = value;
bit_mask = data->out_pol_inv;
new_value = value & bit_mask;
new_value ^= data->out_pol_inv;
new_value &= bit_mask;
port->all &= ~bit_mask;
port->all |= new_value;
return write_port_regs(data, REG_OUTPUT_PORT0, port);
}
int
gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value)
{
union gpio_pcal9535a_port_data buf;
if(!quarkX1000_i2c_is_available()) {
return -1;
}
if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) {
return -1;
}
*value = buf.all;
return 0;
}
int
gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
{
if(!quarkX1000_i2c_is_available()) {
return -1;
}
if(setup_port_dir(data, pin, flags) < 0) {
return -1;
}
if(setup_port_polarity(data, pin, flags) < 0) {
return -1;
}
if(setup_port_pullupdown(data, pin, flags) < 0) {
return -1;
}
return 0;
}
int
gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr)
{
/* has to init after I2C master */
if(!quarkX1000_i2c_is_available()) {
return -1;
}
data->i2c_slave_addr = i2c_slave_addr;
/* default for registers according to datasheet */
data->reg_cache.output.all = 0xFFFF;
data->reg_cache.pol_inv.all = 0x0;
data->reg_cache.dir.all = 0xFFFF;
data->reg_cache.pud_en.all = 0x0;
data->reg_cache.pud_sel.all = 0xFFFF;
return 0;
}

View File

@ -1,65 +0,0 @@
/*
* Copyright (C) 2015, 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_DRIVERS_GPIO_PCAL9535A_H_
#define CPU_X86_DRIVERS_GPIO_PCAL9535A_H_
#include <stdint.h>
union gpio_pcal9535a_port_data {
uint16_t all;
uint8_t port[2];
uint8_t byte[2];
};
struct gpio_pcal9535a_data {
uint16_t i2c_slave_addr;
uint32_t out_pol_inv;
struct {
union gpio_pcal9535a_port_data output;
union gpio_pcal9535a_port_data pol_inv;
union gpio_pcal9535a_port_data dir;
union gpio_pcal9535a_port_data pud_en;
union gpio_pcal9535a_port_data pud_sel;
} reg_cache;
};
int gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr);
int gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags);
int gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value);
int gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value);
int gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags);
int gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value);
int gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value);
#endif /* CPU_X86_DRIVERS_GPIO_PCAL9535A_H_ */

Some files were not shown because too many files have changed in this diff Show More