Skip to content

Commit

Permalink
Merge pull request contiki-os#1433 from mdlemay/x86-mm
Browse files Browse the repository at this point in the history
X86 memory management
  • Loading branch information
alignan committed Jun 5, 2016
2 parents 8cdff8c + 73774de commit b3faefe
Show file tree
Hide file tree
Showing 62 changed files with 5,853 additions and 334 deletions.
6 changes: 4 additions & 2 deletions cpu/x86/Makefile.x86_common
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ CONTIKI_CPU_DIRS += . init/common
CONTIKI_SOURCEFILES += gdt.c helpers.S idt.c cpu.c

CC = gcc
LD = gcc
AS = as
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
Expand Down
59 changes: 56 additions & 3 deletions cpu/x86/Makefile.x86_quarkX1000
Original file line number Diff line number Diff line change
@@ -1,13 +1,66 @@
# See mm/README.md for a description of available settings:
X86_CONF_PROT_DOMAINS ?= none

include $(CONTIKI)/cpu/x86/Makefile.x86_common

CONTIKI_CPU_DIRS += drivers/legacy_pc drivers/quarkX1000 init/legacy_pc
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 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)/cpu/x86/quarkX1000.ld
ASFLAGS += --32 -march=i586 -mtune=i586
LDFLAGS += -m32 -Xlinker -T -Xlinker $(CONTIKI)/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
Expand Down
27 changes: 16 additions & 11 deletions cpu/x86/bootstrap_quarkX1000.S
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

# Kernel
.set STACK_SIZE, 8192
#include "stacks.h"

# Multiboot
.set MAGIC_NUMBER, 0x1BADB002
Expand All @@ -42,15 +41,21 @@
.long FLAGS
.long CHECKSUM

# Reserve space for the C stack.
.lcomm c_stack, STACK_SIZE

.section .text
.section .boot_text
.global start
start:
cli
movl $(c_stack + STACK_SIZE), %esp
call main

/* We're not expected to return from main(). But if we do we halt */
call halt
#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
8 changes: 8 additions & 0 deletions cpu/x86/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@
#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_ */
83 changes: 60 additions & 23 deletions cpu/x86/drivers/legacy_pc/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@

#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.
Expand Down Expand Up @@ -101,47 +104,43 @@ pci_command_enable(pci_config_addr_t addr, uint32_t flags)
* \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].
* \return Returns 0 on success and a negative number otherwise.
*/
int
pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq)
SYSCALLS_DEFINE_SINGLETON(pci_irq_agent_set_pirq,
root_complex_drv,
IRQAGENT agent, INTR_PIN pin, PIRQ pirq)
{
pci_config_addr_t pci;
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);

pci.raw = 0;
pci.bus = 0;
pci.dev = 31;
pci.func = 0;
pci.reg_off = 0xF0; /* Root Complex Base Address Register */

/* masked to clear non-address bits. */
rcba_addr = pci_config_read(pci) & ~0x3FFF;

switch(agent) {
case IRQAGENT0:
if (pin != INTA)
return -1;
if(pin != INTA) {
halt();
}
offset = 0x3140;
break;
case IRQAGENT1:
offset = 0x3142;
break;
case IRQAGENT2:
if (pin != INTA)
return -1;
if(pin != INTA) {
halt();
}
offset = 0x3144;
break;
case IRQAGENT3:
offset = 0x3146;
}

value = *(uint16_t*)(rcba_addr + offset);
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) {
Expand All @@ -162,9 +161,9 @@ pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq)
value |= (pirq << 12);
}

*(uint16_t*)(rcba_addr + offset) = value;
MMIO_WRITEW(*(uint16_t ATTR_MMIO_ADDR_SPACE *)(rcba_addr + offset), value);

return 0;
prot_domains_disable_mmio();
}
/*---------------------------------------------------------------------------*/
/**
Expand Down Expand Up @@ -231,13 +230,51 @@ pci_pirq_set_irq(PIRQ pirq, uint8_t irq, uint8_t route_to_legacy)
* 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 *c_this, pci_config_addr_t pci_addr, uintptr_t meta)
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. */
c_this->mmio = pci_config_read(pci_addr) & ~0xFFF;
c_this->meta = meta;
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);
}
/*---------------------------------------------------------------------------*/
29 changes: 17 additions & 12 deletions cpu/x86/drivers/legacy_pc/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#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
Expand Down Expand Up @@ -98,22 +100,25 @@ 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);

/**
* PCI device driver instance with an optional single MMIO range and optional
* metadata.
*/
typedef struct pci_driver {
uintptr_t mmio; /**< MMIO range base address */
uintptr_t meta; /**< Driver-defined metadata base address */
} pci_driver_t;
typedef dom_client_data_t pci_driver_t;

void pci_init(pci_driver_t *c_this, pci_config_addr_t pci_addr, uintptr_t meta);
int pci_irq_agent_set_pirq(IRQAGENT agent, INTR_PIN pin, PIRQ pirq);
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) \
dest = *((volatile uint32_t *)((c_this).mmio + (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) \
*((volatile uint32_t *)((c_this).mmio + (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_ */
10 changes: 5 additions & 5 deletions cpu/x86/drivers/legacy_pc/shared-isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ shared_isr_init(void)

void shared_isr_stub(void);
__asm__ __volatile__ (
ISR_STUB("shared_isr_stub", 0, "shared_handler")
ISR_STUB("shared_isr_stub", 0, "shared_handler", 0)
:
);

while(client < &_edata_shared_isr) {
Expand Down Expand Up @@ -91,11 +92,10 @@ shared_isr_init(void)
(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);
idt_set_intr_gate_desc(PIC_INT(client->irq), (uint32_t)shared_isr_stub,
GDT_SEL_CODE_INT, PRIV_LVL_INT);

assert(pci_irq_agent_set_pirq(client->agent,
client->pin,
client->pirq) == 0);
pci_irq_agent_set_pirq(client->agent, client->pin, client->pirq);

pci_pirq_set_irq(client->pirq, client->irq, 1);

Expand Down
Loading

0 comments on commit b3faefe

Please sign in to comment.