dde_linux: KMS-based Intel framebuffer driver (I)

Ref #1764
This commit is contained in:
Norman Feske 2015-09-09 16:21:19 +02:00 committed by Christian Helmuth
parent 1081af930d
commit 520c36d77f
75 changed files with 10212 additions and 1 deletions

View File

@ -0,0 +1,63 @@
linux-3.14.5/drivers/char/agp/intel-gtt.c
linux-3.14.5/drivers/char/agp/intel-agp.h
linux-3.14.5/drivers/char/agp/agp.h
linux-3.14.5/drivers/char/agp/generic.c
linux-3.14.5/drivers/char/agp/backend.c
linux-3.14.5/drivers/i2c/i2c-core.c
linux-3.14.5/drivers/i2c/i2c-core.h
linux-3.14.5/drivers/i2c/i2c-boardinfo.c
linux-3.14.5/drivers/gpu/drm/drm_mm.c
linux-3.14.5/drivers/gpu/drm/drm_crtc.c
linux-3.14.5/drivers/gpu/drm/drm_edid.c
linux-3.14.5/drivers/gpu/drm/i915/i915_dma.c
linux-3.14.5/drivers/gpu/drm/i915/i915_drv.c
linux-3.14.5/drivers/gpu/drm/i915/i915_drv.h
linux-3.14.5/drivers/gpu/drm/i915/i915_gem.c
linux-3.14.5/drivers/gpu/drm/i915/i915_gem_stolen.c
linux-3.14.5/drivers/gpu/drm/i915/i915_reg.h
linux-3.14.5/drivers/gpu/drm/i915/i915_gem_gtt.c
linux-3.14.5/drivers/gpu/drm/i915/i915_irq.c
linux-3.14.5/drivers/gpu/drm/i915/intel_bios.h
linux-3.14.5/drivers/gpu/drm/i915/intel_ddi.c
linux-3.14.5/drivers/gpu/drm/i915/intel_dp.c
linux-3.14.5/drivers/gpu/drm/i915/intel_drv.h
linux-3.14.5/drivers/gpu/drm/i915/intel_ringbuffer.h
linux-3.14.5/drivers/gpu/drm/i915/intel_display.c
linux-3.14.5/drivers/gpu/drm/i915/intel_panel.c
linux-3.14.5/drivers/gpu/drm/i915/intel_uncore.c
linux-3.14.5/drivers/gpu/drm/i915/intel_lvds.c
linux-3.14.5/drivers/gpu/drm/i915/intel_i2c.c
linux-3.14.5/include/asm-generic/atomic64.h
linux-3.14.5/include/asm-generic/ioctl.h
linux-3.14.5/include/asm-generic/getorder.h
linux-3.14.5/include/asm-generic/bitops/__ffs.h
linux-3.14.5/include/asm-generic/bitops/__fls.h
linux-3.14.5/include/asm-generic/bitops/ffs.h
linux-3.14.5/include/asm-generic/bitops/fls.h
linux-3.14.5/include/asm-generic/bitops/fls64.h
linux-3.14.5/include/asm-generic/bitops/non-atomic.h
linux-3.14.5/include/linux/agp_backend.h
linux-3.14.5/include/linux/list.h
linux-3.14.5/include/linux/log2.h
linux-3.14.5/include/linux/pci_ids.h
linux-3.14.5/include/linux/i2c-algo-bit.h
linux-3.14.5/include/linux/i2c.h
linux-3.14.5/include/drm/intel-gtt.h
linux-3.14.5/include/drm/i915_pciids.h
linux-3.14.5/include/drm/i915_drm.h
linux-3.14.5/include/drm/drm_dp_helper.h
linux-3.14.5/include/drm/drm_mm.h
linux-3.14.5/include/drm/drm_crtc.h
linux-3.14.5/include/drm/drm_crtc_helper.h
linux-3.14.5/include/drm/drm_edid.h
linux-3.14.5/include/uapi/drm/i915_drm.h
linux-3.14.5/include/uapi/drm/drm.h
linux-3.14.5/include/uapi/linux/pci_regs.h
linux-3.14.5/include/uapi/linux/i2c.h
linux-3.14.5/include/uapi/asm-generic/ioctl.h
linux-3.14.5/include/uapi/drm/drm_fourcc.h
linux-3.14.5/include/uapi/drm/drm_mode.h
linux-3.14.5/include/uapi/linux/byteorder/little_endian.h
linux-3.14.5/include/uapi/linux/swab.h
linux-3.14.5/arch/x86/include/asm/agp.h

View File

@ -0,0 +1,27 @@
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/framebuffer/intel
SRC_DIR := $(REP_DIR)/src/drivers/framebuffer/intel
# architecture-dependent includes
ifeq ($(filter-out $(SPECS),x86),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/x86 \
$(LX_CONTRIB_DIR)/arch/x86/include
ifeq ($(filter-out $(SPECS),32bit),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_32
endif # 32bit
ifeq ($(filter-out $(SPECS),64bit),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_64
endif # 64bit
endif # x86
INC_DIR += $(SRC_DIR)/include \
$(REP_DIR)/src/include \
$(ARCH_SRC_INC_DIR) \
$(LX_CONTRIB_DIR)/drivers/gpu/drm \
$(LX_CONTRIB_DIR)/drivers/gpu/include/drm \
$(LX_CONTRIB_DIR)/drivers/gpu/include \
$(LX_CONTRIB_DIR)/include \
$(LX_CONTRIB_DIR)/include/uapi \
$(LIB_CACHE_DIR)/intel_fb_include
CC_OPT += -U__linux__ -D__KERNEL__
CC_OPT += -DCONFIG_DRM_I915_KMS -DCONFIG_I2C -DCONFIG_I2C_BOARDINFO

View File

@ -0,0 +1,25 @@
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/framebuffer/intel
SRC_DIR := $(REP_DIR)/src/drivers/framebuffer/intel
LIBS += intel_fb_include
SRC_C :=
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/char/agp/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/i2c/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/gpu/drm/*.c))
SRC_C += $(notdir $(wildcard $(LX_CONTRIB_DIR)/drivers/gpu/drm/i915/*.c))
#SRC_C := $(filter-out intel_dp.c,$(SRC_C))
#SRC_C := intel_panel.c
#
# Reduce build noise of compiling contrib code
#
CC_WARN = -Wall -Wno-uninitialized -Wno-unused-but-set-variable \
-Wno-unused-variable -Wno-unused-function
vpath %.c $(LX_CONTRIB_DIR)/drivers/char/agp
vpath %.c $(LX_CONTRIB_DIR)/drivers/i2c
vpath %.c $(LX_CONTRIB_DIR)/drivers/gpu/drm/i915
vpath %.c $(LX_CONTRIB_DIR)/drivers/gpu/drm

View File

@ -0,0 +1,17 @@
#
# Pseudo library to generate a symlink for each header file included by the
# contrib code. Each symlink points to the same 'lx_emul.h' file, which
# provides our emulation of the Linux kernel API.
#
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/framebuffer/intel
LX_EMUL_H := $(REP_DIR)/src/drivers/framebuffer/intel/include/lx_emul.h
GEN_INCLUDES := $(shell grep -rh "^\#include .*\/" $(LX_CONTRIB_DIR) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | sort | uniq)
all: $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -sf $(LX_EMUL_H) $@

View File

@ -1,9 +1,12 @@
LICENSE := GPL
VERSION := 1
DOWNLOADS := dwc_otg.git usb.archive lxip.archive wifi.archive \
DOWNLOADS := dwc_otg.git usb.archive lxip.archive intel_fb.archive wifi.archive \
libnl.archive wpa_supplicant.archive \
fw_6000.archive fw_6205a.archive fw_6205b.archive fw_7260.archive fw_7265.archive
# XXX disable all parts except for intel_fb
DOWNLOADS := intel_fb.archive
#
# Tools
#
@ -37,6 +40,16 @@ URL(dwc_otg) := https://github.com/nfeske/dwc_otg.git
REV(dwc_otg) := r2
DIR(dwc_otg) := $(SRC_DIR_USB)/drivers/usb/host/dwc_otg
#
# Intel framebuffer driver
#
SRC_DIR_INTEL_FB := src/drivers/framebuffer/intel
URL(intel_fb) := ${URL(usb)}
SHA(intel_fb) := ${SHA(usb)}
DIR(intel_fb) := $(SRC_DIR_INTEL_FB)
TAR_OPT(intel_fb) := --strip-components=1 --files-from $(REP_DIR)/intel_fb.list
HASH_INPUT += $(REP_DIR)/intel_fb.list
#
# mac80211 stack, iwlwifi and iwslegacy sources
#
@ -162,4 +175,7 @@ PATCH_OPT(patches/libnl.patch) := -p1 -d ${DIR(libnl)}
# WPA supplicant
PATCH_OPT(patches/wpa_supplicant.patch) := -p1 -d ${DIR(wpa_supplicant)}
# XXX disable all patches of non-intel_fb subsystems
PATCHES :=
# vi: set ft=make :

View File

@ -0,0 +1,79 @@
#
# Build
#
set build_components {
core init
drivers/timer
drivers/framebuffer/intel
}
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
build $build_components
create_boot_directory
proc platform_drv_policy {} {
return {
<policy label="intel_fb_drv">
<pci class="VGA"/>
<pci bus="0" device="0" function="0"/>
<pci class="ISABRIDGE"/>
</policy>
}
}
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL" />
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>}
append_platform_drv_config
append config {
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="intel_fb_drv">
<resource name="RAM" quantum="10M"/>
<provides><service name="Input"/></provides>
</start>
</config>}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init timer intel_fb_drv
}
append_platform_drv_boot_modules
build_boot_image $boot_modules
run_genode_until forever

View File

@ -0,0 +1,139 @@
/*
* \brief Dummy functions
* \author Norman Feske
* \date 2015-08-18
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include "lx_emul_private.h"
extern "C" {
#include <drm/drmP.h>
#include <i915/i915_drv.h>
/*
* Incorporate dummy implemementations semi-automaticall generated via the
* 'gen_dummy' script.
*/
#include "gen_dummies.h"
/*
* Manually defined dummies (because they are not covered by the heuristics
* of the 'gen_dummy' script).
*/
struct timespec timespec_sub(struct timespec lhs, struct timespec rhs)
{
TRACE_AND_STOP;
return { 0, 0 };
}
struct timespec ns_to_timespec(const s64 nsec)
{
TRACE_AND_STOP;
return { 0, 0 };
}
void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, bool ascii)
{
TRACE_AND_STOP;
}
bool mod_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long)
{
TRACE_AND_STOP;
return false;
}
bool capable(int cap)
{
TRACE_AND_STOP;
return false;
}
int drm_dp_bw_code_to_link_rate(u8 link_bw)
{
TRACE_AND_STOP;
return -1;
}
bool intel_fbc_enabled(struct drm_device *dev)
{
TRACE_AND_STOP;
return false;
}
int i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
{
TRACE_AND_STOP;
return -1;
}
int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
int i915_gem_execbuffer2(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
int i915_gem_set_tiling(struct drm_device *dev, void *data, struct drm_file *file)
{
TRACE_AND_STOP;
return -1;
}
int i915_gem_get_tiling(struct drm_device *dev, void *data, struct drm_file *file)
{
TRACE_AND_STOP;
return -1;
}
int intel_overlay_put_image(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
TRACE_AND_STOP;
return -1;
}
bool flush_delayed_work(struct delayed_work *dwork)
{
TRACE_AND_STOP;
return false;
}
void *krealloc(const void *, size_t, gfp_t)
{
TRACE_AND_STOP;
return NULL;
}
void down_read(struct rw_semaphore *sem)
{
TRACE_AND_STOP;
}
void device_unregister(struct device *dev)
{
TRACE_AND_STOP;
}
} /* extern "C" */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
#!/usr/bin/tclsh
#
# \brief Private utility to generate a dummy function from a symbol name
# \date 2015-08-21
# \author Norman Feske
#
# The script must be executed in its directory and takes a symbol name as last
# argument. It searches the following places for a declaration that corresponds
# to the specified symbol:
#
# - the local include/ directory
# - the dde_linux/src/include/lx_emul/ directory
# - the contrib/dde_linux-<hash>/src/drivers/framebuffer/intel directory
#
# If a declaration could be found, the script generates a dummy implementation
# with the signature of the declarated function.
#
set symbol $argv
# determine contrib directory of dde_linux
set lx_drv_path [exec ../../../../../../tool/ports/current dde_linux]
append lx_drv_path "/src/drivers/framebuffer/intel"
# grep for lines that contain the symbol and have with no leading whitespace
if {[catch {
set header [exec grep -rl "^\\w.*$symbol\\>" include ../../../include/lx_emul $lx_drv_path | grep -v "~"]
}]} {
puts stderr "failed to lookup symbol $symbol"
exit 1
}
if {[llength $header] != 1} {
puts stderr "cannot generate dummy for symbol $symbol"
exit 1
}
puts stderr "found declaration of $symbol in $header"
set statements [split [exec cat $header] ";{}"]
foreach statement $statements {
# strip off comments and preprocessor commands
regsub -all {/\*.*?\*/} $statement "" statement
regsub -all {//.*?\n} $statement "" statement
regsub -all {#.*?\n} $statement "\n" statement
# delete consecutive newlines
while {[regexp {\n\n} $statement dummy]} {
regsub -all {\n\n} $statement "\n" statement
}
# function declarations have no leading tabs
if {[regexp {^\t} $statement dummy]} continue
# skip statements where the symbol does not occur
if {![regexp "$symbol\\(" $statement dummy]} continue
# strip leading whitespace (linefeed)
regsub {^\s*} $statement "" statement
# strip leading extern keyword
regsub {^extern\s*} $statement "" statement
# strip leading inline keyword
regsub {^inline\s*} $statement "" statement
# merge multi-line parameter list into a single line
regsub -all {\s*\n\s*} $statement " " statement
# strip function attributes starting with '__'
regsub -all {\)\s*__.*} $statement ")" statement
# determine return type 'ret' of the function
regexp {^[^\(]*} $statement func_ret
regsub {\s[^\s\*]*$} $func_ret "" ret
# output function definition
puts "$statement"
puts "{"
puts "\tTRACE_AND_STOP;"
if {[regexp {\*} $ret]} {
# function returns a pointer
puts "\treturn NULL;"
} elseif {[regexp {void} $ret dummy]} {
# void function
} else {
# function with return value
puts "\treturn -1;"
}
puts "}\n"
# success
exit 0
}
puts stderr "failed to match declaration of $symbol in $header"

View File

@ -0,0 +1,31 @@
/*
* \brief Definition of the global 'i2c_bit_algo' struct
* \author Norman Feske
* \date 2015-09-11
*
* The 'i2c_bit_algo' struct must be defined in a C file because we cannot
* use C-style struct initializers in C++ code.
*/
#include <lx_emul.h>
int i2c_algo_bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
lx_printf("i2c_algo_bit_xfer called - not implemented\n");
for (;;);
return -1;
}
u32 i2c_algo_bit_func(struct i2c_adapter *adap)
{
lx_printf("i2c_algo_bit_func called - not implemented\n");
return 0;
}
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = i2c_algo_bit_xfer,
.functionality = i2c_algo_bit_func,
};

View File

@ -0,0 +1,684 @@
/*
* \brief Platform interface of DRM code
* \author Norman Feske
* \date 2015-08-19
*/
#ifndef _DRMP_H_
#define _DRMP_H_
#ifdef __cplusplus
extern "C" {
#endif
/* local includes */
#include <lx_emul.h>
/*
* Unfortunately, DRM headers use certain C++ keywords as variable names.
* To enable the inclusion of 'drmP.h' from C++ source codes, we have to
* rename these identifiers.
*/
#ifdef __cplusplus
#define new _new
#define virtual _virtual
#define private _private
#endif /* __cplusplus */
#include <uapi/drm/drm.h>
#include <uapi/drm/i915_drm.h>
#include <uapi/drm/drm_fourcc.h>
#include <uapi/drm/drm_mode.h>
#include <drm/i915_pciids.h>
#include <drm/drm_mm.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#ifdef __cplusplus
#undef virtual
#undef new
#undef private
#endif /* __cplusplus */
extern unsigned int drm_debug;
/*******************
** DRM constants **
*******************/
enum {
DRM_MINOR_CONTROL = 2,
// DRM_MINOR_RENDER = 3,
// DRM_MAGIC_HASH_ORDER = 4,
};
enum {
DRM_AUTH = 0x1,
DRM_MASTER = 0x2,
DRM_ROOT_ONLY = 0x4,
DRM_CONTROL_ALLOW = 0x8,
DRM_UNLOCKED = 0x10,
DRM_RENDER_ALLOW = 0x20,
};
enum {
DRIVER_USE_AGP = 0x1,
DRIVER_REQUIRE_AGP = 0x2,
DRIVER_HAVE_IRQ = 0x40,
DRIVER_IRQ_SHARED = 0x80,
DRIVER_GEM = 0x1000,
DRIVER_MODESET = 0x2000,
DRIVER_PRIME = 0x4000,
DRIVER_RENDER = 0x8000,
};
//enum { DRM_HZ = HZ };
enum {
DRM_SCANOUTPOS_VALID = (1 << 0),
DRM_SCANOUTPOS_INVBL = (1 << 1),
DRM_SCANOUTPOS_ACCURATE = (1 << 2),
};
enum { DRM_CALLED_FROM_VBLIRQ = 1 };
//enum {
// DRM_CONNECTOR_POLL_HPD = 1 << 0,
// DRM_CONNECTOR_POLL_CONNECT = 1 << 1,
// DRM_CONNECTOR_POLL_DISCONNECT = 1 << 2,
//};
/****************
** DRM macros **
****************/
#define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
///*
// * Type and function mappings
// */
//#define DRM_IRQ_ARGS void *arg
//#define DRM_ARRAY_SIZE ARRAY_SIZE
//#define DRM_WAKEUP wake_up
//#define DRM_INIT_WAITQUEUE init_waitqueue_head
//#define DRM_AGP_KERN struct agp_kern_info
//#define DRM_AGP_MEM struct agp_memory
//#define DRM_COPY_TO_USER copy_to_user
//
///*
// * Debug macros
// */
#define DRM_VERBOSE 1
#if DRM_VERBOSE
#define DRM_INFO(fmt, arg...) do { \
lx_printfln("[" DRM_NAME ":%s] *INFO* " fmt , __func__ , ##arg); } while (0)
#define DRM_ERROR(fmt, arg...) do { \
lx_printfln("[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg); } while (0)
#define DRM_DEBUG(fmt, arg...) do { \
lx_printfln("[" DRM_NAME ":%s] *DEBUG* " fmt , __func__ , ##arg); } while (0)
#define DRM_DEBUG_DRIVER(fmt, arg...) do { \
lx_printfln("[" DRM_NAME ":%s] *DRIVER* " fmt , __func__ , ##arg); } while (0)
#define DRM_DEBUG_KMS(fmt, arg...) do { \
lx_printfln("[" DRM_NAME ":%s] *KMS* " fmt , __func__ , ##arg); } while (0)
#else
#define DRM_INFO(fmt, arg...) do { } while (0)
#define DRM_ERROR(fmt, arg...) do { } while (0)
#define DRM_DEBUG(fmt, arg...) do { } while (0)
#define DRM_DEBUG_DRIVER(fmt, arg...) do { } while (0)
#define DRM_DEBUG_KMS(fmt, arg...) do { } while (0)
#endif
#define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
#define DRM_UT_KMS 0x04
///***************
// ** DRM types **
// ***************/
//
///*
// * Forward type declarations
// */
struct drm_device;
struct drm_mm_node;
struct drm_master;
struct drm_file;
struct drm_crtc;
struct drm_plane;
struct drm_display_mode;
struct drm_connector;
struct drm_mode_create_dumb;
struct drm_mode_fb_cmd2;
/**
* Ioctl handler function
*/
typedef int drm_ioctl_t(struct drm_device *dev, void *data,
struct drm_file *file_priv);
/**
* Ioctl representation
*/
struct drm_ioctl_desc {
unsigned int cmd;
int flags;
drm_ioctl_t *func;
unsigned int cmd_drv;
const char *name;
};
#define DRM_IOCTL_NR(n) (n & 0xff)
#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \
[DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl, .name = #ioctl}
#if 0
#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
[ioctl & 0xff] = {.cmd = ioctl, .func = _func, .flags = _flags}
#endif
struct drm_gem_object;
struct drm_driver {
u32 driver_features;
const struct vm_operations_struct *gem_vm_ops;
const struct drm_ioctl_desc *ioctls;
int num_ioctls;
const struct file_operations *fops;
int major;
int minor;
int patchlevel;
char *name;
char *desc;
char *date;
int (*load) (struct drm_device *, unsigned long flags);
int (*unload) (struct drm_device *);
int (*open) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *);
void (*preclose) (struct drm_device *, struct drm_file *file_priv);
void (*postclose) (struct drm_device *, struct drm_file *);
int (*suspend) (struct drm_device *, pm_message_t state);
int (*resume) (struct drm_device *);
int (*device_is_agp) (struct drm_device *dev);
int (*master_create)(struct drm_device *dev, struct drm_master *master);
void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
void (*gem_free_object) (struct drm_gem_object *obj);
int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv,
uint32_t handle, uint32_t flags, int *prime_fd);
int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv,
int prime_fd, uint32_t *handle);
struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
struct drm_gem_object *obj, int flags);
struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
struct dma_buf *dma_buf);
int (*dumb_create)(struct drm_file *file_priv,
struct drm_device *dev,
struct drm_mode_create_dumb *args);
int (*dumb_map_offset)(struct drm_file *file_priv,
struct drm_device *dev, uint32_t handle,
uint64_t *offset);
int (*dumb_destroy)(struct drm_file *file_priv,
struct drm_device *dev,
uint32_t handle);
int (*get_vblank_timestamp) (struct drm_device *dev, int crtc,
int *max_error,
struct timeval *vblank_time,
unsigned flags);
u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
int (*get_scanout_position) (struct drm_device *dev, int crtc,
unsigned int flags,
int *vpos, int *hpos, ktime_t *stime,
ktime_t *etime);
irqreturn_t(*irq_handler) (int irq, void *arg);
void (*irq_preinstall) (struct drm_device *dev);
int (*irq_postinstall) (struct drm_device *dev);
void (*irq_uninstall) (struct drm_device *dev);
int (*enable_vblank) (struct drm_device *dev, int crtc);
void (*disable_vblank) (struct drm_device *dev, int crtc);
};
///* needed by drm_agpsupport.c */
//struct drm_agp_mem {
// unsigned long handle;
// DRM_AGP_MEM *memory;
// unsigned long bound;
// int pages;
// struct list_head head;
//};
//
//struct drm_agp_head {
// DRM_AGP_KERN agp_info;
// unsigned long base;
//
// /*
// * Members used by drm_agpsupport.c
// */
// int acquired;
// struct agp_bridge_data *bridge;
// int enabled;
// unsigned long mode;
// struct list_head memory;
// int cant_use_aperture;
// unsigned long page_mask;
//};
#define DRM_SWITCH_POWER_ON 0
#define DRM_SWITCH_POWER_OFF 1
#define DRM_SWITCH_POWER_CHANGING 2
struct drm_i915_private;
struct drm_device {
// int pci_device;
struct pci_dev *pdev;
struct mutex struct_mutex;
struct drm_driver *driver;
struct drm_i915_private *dev_private;
// struct drm_gem_mm *mm_private;
// enum drm_stat_type types[15];
// unsigned long counters;
struct address_space *dev_mapping;
struct drm_agp_head *agp;
int irq_enabled; /* needed for i915_dma.c */
spinlock_t count_lock;
struct drm_mode_config mode_config;
int open_count;
int vblank_disable_allowed;
u32 max_vblank_count;
struct drm_minor *primary; /* needed by i915_dma.c */
// atomic_t object_count;
// atomic_t object_memory;
// atomic_t pin_count;
// atomic_t pin_memory;
// atomic_t gtt_count;
// atomic_t gtt_memory;
// uint32_t gtt_total;
// uint32_t invalidate_domains;
// uint32_t flush_domains;
int switch_power_state;
spinlock_t event_lock;
struct device *dev; /* i915_gem_stolen.c */
};
//
//struct drm_map_list {
// struct drm_hash_item hash;
// struct drm_local_map *map;
// struct drm_mm_node *file_offset_node;
//};
/***************************
** drm/drm_vma_manager.h **
***************************/
struct drm_vma_offset_node {
int dummy;
};
struct drm_gem_object {
// /** Related drm device */
struct drm_device *dev;
//
// /** File representing the shmem storage */
struct file *filp;
//
// /**
// * Size of the object, in bytes. Immutable over the object's
// * lifetime.
// */
size_t size;
//
// /**
// * Global name for this object, starts at 1. 0 means unnamed.
// * Access is covered by the object_name_lock in the related drm_device
// */
// int name;
//
// /* Mapping info for this object */
// struct drm_map_list map_list;
//
// /**
// * Memory domains. These monitor which caches contain read/write data
// * related to the object. When transitioning from one set of domains
// * to another, the driver is called to ensure that caches are suitably
// * flushed and invalidated
// */
uint32_t read_domains;
uint32_t write_domain;
//
// /**
// * While validating an exec operation, the
// * new read/write domain values are computed here.
// * They will be transferred to the above values
// * at the point that any cache flushing occurs
// */
// uint32_t pending_read_domains;
// uint32_t pending_write_domain;
//
// void *driver_private;
struct drm_vma_offset_node vma_node;
struct dma_buf_attachment *import_attach;
};
typedef struct drm_dma_handle {
void *vaddr;
size_t size;
dma_addr_t busaddr; /* needed by i915_drv.h */
} drm_dma_handle_t;
typedef struct drm_local_map {
size_t offset; /* Requested physical address (0 for SAREA)*/
unsigned long size; /* Requested physical size (bytes) */
// enum drm_map_type type; /* Type of memory to map */
// enum drm_map_flags flags; /* Flags */
void *handle; /* User-space: "Handle" to pass to mmap() */
/* Kernel-space: kernel-virtual address */
int mtrr; /* MTRR slot used */
} drm_local_map_t;
//struct drm_gem_mm {
// struct drm_mm offset_manager;
// struct drm_open_hash offset_hash;
//};
//
struct drm_lock_data {
struct drm_hw_lock *hw_lock; /* for i915_dma.c */
struct drm_file *file_priv; /* for i915_dma.c */
};
//
struct drm_master {
struct drm_lock_data lock; /* needed for i915_dma.c */
void *driver_priv; /* needed for i915_dma.c */
struct drm_minor *minor;
};
struct drm_file {
void *driver_priv;
struct drm_minor *minor; /* needed for drm_agpsupport.c */
struct drm_master *master; /* needed for i915_dma.c */
struct list_head fbs;
struct mutex fbs_lock;
unsigned stereo_allowed :1;
unsigned is_master :1; /* this file private is a master for a minor */
int event_space;
};
//
///*
// * needed for drm_agpsupport.c
// */
struct drm_minor {
struct device *kdev; /* needed by i915_irq.c */
struct drm_device *dev;
struct drm_master *master; /* needed for i915_dma.c */
int index; /**< Minor device number */
struct drm_mode_group mode_group;
int type; /**< Control or render */
};
//
///*
// * needed for drm_crtc_helper.h, included by i915_dma.c
// */
//struct drm_encoder { void *helper_private; };
//struct drm_mode_set { };
#define DRM_MODE_OBJECT_CRTC 0xcccccccc
//#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
//#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0
#define DRM_MODE_OBJECT_MODE 0xdededede
//#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0
//#define DRM_MODE_OBJECT_FB 0xfbfbfbfb
//#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb
//#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee
//#define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd
#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
.name = nm, .status = 0, .type = (t), .clock = (c), \
.hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
.htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
.vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
.vscan = (vs), .flags = (f), \
.base.type = DRM_MODE_OBJECT_MODE
#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */
struct drm_pending_vblank_event;
struct drm_fb_helper { int dummy; };
#include <drm/drm_dp_helper.h>
/***************************
** drm/drm_crtc_helper.h **
***************************/
struct drm_pending_event {
struct drm_event *event;
// struct list_head link;
struct drm_file *file_priv;
// pid_t pid; /* pid of requester, no guarantee it's valid by the time
// we deliver the event, for tracing only */
void (*destroy)(struct drm_pending_event *event);
};
struct drm_pending_vblank_event {
int dummy;
struct drm_pending_event base;
// int pipe;
struct drm_event_vblank event;
};
/******************
** Misc helpers **
******************/
/* normally found in drm_os_linux.h */
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
do { \
DECLARE_WAITQUEUE(entry, current); \
unsigned long end = jiffies + (timeout); \
add_wait_queue(&(queue), &entry); \
\
for (;;) { \
__set_current_state(TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (time_after_eq(jiffies, end)) { \
ret = -EBUSY; \
break; \
} \
schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \
if (signal_pending(current)) { \
ret = -EINTR; \
break; \
} \
} \
__set_current_state(TASK_RUNNING); \
remove_wait_queue(&(queue), &entry); \
} while (0)
/* normally found in Linux drmP.h */
#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \
do { \
if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \
_file_priv->master->lock.file_priv != _file_priv) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
__func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\
_file_priv->master->lock.file_priv, _file_priv); \
return -EINVAL; \
} \
} while (0)
static inline int drm_core_check_feature(struct drm_device *dev, int feature) {
return ((dev->driver->driver_features & feature) ? 1 : 0); }
#if 0
static inline int drm_core_has_AGP(struct drm_device *dev) {
return drm_core_check_feature(dev, DRIVER_USE_AGP); }
/*
* Functions normally provided by drm_bufs.c
*/
static inline resource_size_t
drm_get_resource_start(struct drm_device *dev, unsigned int rsc) {
return pci_resource_start(dev->pdev, rsc); }
static inline resource_size_t
drm_get_resource_len(struct drm_device *dev, unsigned int rsc) {
return pci_resource_len(dev->pdev, rsc); }
#endif
static __inline__ bool drm_can_sleep(void) { return true; }
extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
extern int drm_noop(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int drm_irq_install(struct drm_device *dev);
extern int drm_irq_uninstall(struct drm_device *dev);
extern struct drm_local_map *drm_getsarea(struct drm_device *dev);
extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
extern void drm_vblank_cleanup(struct drm_device *dev);
extern void drm_kms_helper_poll_disable(struct drm_device *dev);
extern void drm_kms_helper_poll_init(struct drm_device *dev);
extern void drm_mm_takedown(struct drm_mm *mm);
extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
extern void drm_modeset_lock_all(struct drm_device *dev);
extern void drm_mode_config_reset(struct drm_device *dev);
extern void drm_modeset_unlock_all(struct drm_device *dev);
extern void drm_kms_helper_poll_enable(struct drm_device *dev);
extern int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver);
extern void drm_put_dev(struct drm_device *dev);
extern void drm_gem_vm_open(struct vm_area_struct *vma);
extern void drm_gem_vm_close(struct vm_area_struct *vma);
extern int drm_open(struct inode *inode, struct file *filp);
extern int drm_release(struct inode *inode, struct file *filp);
extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
extern long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
extern ssize_t drm_read(struct file *filp, char __user *buffer, size_t count, loff_t *offset);
extern int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, struct drm_file *file_priv, uint32_t handle, uint32_t flags, int *prime_fd);
extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, struct drm_file *file_priv, int prime_fd, uint32_t *handle);
extern int drm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev, uint32_t handle);
extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
extern void drm_vblank_off(struct drm_device *dev, int crtc);
extern void drm_encoder_cleanup(struct drm_encoder *encoder);
extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
extern struct drm_connector *drm_select_eld(struct drm_encoder *encoder, struct drm_display_mode *mode);
extern int drm_av_sync_delay(struct drm_connector *connector, struct drm_display_mode *mode);
extern struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, u32 handle);
extern void drm_gem_object_unreference(struct drm_gem_object *obj);
extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj);
extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth);
extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
extern void drm_mode_set_name(struct drm_display_mode *mode);
extern void drm_crtc_cleanup(struct drm_crtc *crtc);
extern void drm_send_vblank_event(struct drm_device *dev, int crtc, struct drm_pending_vblank_event *e);
extern void drm_vblank_put(struct drm_device *dev, int crtc);
extern int drm_vblank_get(struct drm_device *dev, int crtc);
extern void drm_gem_object_reference(struct drm_gem_object *obj);
extern void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags);
extern int drm_object_property_set_value(struct drm_mode_object *obj, struct drm_property *property, uint64_t val);
extern void drm_calc_timestamping_constants(struct drm_crtc *crtc, const struct drm_display_mode *mode);
extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2);
extern bool drm_encoder_crtc_ok(struct drm_encoder *encoder, struct drm_crtc *crtc);
extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, int gamma_size);
extern void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs);
extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type);
extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
extern int drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, u32 *handlep);
extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd2 *mode_cmd);
extern int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb, const struct drm_framebuffer_funcs *funcs);
extern void drm_mode_config_init(struct drm_device *dev);
extern void drm_kms_helper_poll_fini(struct drm_device *dev);
extern void drm_sysfs_connector_remove(struct drm_connector *connector);
extern void drm_mode_config_cleanup(struct drm_device *dev);
extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, struct drm_encoder *encoder);
extern bool drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
extern int drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder, const struct drm_encoder_funcs *funcs, int encoder_type);
extern int drm_dp_bw_code_to_link_rate(u8 link_bw);
extern u8 drm_dp_max_lane_count(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
extern u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
extern bool drm_probe_ddc(struct i2c_adapter *adapter);
extern struct edid *drm_edid_duplicate(const struct edid *edid);
extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter);
extern bool drm_detect_monitor_audio(struct edid *edid);
extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, const struct drm_display_mode *mode);
extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
extern void drm_connector_cleanup(struct drm_connector *connector);
extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
extern int drm_mode_create_scaling_mode_property(struct drm_device *dev);
extern void drm_object_attach_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t init_val);
extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, struct edid *edid);
extern void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid);
extern int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, const struct drm_connector_funcs *funcs, int connector_type);
extern int drm_sysfs_connector_add(struct drm_connector *connector);
extern void drm_clflush_virt_range(char *addr, unsigned long length);
extern void drm_vma_node_unmap(struct drm_vma_offset_node *node, struct address_space *file_mapping);
extern bool drm_vma_node_has_offset(struct drm_vma_offset_node *node);
extern int drm_gem_create_mmap_offset(struct drm_gem_object *obj);
extern void drm_gem_free_mmap_offset(struct drm_gem_object *obj);
extern __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node);
extern bool drm_mm_node_allocated(struct drm_mm_node *node);
extern void drm_mm_remove_node(struct drm_mm_node *node);
extern void drm_clflush_sg(struct sg_table *st);
extern int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj, size_t size);
extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
extern void drm_gem_object_release(struct drm_gem_object *obj);
extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, size_t align);
extern void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
extern const char *drm_get_connector_name(const struct drm_connector *connector);
extern const char *drm_get_encoder_name(const struct drm_encoder *encoder);
extern const char *drm_get_format_name(uint32_t format);
extern void drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
extern int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, int *max_error, struct timeval *vblank_time, unsigned flags, const struct drm_crtc *refcrtc, const struct drm_display_mode *mode);
extern const char *drm_get_connector_status_name(enum drm_connector_status status);
extern void drm_kms_helper_hotplug_event(struct drm_device *dev);
extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
extern void drm_gem_private_object_init(struct drm_device *dev, struct drm_gem_object *obj, size_t size);
#ifdef __cplusplus
}
#endif /* extern "C" */
#endif /* _DRMP_H_ */

View File

@ -0,0 +1 @@
#include <lx_emul.h>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,627 @@
/*
* \brief Emulation of Linux kernel interfaces
* \author Norman Feske
* \date 2015-08-19
*/
/* local includes */
#include "lx_emul_private.h"
/* Genode includes */
#include <base/printf.h>
/* DRM-specific includes */
extern "C" {
#include <drm/drmP.h>
#include <i915/i915_drv.h>
#include <i915/intel_drv.h>
}
void lx_printf(char const *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
}
void lx_vprintf(char const *fmt, va_list va)
{
Genode::vprintf(fmt, va);
}
/****************************************
** Common Linux kernel infrastructure **
****************************************/
#include <lx_emul/impl/kernel.h>
int oops_in_progress;
/********************
** linux/string.h **
********************/
char *strncpy(char *dst, const char* src, size_t n)
{
return Genode::strncpy(dst, src, n);
}
/*****************
** linux/dmi.h **
*****************/
int dmi_check_system(const struct dmi_system_id *list)
{
TRACE;
/*
* Is used to check for quirks of the platform.
*/
return 0;
}
/*******************
** linux/delay.h **
*******************/
#include <lx_emul/impl/delay.h>
/**********************
** Global variables **
**********************/
struct task_struct *current;
struct boot_cpu_data boot_cpu_data;
/*******************
** Kernel memory **
*******************/
#include <lx_emul/impl/slab.h>
#include <lx_emul/impl/gfp.h>
dma_addr_t page_to_phys(void *p)
{
struct page *page = (struct page *)p;
dma_addr_t const phys = Lx::Malloc::dma().phys_addr(page->addr);
PDBG("virt=0x%lx -> phys=0x%lx", (long)page->addr, phys);
return phys;
}
/*****************
** linux/idr.h **
*****************/
void idr_init(struct idr *idp)
{
TRACE;
}
int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
{
TRACE;
/*
* Called from i915_gem_context.c: create_hw_context()
*/
return 0;
}
int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, gfp_t gfp_mask)
{
/*
* Called by drm_crtc.c: drm_connector_init to allocate a connector_type_id
*/
TRACE;
return 0;
}
/**********************
** asm/cacheflush.h **
**********************/
int set_pages_uc(struct page *page, int numpages)
{
TRACE;
return 0;
}
/********************
** linux/ioport.h **
********************/
struct resource iomem_resource;
/*********
** PCI **
*********/
#include <lx_emul/impl/io.h>
#include <lx_emul/impl/pci.h>
struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
{
if (bus != 0 || devfn != 0)
TRACE_AND_STOP;
pci_dev *pci_dev = nullptr;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
/* request bus address of device from platform driver */
unsigned char dev_bus = 0, dev_slot = 0, dev_fn = 0;
client.bus_address(&dev_bus, &dev_slot, &dev_fn);
if (dev_bus == bus && PCI_SLOT(devfn) == dev_slot && PCI_FUNC(devfn) == dev_fn) {
Lx::Pci_dev *dev = new (Genode::env()->heap()) Lx::Pci_dev(cap);
Lx::pci_dev_registry()->insert(dev);
pci_dev = dev;
return true;
}
return false;
};
Lx::for_each_pci_device(lamda);
return pci_dev;
}
struct pci_dev *pci_get_class(unsigned int class_code, struct pci_dev *from)
{
/*
* The function is solely called by the i915 initialization code to
* probe for the ISA bridge device in order to detect the hardware
* generation.
*
* We look up the bridge but don't need to support the iteration over
* multiple devices of the given class.
*/
if (from)
return nullptr;
pci_dev *pci_dev = nullptr;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
if (client.class_code() == class_code) {
pci_dev = new (Genode::env()->heap()) Lx::Pci_dev(cap);
return true;
}
return false;
};
Lx::for_each_pci_device(lamda);
return pci_dev;
}
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
{
return pci_ioremap_bar(dev, bar);
}
struct pci_dev *pci_dev_get(struct pci_dev *dev)
{
TRACE;
return dev;
};
int vga_get_uninterruptible(struct pci_dev *pdev, unsigned int rsrc)
{
/*
* This function locks the VGA device. It is normally provided by the
* VGA arbiter in the Linux kernel. We don't need this arbitration because
* the platform-driver enforces the exclusive access to the VGA resources
* by our driver.
*
* At the time when this function is called, the 'pci_dev' structure for
* the VGA card was already requested. Hence, subsequent I/O accesses
* should work.
*/
TRACE;
return 0;
}
void vga_put(struct pci_dev *pdev, unsigned int rsrc)
{
TRACE;
}
int pci_bus_alloc_resource(struct pci_bus *, struct resource *, resource_size_t,
resource_size_t, resource_size_t, unsigned int,
resource_size_t (*)(void *, const struct resource *, resource_size_t, resource_size_t),
void *alignf_data)
{
TRACE;
return 0;
}
void pci_set_master(struct pci_dev *dev)
{
TRACE;
}
int pci_enable_msi(struct pci_dev *dev)
{
TRACE;
return 0;
}
struct io_mapping
{
private:
resource_size_t _base;
unsigned long _size;
public:
/**
* Constructor
*/
io_mapping(resource_size_t base, unsigned long size) :
_base(base), _size(size) { }
resource_size_t base() const { return _base; }
};
/**
* I/O mapping used by i915_dma.c to map the GTT aperture
*/
struct io_mapping *io_mapping_create_wc(resource_size_t base, unsigned long size)
{
static int called;
TRACE;
if (called++ != 0) {
PERR("io_mapping_create_wc unexpectedly called twice");
return 0;
}
io_mapping *mapping = new (Genode::env()->heap()) io_mapping(base, size);
return mapping;
}
/****************
** linux/io.h **
****************/
int arch_phys_wc_add(unsigned long base, unsigned long size)
{
/*
* Linux tries to manipulate physical memory attributes here (e.g.,
* using MTRRs). But when using PAT, this is not needed. When running
* on top of a microkernel, we cannot manipulate the attributes
* anyway.
*/
TRACE;
return 0;
}
/********************
** linux/device.h **
********************/
struct subsys_private { int dummy; };
int bus_register(struct bus_type *bus)
{
/*
* called by i2c-core init
*
* The subsequent code checks for the 'p' member of the 'bus'. So
* we have to supply a valid pointer there.
*/
static subsys_private priv = { 0 };
bus->p = &priv;
TRACE;
return 0;
}
int driver_register(struct device_driver *drv)
{
TRACE;
return 0;
}
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data,
int (*fn)(struct device *dev, void *data))
{
/*
* Called bu the i2c-core driver after registering the driver. This
* function is called to process drivers that are present at initialization
* time. Since we initialize the i2c driver prior the others, we don't
* need to perform anything.
*/
TRACE;
return 0;
}
int dev_set_name(struct device *dev, const char *name, ...)
{
PDBG("name=%s", name);
TRACE;
return 0;
}
int device_register(struct device *dev)
{
TRACE;
return 0;
}
/***********************
** linux/workqueue.h **
***********************/
struct workqueue_struct *create_singlethread_workqueue(char const *)
{
workqueue_struct *wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
return wq;
}
struct workqueue_struct *alloc_ordered_workqueue(char const *name , unsigned int flags, ...)
{
return create_singlethread_workqueue(name);
}
/***************
** Execution **
***************/
#include <lx_emul/impl/spinlock.h>
#include <lx_emul/impl/mutex.h>
#include <lx_emul/impl/sched.h>
#include <lx_emul/impl/timer.h>
#include <lx_emul/impl/completion.h>
#include <lx_emul/impl/wait.h>
void __wait_completion(struct completion *work)
{
TRACE_AND_STOP;
}
void mutex_lock_nest_lock(struct mutex *lock, struct mutex *)
{
TRACE;
/*
* Called by drm_crtc.c: drm_modeset_lock_all, drm_crtc_init to
* lock the crtc mutex.
*/
mutex_lock(lock);
}
/************************
** DRM implementation **
************************/
unsigned int drm_debug = 1;
extern "C" int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
{
PDBG("call pci_register_driver");
return pci_register_driver(pdriver);
}
struct drm_device *drm_dev_alloc(struct drm_driver *driver, struct device *parent)
{
struct drm_device *dev = (drm_device *)kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return nullptr;
dev->driver = driver;
spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->event_lock);
mutex_init(&dev->struct_mutex);
// ret = drm_gem_init(dev);
// if (ret) {
// PERR("drm_gem_init failed");
// return nullptr;
// }
return dev;
}
/*
* Called indirectly when 'pci_register_driver' has found a matching
* device.
*/
int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
{
drm_device *dev = drm_dev_alloc(driver, &pdev->dev);
if (!dev)
return -ENOMEM;
// ret = pci_enable_device(pdev);
dev->pdev = pdev;
pci_set_drvdata(pdev, dev);
// drm_pci_agp_init(dev);
/*
* Kick off the actual driver initialization code
*
* In the Linux DRM code, this happens indirectly via the call of
* 'drm_dev_register'.
*/
driver->load(dev, ent->driver_data);
DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
driver->name, driver->major, driver->minor, driver->patchlevel,
driver->date, pci_name(pdev), dev->primary->index);
return 0;
}
/**
* Called from 'i915_driver_load'
*/
int drm_vblank_init(struct drm_device *dev, int num_crtcs)
{
TRACE;
return 0;
}
int drm_irq_install(struct drm_device *dev)
{
TRACE;
return 0;
}
/**************************************
** Stubs for non-ported driver code **
**************************************/
void intel_pm_setup(struct drm_device *dev)
{
TRACE;
}
void intel_init_pm(struct drm_device *dev)
{
TRACE;
}
int intel_power_domains_init(struct drm_device *dev)
{
TRACE;
return 0;
}
void intel_power_domains_init_hw(struct drm_device *dev)
{
TRACE;
}
void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class, s32 value)
{
TRACE;
}
void intel_disable_gt_powersave(struct drm_device *dev)
{
TRACE;
}
void intel_setup_bios(struct drm_device *dev)
{
TRACE;
}
int intel_parse_bios(struct drm_device *dev)
{
TRACE;
return -1;
}
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
{
TRACE;
}
int register_shrinker(struct shrinker *)
{
TRACE;
return 0;
}
int vga_client_register(struct pci_dev *pdev, void *cookie, void (*irq_set_state)(void *cookie, bool state), unsigned int (*set_vga_decode)(void *cookie, bool state))
{
TRACE;
return -ENODEV;
}
int vga_switcheroo_register_client(struct pci_dev *dev, const struct vga_switcheroo_client_ops *ops, bool driver_power_control)
{
TRACE;
return 0;
}
int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
{
TRACE;
return 0;
}
struct i915_ctx_hang_stats * i915_gem_context_get_hang_stats(struct drm_device *dev, struct drm_file *file, u32 id)
{
TRACE_AND_STOP;
return NULL;
}
struct resource * devm_request_mem_region(struct device *dev, resource_size_t start, resource_size_t n, const char *name)
{
/*
* This function solely called for keeping the stolen memory preserved
* for the driver only ('i915_stolen_to_physical'). The returned pointer is
* just checked for NULL but not used otherwise.
*/
TRACE;
static struct resource dummy;
return &dummy;
}
DEFINE_SPINLOCK(mchdev_lock);

View File

@ -0,0 +1,28 @@
/*
* \brief Local definitions of the Linux kernel API implementation
* \author Norman Feske
* \date 2015-08-24
*/
#ifndef _LX_EMUL_PRIVATE_H_
#define _LX_EMUL_PRIVATE_H_
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
/* Linux kernel API */
#include <lx_emul.h>
#define TRACE \
do { \
PLOG("%s not implemented", __func__); \
} while (0)
#define TRACE_AND_STOP \
do { \
PWRN("%s not implemented", __func__); \
Genode::sleep_forever(); \
} while (0)
#endif /* _LX_EMUL_PRIVATE_H_ */

View File

@ -0,0 +1,115 @@
/*
* \brief Intel framebuffer driver
* \author Norman Feske
* \date 2015-08-19
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
#include <os/server.h>
/* Linux emulation environment includes */
#include <lx_emul.h>
#include <lx_emul/impl/internal/scheduler.h>
#include <lx_emul/impl/internal/timer.h>
#include <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/pci_backend_alloc.h>
namespace Server { struct Main; }
Lx::Scheduler & Lx::scheduler()
{
static Lx::Scheduler inst;
return inst;
}
Lx::Timer & Lx::timer(Server::Entrypoint *ep, unsigned long *jiffies)
{
return _timer_impl(ep, jiffies);
}
Platform::Connection *Lx::pci()
{
static Platform::Connection _pci;
return &_pci;
}
Lx::Pci_dev_registry *Lx::pci_dev_registry()
{
static Lx::Pci_dev_registry _pci_dev_registry;
return &_pci_dev_registry;
}
namespace Lx {
Genode::Object_pool<Memory_object_base> memory_pool;
};
extern "C" int postcore_i2c_init(); /* i2c-core.c */
extern "C" int module_i915_init(); /* i915_drv.c */
static void run_linux(void *)
{
PDBG("postcore_i915_init");
postcore_i2c_init();
PDBG("module_i915_init");
module_i915_init();
while (1) {
Lx::scheduler().current()->block_and_schedule();
}
}
unsigned long jiffies;
struct Server::Main
{
Entrypoint &ep;
/* init singleton Lx::Timer */
Lx::Timer &timer = Lx::timer(&ep, &jiffies);
/* Linux task that handles the initialization */
Lx::Task linux { run_linux, nullptr, "linux",
Lx::Task::PRIORITY_0, Lx::scheduler() };
Main(Entrypoint &ep) : ep(ep)
{
Genode::printf("--- intel framebuffer driver ---\n");
/* give all task a first kick before returning */
Lx::scheduler().schedule();
PDBG("returning from main");
}
};
namespace Server {
char const *name() { return "intel_fb_ep"; }
size_t stack_size() { return 8*1024*sizeof(long); }
void construct(Entrypoint &ep)
{
static Main main(ep);
}
}

View File

@ -0,0 +1,5 @@
TARGET = intel_fb_drv
LIBS = base intel_fb_drv intel_fb_include libc-setjmp server
SRC_CC = main.cc lx_emul.cc dummies.cc
SRC_C = i2c-algo-bit.c
INC_DIR += $(REP_DIR)/src/include

View File

@ -0,0 +1,111 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************
** asm/cmpxchg.h **
*******************/
#define cmpxchg(ptr, o, n) ({ \
typeof(*ptr) prev = *ptr; \
*ptr = (*ptr == o) ? n : *ptr; \
prev;\
})
#define xchg(ptr, x) ({ \
typeof(*ptr) old = *ptr; \
*ptr = x; \
old; \
})
#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v)))
/******************
** asm/atomic.h **
******************/
#include <asm-generic/atomic64.h>
#define ATOMIC_INIT(i) { (i) }
typedef struct atomic { long counter; } atomic_t;
typedef atomic_t atomic_long_t;
static inline int atomic_read(const atomic_t *p) { return p->counter; }
static inline void atomic_set(atomic_t *p, int i) { p->counter = i; }
static inline void atomic_sub(int i, atomic_t *p) { p->counter -= i; }
static inline void atomic_add(int i, atomic_t *p) { p->counter += i; }
static inline int atomic_sub_return(int i, atomic_t *p) { p->counter -= i; return p->counter; }
static inline int atomic_add_return(int i, atomic_t *p) { p->counter += i; return p->counter; }
static inline int atomic_sub_and_test(int i, atomic_t *p) { return atomic_sub_return(i, p) == 0; }
static inline void atomic_dec(atomic_t *p) { atomic_sub(1, p); }
static inline void atomic_inc(atomic_t *p) { atomic_add(1, p); }
static inline int atomic_dec_return(atomic_t *p) { return atomic_sub_return(1, p); }
static inline int atomic_inc_return(atomic_t *p) { return atomic_add_return(1, p); }
static inline int atomic_dec_and_test(atomic_t *p) { return atomic_sub_and_test(1, p); }
static inline int atomic_inc_not_zero(atomic_t *p) { return p->counter ? atomic_inc_return(p) : 0; }
static inline void atomic_long_inc(atomic_long_t *p) { atomic_add(1, p); }
static inline void atomic_long_sub(int i, atomic_long_t *p) { atomic_sub(i, p); }
static inline long atomic_long_add_return(long i, atomic_long_t *p) { return atomic_add_return(i, p); }
static inline long atomic_long_read(atomic_long_t *p) { return atomic_read(p); }
static inline int atomic_cmpxchg(atomic_t *v, int old, int n)
{
return cmpxchg(&v->counter, old, n);
}
static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint)
{
int val, c = hint;
/* sanity test, should be removed by compiler if hint is a constant */
if (!hint)
return atomic_inc_not_zero(v);
do {
val = atomic_cmpxchg(v, c, c + 1);
if (val == c)
return 1;
c = val;
} while (c);
return 0;
}
static inline int atomic_add_unless(atomic_t *v, int a, int u)
{
int ret;
unsigned long flags;
(void)flags;
ret = v->counter;
if (ret != u)
v->counter += a;
return ret != u;
}
#define smp_mb__before_atomic_dec()
/*******************************
** asm-generic/atomic-long.h **
*******************************/
#define ATOMIC_LONG_INIT(i) ATOMIC_INIT(i)

View File

@ -0,0 +1,111 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************************
** asm-generic/bitsperlong.h **
*******************************/
#define BITS_PER_LONG (__SIZEOF_LONG__ * 8)
/**********************************
** linux/bitops.h, asm/bitops.h **
**********************************/
#define BITS_PER_BYTE 8
#define BIT(nr) (1UL << (nr))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#include <asm-generic/bitops/non-atomic.h>
#define test_and_clear_bit(nr, addr) \
__test_and_clear_bit(nr, (volatile unsigned long *)(addr))
#define test_and_set_bit(nr, addr) \
__test_and_set_bit(nr, (volatile unsigned long *)(addr))
#define set_bit(nr, addr) \
__set_bit(nr, (volatile unsigned long *)(addr))
#define clear_bit(nr, addr) \
__clear_bit(nr, (volatile unsigned long *)(addr))
#define smp_mb__before_clear_bit()
#define smp_mb__after_clear_bit() smp_mb()
/**
* Find first zero bit (limit to machine word size)
*/
long find_next_zero_bit_le(const void *addr,
unsigned long size, unsigned long offset);
#include <asm-generic/bitops/__ffs.h>
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/ffs.h>
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/fls64.h>
static inline unsigned fls_long(unsigned long l)
{
if (sizeof(l) == 4)
return fls(l);
return fls64(l);
}
static inline unsigned long __ffs64(u64 word)
{
#if BITS_PER_LONG == 32
if (((u32)word) == 0UL)
return __ffs((u32)(word >> 32)) + 32;
#elif BITS_PER_LONG != 64
#error BITS_PER_LONG not 32 or 64
#endif
return __ffs((unsigned long)word);
}
#include <linux/log2.h>
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
(bit) < (size); \
(bit) = find_next_bit((addr), (size), (bit) + 1))
static inline int get_bitmask_order(unsigned int count) {
return __builtin_clz(count) ^ 0x1f; }
static inline __s32 sign_extend32(__u32 value, int index)
{
__u8 shift = 31 - index;
return (__s32)(value << shift) >> shift;
}
static inline __u32 rol32(__u32 word, unsigned int shift)
{
return (word << shift) | (word >> (32 - shift));
}
static inline __u32 ror32(__u32 word, unsigned int shift)
{
return (word >> shift) | (word << (32 - shift));
}
static inline __u16 ror16(__u16 word, unsigned int shift)
{
return (word >> shift) | (word << (16 - shift));
}

View File

@ -0,0 +1,40 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/***************
** asm/bug.h **
***************/
#define WARN_ON(condition) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] WARN_ON(" #condition ") ", __func__); \
ret; })
#define WARN(condition, fmt, arg...) ({ \
int ret = !!(condition); \
if (ret) lx_printf("[%s] *WARN* " fmt , __func__ , ##arg); \
ret; })
#define BUG() do { \
lx_printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
while (1); \
} while (0)
#define WARN_ON_ONCE WARN_ON
#define WARN_ONCE WARN
#define BUG_ON(condition) do { if (condition) BUG(); } while(0)

View File

@ -0,0 +1,48 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*************************************
** linux/byteorder/little_endian.h **
*************************************/
#include <uapi/linux/byteorder/little_endian.h>
/*******************************
** linux/byteorder/generic.h **
*******************************/
#define le16_to_cpu __le16_to_cpu
#define be16_to_cpu __be16_to_cpu
#define le32_to_cpu __le32_to_cpu
#define be32_to_cpu __be32_to_cpu
#define le16_to_cpus __le16_to_cpus
#define cpu_to_le16p __cpu_to_le16p
#define cpu_to_be16p __cpu_to_be16p
#define cpu_to_le16 __cpu_to_le16
#define cpu_to_le16s __cpu_to_le16s
#define cpu_to_be16 __cpu_to_be16
#define cpu_to_le32 __cpu_to_le32
#define cpu_to_be32 __cpu_to_be32
#define cpu_to_le32s __cpu_to_le32s
#define cpu_to_le64 __cpu_to_le64
#define le16_to_cpup __le16_to_cpup
#define be16_to_cpup __be16_to_cpup
#define le32_to_cpup __le32_to_cpup
#define le32_to_cpus __le32_to_cpus
#define be32_to_cpup __be32_to_cpup
#define le64_to_cpu __le64_to_cpu

View File

@ -0,0 +1,70 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/**********************
** linux/compiler.h **
**********************/
#define likely
#define unlikely
#define __user
#define __iomem
#define __rcu
#define __percpu
#define __must_check
#define __force
#define __read_mostly
#define __releases(x) /* needed by usb/core/devio.c */
#define __acquires(x) /* needed by usb/core/devio.c */
#define __force
#define __maybe_unused
#define __bitwise
# define __acquire(x) (void)0
# define __release(x) (void)0
#define __must_check
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
#define __attribute_const__
#undef __always_inline
#define __always_inline
#undef __unused
#define noinline __attribute__((noinline))
#define __printf(a, b) __attribute__((format(printf, a, b)))
#define __always_unused
#define __read_mostly
#define __noreturn __attribute__((noreturn))
/**************************
** linux/compiler-gcc.h **
**************************/
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#define uninitialized_var(x) x = x

View File

@ -0,0 +1,126 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************************
** linux/errno.h and friends **
*******************************/
/**
* Error codes
*
* Note that the codes do not correspond to those of the Linux kernel.
*/
enum {
/*
* The following numbers correspond to FreeBSD
*/
EPERM = 1,
ENOENT = 2,
ESRCH = 3,
EINTR = 4,
EIO = 5,
ENXIO = 6,
E2BIG = 7,
EDEADLK = 11,
ENOMEM = 12,
EACCES = 13,
EFAULT = 14,
EBUSY = 16,
EEXIST = 17,
EXDEV = 18,
ENODEV = 19,
EINVAL = 22,
ENFILE = 23,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
EPIPE = 32,
EDOM = 33,
ERANGE = 34,
EAGAIN = 35,
EINPROGRESS = 36,
EALREADY = 37,
ENOTSOCK = 38,
EDESTADDRREQ = 39,
EMSGSIZE = 40,
ENOPROTOOPT = 42,
EPROTONOSUPPORT = 43,
ESOCKTNOSUPPORT = 44,
EOPNOTSUPP = 45,
EPFNOSUPPORT = 46,
EAFNOSUPPORT = 47,
EADDRINUSE = 48,
EADDRNOTAVAIL = 49,
ENETDOWN = 50,
ENETUNREACH = 51,
ECONNABORTED = 53,
ECONNRESET = 54,
ENOBUFS = 55,
EISCONN = 56,
ENOTCONN = 57,
ETIMEDOUT = 60,
ECONNREFUSED = 61,
ENAMETOOLONG = 63,
EHOSTDOWN = 64,
EHOSTUNREACH = 65,
ENOSYS = 78,
ENOMSG = 83,
EOVERFLOW = 84,
ECANCELED = 85,
EILSEQ = 86,
EBADMSG = 89,
ENOLINK = 91,
EPROTO = 92,
/*
* The following numbers correspond to nothing
*/
EREMOTEIO = 200,
ERESTARTSYS = 201,
ENODATA = 202,
ETOOSMALL = 203,
ENOIOCTLCMD = 204,
ENONET = 205,
ENOTSUPP = 206,
ENOTUNIQ = 207,
ERFKILL = 208,
ETIME = 209,
MAX_ERRNO = 4095,
};
/*****************
** linux/err.h **
*****************/
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline bool IS_ERR(void const *ptr) {
return (unsigned long)(ptr) > (unsigned long)(-1000); }
static inline void * ERR_PTR(long error) {
return (void *) error; }
static inline void * ERR_CAST(const void *ptr) {
return (void *) ptr; }
static inline long IS_ERR_OR_NULL(const void *ptr) {
return !ptr || IS_ERR_VALUE((unsigned long)ptr); }
static inline long PTR_ERR(const void *ptr) { return (long) ptr; }

View File

@ -0,0 +1,30 @@
/*
* \brief Include before including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifdef __cplusplus
#define extern_c_begin
extern "C" {
/* some warnings should only be switched of for Linux headers */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpointer-arith"
#pragma GCC diagnostic ignored "-Wsign-compare"
/* deal with C++ keywords used for identifiers etc. */
#define private private_
#define class class_
#define new new_
#endif /* __cplusplus */

View File

@ -0,0 +1,24 @@
/*
* \brief Include after including Linux headers in C++
* \author Christian Helmuth
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifdef __cplusplus
#undef new
#undef class
#undef private
#pragma GCC diagnostic pop
} /* extern "C" */
#endif /* __cplusplus */

View File

@ -0,0 +1,58 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*****************
** linux/gfp.h **
*****************/
enum {
__GFP_DMA = 0x00000001u,
__GFP_HIGHMEM = 0x00000002u,
__GFP_DMA32 = 0x00000004u,
__GFP_MOVABLE = 0x00000008u,
__GFP_WAIT = 0x00000010u,
__GFP_HIGH = 0x00000020u,
__GFP_IO = 0x00000040u,
__GFP_FS = 0x00000080u,
__GFP_COLD = 0x00000100u,
__GFP_NOWARN = 0x00000200u,
__GFP_REPEAT = 0x00000400u,
__GFP_NOFAIL = 0x00000800u,
__GFP_NORETRY = 0x00001000u,
__GFP_MEMALLOC = 0x00002000u,
__GFP_COMP = 0x00004000u,
__GFP_ZERO = 0x00008000u,
__GFP_NOMEMALLOC = 0x00010000u,
__GFP_HARDWALL = 0x00020000u,
__GFP_THISNODE = 0x00040000u,
__GFP_RECLAIMABLE = 0x00080000u,
__GFP_KMEMCG = 0x00100000u,
__GFP_NOTRACK = 0x00200000u,
__GFP_NO_KSWAPD = 0x00400000u,
__GFP_OTHER_NODE = 0x00800000u,
__GFP_WRITE = 0x01000000u,
GFP_LX_DMA = 0x80000000u,
GFP_ATOMIC = __GFP_HIGH,
GFP_DMA = __GFP_DMA,
GFP_DMA32 = __GFP_DMA32,
GFP_KERNEL = __GFP_WAIT | __GFP_IO | __GFP_FS,
GFP_USER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL,
GFP_HIGHUSER = __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL |
__GFP_HIGHMEM,
};

View File

@ -0,0 +1,112 @@
/*
* \brief Implementation of linux/completion.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
typedef Lx::Task::List_element Wait_le;
typedef Lx::Task::List Wait_list;
void init_waitqueue_head(wait_queue_head_t *wq)
{
wq->list = new (Genode::env()->heap()) Wait_list;
}
int waitqueue_active(wait_queue_head_t *wq)
{
Wait_list *list = static_cast<Wait_list*>(wq->list);
if (!list)
return 0;
return list->first() ? 1 : 0;
}
void __wake_up(wait_queue_head_t *wq, bool all)
{
Wait_list *list = static_cast<Wait_list *>(wq->list);
if (!list) {
PWRN("wait_queue_head_t is empty, wq: %p called from: %p", wq, __builtin_return_address(0));
return;
}
Wait_le *le = list->first();
do {
if (!le)
return;
le->object()->unblock();
} while (all && (le = le->next()));
}
void wake_up_interruptible_sync_poll(wait_queue_head_t *wq, int)
{
__wake_up(wq, false);
}
void __wait_event(wait_queue_head_t wq)
{
Wait_list *list = static_cast<Wait_list *>(wq.list);
if (!list) {
PERR("__wait_event(): empty list in wq: %p", &wq);
Genode::sleep_forever();
}
Lx::Task *task = Lx::scheduler().current();
task->wait_enqueue(list);
task->block_and_schedule();
task->wait_dequeue(list);
}
void init_completion(struct completion *work)
{
work->done = 0;
}
void complete(struct completion *work)
{
work->done = 1;
}
unsigned long wait_for_completion_timeout(struct completion *work,
unsigned long timeout)
{
__wait_completion(work);
return 1;
}
int wait_for_completion_interruptible(struct completion *work)
{
__wait_completion(work);
return 0;
}
long wait_for_completion_interruptible_timeout(struct completion *work,
unsigned long timeout)
{
__wait_completion(work);
return 1;
}
void wait_for_completion(struct completion *work)
{
__wait_completion(work);
}

View File

@ -0,0 +1,30 @@
/*
* \brief Implementation of linux/delay.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <timer_session/connection.h>
/*
* XXX We may consider to use the Lx::Timer instead of opening a dedicated
* timer session.
*/
static Timer::Connection _delay_timer;
void udelay(unsigned long usecs) { _delay_timer.usleep(usecs); }
void msleep(unsigned int msecs) { _delay_timer.msleep(msecs); }
void mdelay(unsigned long msecs) { msleep(msecs); }

View File

@ -0,0 +1,43 @@
/*
* \brief Implementation of linux/gfp.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/addr_to_page_mapping.h>
#include <lx_emul/impl/internal/malloc.h>
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
size_t size = PAGE_SIZE << order;
page->addr = Lx::Malloc::dma().alloc(size, 12);
if (!page->addr) {
PERR("alloc_pages: %zu failed", size);
kfree(page);
return 0;
}
Lx::Addr_to_page_mapping::insert(page);
atomic_set(&page->_count, 1);
return page;
}
void get_page(struct page *page)
{
atomic_inc(&page->_count);
}

View File

@ -0,0 +1,78 @@
/*
* \brief Address-to-page mapping helper
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_
#define _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/malloc.h>
#include <lx_emul/impl/internal/list.h>
namespace Lx { class Addr_to_page_mapping; }
class Lx::Addr_to_page_mapping : public Lx::List<Addr_to_page_mapping>::Element
{
private:
unsigned long _addr { 0 };
struct page *_page { 0 };
static Genode::List<Addr_to_page_mapping> *_list()
{
static Genode::List<Addr_to_page_mapping> _l;
return &_l;
}
public:
Addr_to_page_mapping(unsigned long addr, struct page *page)
: _addr(addr), _page(page) { }
static void insert(struct page *page)
{
Addr_to_page_mapping *m = (Addr_to_page_mapping*)
Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping));
m->_addr = (unsigned long)page->addr;
m->_page = page;
_list()->insert(m);
}
static void remove(struct page *page)
{
Addr_to_page_mapping *mp = 0;
for (Addr_to_page_mapping *m = _list()->first(); m; m = m->next())
if (m->_page == page)
mp = m;
if (mp) {
_list()->remove(mp);
Lx::Malloc::mem().free(mp);
}
}
static struct page* find_page(unsigned long addr)
{
for (Addr_to_page_mapping *m = _list()->first(); m; m = m->next())
if (m->_addr == addr)
return m->_page;
return 0;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__ADDR_TO_PAGE_MAPPING_H_ */

View File

@ -0,0 +1,23 @@
/*
* \brief Debug utilities
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__DEBUG_H_
#define _LX_EMUL__IMPL__INTERNAL__DEBUG_H_
#ifndef PDBGV
#define PDBGV(...) do { if (verbose) PDBG(__VA_ARGS__); } while (0)
#endif
#endif /* _LX_EMUL__IMPL__INTERNAL__DEBUG_H_ */

View File

@ -0,0 +1,83 @@
/*
* \brief I/O port access helper
* \author Sebastian Sumpf
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_
#define _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_
/* Genode includes */
#include <util/volatile_object.h>
#include <io_port_session/client.h>
namespace Lx { class Io_port; }
class Lx::Io_port
{
private:
unsigned _base = 0;
unsigned _size = 0;
Genode::Io_port_session_capability _cap;
Genode::Lazy_volatile_object<Genode::Io_port_session_client> _port;
bool _valid(unsigned port) {
return _cap.valid() && port >= _base && port < _base + _size; }
public:
~Io_port()
{
if (_cap.valid())
_port.destruct();
}
void session(unsigned base, unsigned size, Genode::Io_port_session_capability cap)
{
_base = base;
_size = size;
_cap = cap;
_port.construct(_cap);
}
template<typename POD>
bool out(unsigned port, POD val)
{
if (!_valid(port))
return false;
switch (sizeof(POD)) {
case 1: _port->outb(port, val); break;
case 2: _port->outw(port, val); break;
case 4: _port->outl(port, val); break;
}
return true;
}
template<typename POD>
bool in(unsigned port, POD *val)
{
if (!_valid(port))
return false;;
switch (sizeof(POD)) {
case 1: *val = _port->inb(port); break;
case 2: *val = _port->inw(port); break;
case 4: *val = _port->inl(port); break;
}
return true;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__IO_PORT_H_ */

View File

@ -0,0 +1,102 @@
/*
* \brief Slightly improved list
* \author Christian Helmuth
* \date 2014-09-25
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__LIST_H_
#define _LX_EMUL__IMPL__INTERNAL__LIST_H_
#include <util/list.h>
namespace Lx {
template <typename> class List;
template <typename> class List_element;
}
template <typename LT>
class Lx::List : private Genode::List<LT>
{
private:
typedef Genode::List<LT> Base;
public:
using Base::Element;
void append(LT const *le)
{
LT *at = nullptr;
for (LT *l = first(); l; l = l->next())
at = l;
Base::insert(le, at);
}
void prepend(LT const *le)
{
Base::insert(le);
}
void insert_before(LT const *le, LT const *at)
{
if (at == first()) {
prepend(le);
return;
} else if (!at) {
append(le);
return;
}
for (LT *l = first(); l; l = l->next())
if (l->next() == at)
at = l;
Base::insert(le, at);
}
/****************************
** Genode::List interface **
****************************/
LT *first() { return Base::first(); }
LT const *first() const { return Base::first(); }
void insert(LT const *le, LT const *at = 0)
{
Base::insert(le, at);
}
void remove(LT const *le)
{
Base::remove(le);
}
};
template <typename T>
class Lx::List_element : public Lx::List<List_element<T> >::Element
{
private:
T *_object;
public:
List_element(T *object) : _object(object) { }
T *object() const { return _object; }
};
#endif /* _LX_EMUL__IMPL__INTERNAL__LIST_H_ */

View File

@ -0,0 +1,208 @@
/*
* \brief Linux kernel memory allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__MALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__MALLOC_H_
#include <lx_emul/impl/internal/slab_alloc.h>
#include <lx_emul/impl/internal/slab_backend_alloc.h>
namespace Lx { class Malloc; }
class Lx::Malloc
{
private:
enum {
SLAB_START_LOG2 = 3, /* 8 B */
SLAB_STOP_LOG2 = 16, /* 64 KiB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
typedef Genode::addr_t addr_t;
typedef Lx::Slab_alloc Slab_alloc;
typedef Lx::Slab_backend_alloc Slab_backend_alloc;
Slab_backend_alloc &_back_allocator;
Slab_alloc *_allocator[NUM_SLABS];
Genode::Cache_attribute _cached; /* cached or un-cached memory */
addr_t _start; /* VM region of this allocator */
addr_t _end;
/**
* Set 'value' at 'addr'
*/
void _set_at(addr_t addr, addr_t value) { *((addr_t *)addr) = value; }
/**
* Retrieve slab index belonging to given address
*/
unsigned _slab_index(Genode::addr_t **addr)
{
using namespace Genode;
/* get index */
addr_t index = *(*addr - 1);
/*
* If index large, we use aligned memory, retrieve beginning of slab entry
* and read index from there
*/
if (index > 32) {
*addr = (addr_t *)*(*addr - 1);
index = *(*addr - 1);
}
return index;
}
/**
* Get the originally requested size of the allocation
*/
size_t _get_orig_size(Genode::addr_t **addr)
{
using namespace Genode;
addr_t index = *(*addr - 1);
if (index > 32) {
*addr = (addr_t *) * (*addr - 1);
}
return *(*addr - 2);
}
public:
Malloc(Slab_backend_alloc &alloc, Genode::Cache_attribute cached)
:
_back_allocator(alloc), _cached(cached), _start(alloc.start()),
_end(alloc.end())
{
/* init slab allocators */
for (unsigned i = SLAB_START_LOG2; i <= SLAB_STOP_LOG2; i++)
_allocator[i - SLAB_START_LOG2] = new (Genode::env()->heap())
Slab_alloc(1U << i, alloc);
}
/**
* Alloc in slabs
*/
void *alloc(Genode::size_t size, int align = 0, Genode::addr_t *phys = 0)
{
using namespace Genode;
/* save requested size */
size_t orig_size = size;
size += sizeof(addr_t);
/* += slab index + aligment size */
size += sizeof(addr_t) + (align > 2 ? (1 << align) : 0);
int msb = Genode::log2(size);
if (size > (1U << msb))
msb++;
if (size < (1U << SLAB_START_LOG2))
msb = SLAB_STOP_LOG2;
if (msb > SLAB_STOP_LOG2) {
// PERR("Slab too large %u reqested %zu cached %d", 1U << msb, size, _cached);
return 0;
}
addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
if (!addr) {
PERR("Failed to get slab for %u", 1 << msb);
return 0;
}
_set_at(addr, orig_size);
addr += sizeof(addr_t);
_set_at(addr, msb - SLAB_START_LOG2);
addr += sizeof(addr_t);
if (align > 2) {
/* save */
addr_t ptr = addr;
addr_t align_val = (1U << align);
addr_t align_mask = align_val - 1;
/* align */
addr = (addr + align_val) & ~align_mask;
/* write start address before aligned address */
_set_at(addr - sizeof(addr_t), ptr);
}
if (phys)
*phys = _back_allocator.phys_addr(addr);
return (addr_t *)addr;
}
void free(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
unsigned nr = _slab_index(&addr);
/* we need to decrease addr by 2, orig_size and index come first */
_allocator[nr]->free((void *)(addr - 2));
}
size_t size(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
/* XXX changes addr */
return _get_orig_size(&addr);
}
Genode::addr_t phys_addr(void *a)
{
return _back_allocator.phys_addr((addr_t)a);
}
Genode::addr_t virt_addr(Genode::addr_t phys)
{
return _back_allocator.virt_addr(phys);
}
/**
* Belongs given address to this allocator
*/
bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); }
/**
* Cached memory allocator
*/
static Malloc & mem()
{
static Malloc inst(Slab_backend_alloc::mem(), Genode::CACHED);
return inst;
}
/**
* DMA memory allocator
*/
static Malloc & dma()
{
static Malloc inst(Slab_backend_alloc::dma(), Genode::UNCACHED);
return inst;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__MALLOC_H_ */

View File

@ -0,0 +1,112 @@
/*
* \brief Representation of a locally-mapped MMIO range
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_
#define _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_
/* Genode includes */
#include <os/attached_dataspace.h>
#include <io_mem_session/io_mem_session.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/list.h>
namespace Lx {
class Mapped_io_mem_range;
void *ioremap(resource_size_t, unsigned long, Genode::Cache_attribute);
}
/**
* Representation of a locally-mapped MMIO range
*
* This class is supposed to be a private utility to support 'ioremap'.
*/
class Lx::Mapped_io_mem_range : public Lx::List<Mapped_io_mem_range>::Element
{
private:
Genode::Attached_dataspace _ds;
Genode::size_t const _size;
Genode::addr_t const _phys;
Genode::addr_t const _virt;
public:
Mapped_io_mem_range(Genode::addr_t phys, Genode::size_t size,
Genode::Io_mem_dataspace_capability ds_cap)
:
_ds(ds_cap),
_size(size),
_phys(phys),
_virt((Genode::addr_t)_ds.local_addr<void>() | (phys & 0xfffUL))
{ }
Genode::addr_t phys() const { return _phys; }
Genode::addr_t virt() const { return _virt; }
/**
* Return true if the mapped range contains the specified sub range
*/
bool contains(Genode::addr_t phys, Genode::size_t size) const
{
return (phys >= _phys) && (phys + size - 1 <= _phys + _size - 1);
}
};
void *Lx::ioremap(resource_size_t phys_addr, unsigned long size,
Genode::Cache_attribute cache_attribute)
{
using namespace Genode;
static Lx::List<Lx::Mapped_io_mem_range> ranges;
/* search for the requested region within the already mapped ranges */
for (Lx::Mapped_io_mem_range *r = ranges.first(); r; r = r->next()) {
if (r->contains(phys_addr, size)) {
void * const virt = (void *)(r->virt() + phys_addr - r->phys());
PLOG("ioremap: return sub range phys 0x%lx (size %lx) to virt 0x%lx",
(long)phys_addr, (long)size, (long)virt);
return virt;
}
}
Io_mem_dataspace_capability ds_cap =
Lx::pci_dev_registry()->io_mem(phys_addr, cache_attribute, size);
if (!ds_cap.valid()) {
PERR("Failed to request I/O memory: [%zx,%lx)", phys_addr,
phys_addr + size);
return nullptr;
}
Genode::size_t const ds_size = Genode::Dataspace_client(ds_cap).size();
Lx::Mapped_io_mem_range *io_mem =
new (env()->heap()) Lx::Mapped_io_mem_range(phys_addr, ds_size, ds_cap);
ranges.insert(io_mem);
PLOG("ioremap: mapped phys 0x%lx (size %lx) to virt 0x%lx",
(long)phys_addr, (long)size, (long)io_mem->virt());
addr_t const sub_page_offset = phys_addr & 0xfff;
return (void *)(io_mem->virt() + sub_page_offset);
}
#endif /* _LX_EMUL__IMPL__INTERNAL__MAPPED_IO_MEM_RANGE_H_ */

View File

@ -0,0 +1,110 @@
/*
* \brief Backend allocator for DMA-capable memory
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_
/* Genode includes */
#include <base/object_pool.h>
#include <base/env.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/slab_backend_alloc.h>
namespace Lx {
struct Memory_object_base;
struct Ram_object;
struct Dma_object;
extern Genode::Object_pool<Memory_object_base> memory_pool;
};
struct Lx::Memory_object_base : Genode::Object_pool<Memory_object_base>::Entry
{
Memory_object_base(Genode::Ram_dataspace_capability cap)
: Genode::Object_pool<Memory_object_base>::Entry(cap) {}
virtual ~Memory_object_base() {};
virtual void free() = 0;
Genode::Ram_dataspace_capability ram_cap()
{
using namespace Genode;
return reinterpret_cap_cast<Ram_dataspace>(cap());
}
};
struct Lx::Ram_object : Memory_object_base
{
Ram_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
void free() { Genode::env()->ram_session()->free(ram_cap()); }
};
struct Lx::Dma_object : Memory_object_base
{
Dma_object(Genode::Ram_dataspace_capability cap)
: Memory_object_base(cap) {}
void free() { Lx::pci()->free_dma_buffer(ram_cap()); }
};
Genode::Ram_dataspace_capability
Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
{
using namespace Genode;
Memory_object_base *o;
Genode::Ram_dataspace_capability cap;
if (cached == CACHED) {
cap = env()->ram_session()->alloc(size);
o = new (env()->heap()) Ram_object(cap);
} else {
/* transfer quota to pci driver, otherwise it will give us a exception */
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%ld", size);
Genode::env()->parent()->upgrade(Lx::pci()->cap(), buf);
cap = Lx::pci()->alloc_dma_buffer(size);
o = new (env()->heap()) Dma_object(cap);
}
memory_pool.insert(o);
return cap;
}
void Lx::backend_free(Genode::Ram_dataspace_capability cap)
{
using namespace Genode;
Memory_object_base *o = memory_pool.lookup_and_lock(cap);
if (!o)
return;
o->free();
memory_pool.remove_locked(o);
destroy(env()->heap(), o);
}
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_BACKEND_ALLOC_H_ */

View File

@ -0,0 +1,241 @@
/*
* \brief Emulate 'pci_dev' structure
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_
/* Genode includes */
#include <base/object_pool.h>
#include <platform_session/connection.h>
#include <platform_device/client.h>
#include <io_mem_session/connection.h>
#include <os/attached_dataspace.h>
#include <util/retry.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/debug.h>
#include <lx_emul/impl/internal/list.h>
#include <lx_emul/impl/internal/io_port.h>
namespace Lx {
class Pci_dev;
/**
* Return singleton 'Platform::Connection'
*
* Implementation must be privided by the driver.
*/
Platform::Connection *pci();
template <typename FUNC>
static inline void for_each_pci_device(FUNC const &func);
}
class Lx::Pci_dev : public pci_dev, public Lx::List<Pci_dev>::Element
{
private:
bool const verbose = true;
Platform::Device_client _client;
Io_port _io_port;
/* offset used in PCI config space */
enum Pci_config { IRQ = 0x3c, REV = 0x8, CMD = 0x4,
STATUS = 0x4, CAP = 0x34 };
enum Pci_cap { CAP_LIST = 0x10, CAP_EXP = 0x10,
CAP_EXP_FLAGS = 0x2, CAP_EXP_DEVCAP = 0x4 };
template <typename T>
Platform::Device::Access_size _access_size(T t)
{
switch (sizeof(T))
{
case 1:
return Platform::Device::ACCESS_8BIT;
case 2:
return Platform::Device::ACCESS_16BIT;
default:
return Platform::Device::ACCESS_32BIT;
}
}
public:
/**
* Constructor
*/
Pci_dev(Platform::Device_capability cap)
:
_client(cap)
{
using namespace Platform;
Genode::memset(static_cast<pci_dev *>(this), 0, sizeof(pci_dev));
this->vendor = _client.vendor_id();
this->device = _client.device_id();
this->class_ = _client.class_code();
this->revision = _client.config_read(REV, Device::ACCESS_8BIT);
/* dummy dma mask used to mark device as DMA capable */
this->dev._dma_mask_buf = ~(u64)0;
this->dev.dma_mask = &this->dev._dma_mask_buf;
this->dev.coherent_dma_mask = ~0;
/* read interrupt line */
this->irq = _client.config_read(IRQ, Device::ACCESS_8BIT);
/* hide ourselfs in bus structure */
this->bus = (struct pci_bus *)this;
/* setup resources */
bool io = false;
for (int i = 0; i < Device::NUM_RESOURCES; i++) {
Device::Resource res = _client.resource(i);
if (res.type() == Device::Resource::INVALID)
continue;
this->resource[i].start = res.base();
this->resource[i].end = res.base() + res.size() - 1;
unsigned flags = 0;
if (res.type() == Device::Resource::IO) flags |= IORESOURCE_IO;
if (res.type() == Device::Resource::MEMORY) flags |= IORESOURCE_MEM;
this->resource[i].flags = flags;
PDBGV("this=%p base: %x size: %x type: %u",
this, res.base(), res.size(), res.type());
/* request port I/O session */
if (res.type() == Device::Resource::IO) {
uint8_t const virt_bar = _client.phys_bar_to_virt(i);
_io_port.session(res.base(), res.size(), _client.io_port(virt_bar));
io = true;
PDBGV("I/O [%u-%u)",
res.base(), res.base() + res.size());
}
/* request I/O memory (write combined) */
if (res.type() == Device::Resource::MEMORY)
PDBGV("I/O memory [%x-%x)", res.base(),
res.base() + res.size());
}
/* enable bus master and io bits */
uint16_t cmd = _client.config_read(CMD, Device::ACCESS_16BIT);
cmd |= io ? 0x1 : 0;
/* enable bus master */
cmd |= 0x4;
_client.config_write(CMD, cmd, Device::ACCESS_16BIT);
/* get pci express capability */
this->pcie_cap = 0;
uint16_t status = _client.config_read(STATUS, Device::ACCESS_32BIT) >> 16;
if (status & CAP_LIST) {
uint8_t offset = _client.config_read(CAP, Device::ACCESS_8BIT);
while (offset != 0x00) {
uint8_t value = _client.config_read(offset, Device::ACCESS_8BIT);
if (value == CAP_EXP)
this->pcie_cap = offset;
offset = _client.config_read(offset + 1, Device::ACCESS_8BIT);
}
}
if (this->pcie_cap) {
uint16_t reg_val = _client.config_read(this->pcie_cap, Device::ACCESS_16BIT);
this->pcie_flags_reg = reg_val;
}
}
/**
* Read/write data from/to config space
*/
template <typename T>
void config_read(unsigned int devfn, T *val)
{
*val = _client.config_read(devfn, _access_size(*val));
}
template <typename T>
void config_write(unsigned int devfn, T val)
{
_client.config_write(devfn, val, _access_size(val));
}
Platform::Device &client() { return _client; }
Io_port &io_port() { return _io_port; }
};
/**
* Call functor for each available physical PCI device
*
* The functor is called with the device capability as argument. If
* returns true if we can stop iterating. In this case, the device
* is expected to be acquired by the driver. All other devices are
* released at the platform driver.
*/
template <typename FUNC>
void Lx::for_each_pci_device(FUNC const &func)
{
/*
* Functor that is called if the platform driver throws a
* 'Quota_exceeded' exception.
*/
auto handler = [&] () {
Genode::env()->parent()->upgrade(Lx::pci()->cap(),
"ram_quota=4096"); };
/*
* Obtain first device, the operation may exceed the session quota.
* So we use the 'retry' mechanism.
*/
Platform::Device_capability cap;
auto attempt = [&] () { cap = Lx::pci()->first_device(); };
Genode::retry<Platform::Device::Quota_exceeded>(attempt, handler);
/*
* Iterate over the devices of the platform session.
*/
while (cap.valid()) {
/*
* Call functor, stop iterating depending on its return value.
*/
if (func(cap))
break;
/*
* Release current device and try next one. Upgrade session
* quota on demand.
*/
auto attempt = [&] () {
Platform::Device_capability next_cap = pci()->next_device(cap);
Lx::pci()->release_device(cap);
cap = next_cap;
};
Genode::retry<Platform::Device::Quota_exceeded>(attempt, handler);
}
}
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_DEV_H_ */

View File

@ -0,0 +1,111 @@
/*
* \brief Registry of PCI devices
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_
#define _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/pci_dev.h>
namespace Lx {
class Pci_dev_registry;
/**
* Return singleton 'Pci_dev_registry' object
*
* Implementation must be provided by the driver.
*/
Pci_dev_registry *pci_dev_registry();
}
class Lx::Pci_dev_registry
{
private:
List<Pci_dev> _devs;
public:
void insert(Pci_dev *pci_dev)
{
PDBG("insert pci_dev %p", pci_dev);
_devs.insert(pci_dev);
}
Genode::Io_mem_dataspace_capability io_mem(resource_size_t phys,
Genode::Cache_attribute cache_attribute,
Genode::size_t size)
{
enum { PCI_ROM_RESOURCE = 6 };
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
unsigned bar = 0;
for (; bar < PCI_ROM_RESOURCE; bar++) {
if ((pci_resource_flags(d, bar) & IORESOURCE_MEM) &&
(pci_resource_start(d, bar) == phys))
break;
}
if (bar >= PCI_ROM_RESOURCE)
continue;
Platform::Device &device = d->client();
unsigned const resource_id =
device.phys_bar_to_virt(bar);
/* offset from the beginning of the PCI resource */
Genode::addr_t const offset =
phys - pci_resource_start(d, bar);
Genode::Io_mem_session_capability io_mem_cap =
device.io_mem(resource_id, cache_attribute, offset, size);
return Genode::Io_mem_session_client(io_mem_cap).dataspace();
}
PERR("Device using i/o memory of address %zx is unknown", phys);
return Genode::Io_mem_dataspace_capability();
}
template <typename T>
T io_read(unsigned port)
{
PDBG("io_read %u", port);
/* try I/O access on all PCI devices */
for (Pci_dev *d = _devs.first(); d; d = d->next()) {
T value = 0;
if (d->io_port().in<T>(port, &value))
return value;
}
PWRN("I/O port(%u) read failed", port);
return (T)~0;
}
template <typename T>
void io_write(unsigned port, T value)
{
PDBG("io_write %u", port);
/* try I/O access on all PCI devices, return on first success */
for (Pci_dev *d = _devs.first(); d; d = d->next())
if (d->io_port().out<T>(port, value))
return;
PWRN("I/O port(%u) write failed", port);
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__PCI_DEV_REGISTRY_H_ */

View File

@ -0,0 +1,230 @@
/*
* \brief Scheduler for executing Lx::Task objects
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_
#define _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_
/* Genode includes */
#include <base/env.h>
#include <base/lock.h>
#include <base/printf.h>
#include <base/thread.h>
#include <timer_session/connection.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
#include <lx_emul/impl/internal/debug.h>
namespace Lx {
class Scheduler;
/**
* Return singleton instance of the scheduler
*
* Implementation must be provided by the driver.
*/
Scheduler &scheduler();
/**
* Called each time when a scheduling decision is taken
*
* Must be provided by the compilation unit that includes 'scheduler.h',
* e.g., by also including 'timer.h'.
*/
static inline void timer_update_jiffies();
}
class Lx::Scheduler
{
private:
bool verbose = true;
Lx::List<Lx::Task> _present_list;
Genode::Lock _present_list_mutex;
Task *_current = nullptr; /* currently scheduled task */
bool _run_task(Task *);
/*
* Support for logging
*/
static inline char const *_ansi_esc_reset() { return "\033[00m"; }
static inline char const *_ansi_esc_black() { return "\033[30m"; }
static inline char const *_ansi_esc_red() { return "\033[31m"; }
static inline char const *_ansi_esc_yellow() { return "\033[33m"; }
static inline char const *_state_color(Lx::Task::State state)
{
switch (state) {
case Lx::Task::STATE_INIT: return _ansi_esc_reset();
case Lx::Task::STATE_RUNNING: return _ansi_esc_red();
case Lx::Task::STATE_BLOCKED: return _ansi_esc_yellow();
case Lx::Task::STATE_MUTEX_BLOCKED: return _ansi_esc_yellow();
case Lx::Task::STATE_WAIT_BLOCKED: return _ansi_esc_yellow();
}
return _ansi_esc_black();
}
struct Logger : Genode::Thread<0x4000>
{
Timer::Connection _timer;
Lx::Scheduler &_scheduler;
unsigned const _interval;
Logger(Lx::Scheduler &scheduler, unsigned interval_seconds)
:
Genode::Thread<0x4000>("logger"),
_scheduler(scheduler), _interval(interval_seconds)
{
start();
}
void entry()
{
PWRN("Scheduler::Logger is up");
_timer.msleep(1000 * _interval);
while (true) {
_scheduler.log_state("LOGGER");
_timer.msleep(2000);
}
}
};
public:
Scheduler()
{
if (verbose)
new (Genode::env()->heap()) Logger(*this, 10);
}
/**
* Return currently scheduled task
*/
Task *current()
{
if (!_current) {
PERR("BUG: _current is zero!");
Genode::sleep_forever();
}
return _current;
}
/**
* Add new task to the present list
*/
void add(Task *task)
{
Lx::Task *p = _present_list.first();
for ( ; p; p = p->next()) {
if (p->priority() <= task->priority()) {
_present_list.insert_before(task, p);
break;
}
}
if (!p)
_present_list.append(task);
}
/**
* Schedule all present tasks
*
* Returns if no task is runnable.
*/
void schedule()
{
bool at_least_one = false;
/*
* Iterate over all tasks and run first runnable.
*
* (1) If one runnable tasks was run start over from beginning of
* list.
*
* (2) If no task is runnable quit scheduling (break endless
* loop).
*/
while (true) {
/* update jiffies before running task */
Lx::timer_update_jiffies();
bool was_run = false;
for (Task *t = _present_list.first(); t; t = t->next()) {
/* update current before running task */
_current = t;
if ((was_run = t->run())) {
at_least_one = true;
break;
}
}
if (!was_run)
break;
}
if (!at_least_one) {
PWRN("schedule() called without runnable tasks");
log_state("SCHEDULE");
}
/* clear current as no task is running */
_current = nullptr;
}
/**
* Log current state of tasks in present list (debug)
*
* Log lines are prefixed with 'prefix'.
*/
void log_state(char const *prefix)
{
unsigned i;
Lx::Task *t;
for (i = 0, t = _present_list.first(); t; t = t->next(), ++i) {
Genode::printf("%s [%u] prio: %u state: %s%u%s %s\n",
prefix, i, t->priority(), _state_color(t->state()),
t->state(), _ansi_esc_reset(), t->name());
}
}
};
Lx::Task::Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler)
:
_priority(priority), _scheduler(scheduler),
_func(func), _arg(arg), _name(name)
{
scheduler.add(this);
PDBGV("name: '%s' func: %p arg: %p prio: %u t: %p", name, func, arg, priority, this);
}
void Lx::Task::_deinit()
{
if (_stack)
Genode::Thread_base::myself()->free_secondary_stack(_stack);
}
#endif /* _LX_EMUL__IMPL__INTERNAL__SCHEDULER_H_ */

View File

@ -0,0 +1,58 @@
/*
* \brief Slab allocator using our back-end allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_
/* Genode includes */
#include <base/slab.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/slab_backend_alloc.h>
namespace Lx { class Slab_alloc; }
class Lx::Slab_alloc : public Genode::Slab
{
private:
/*
* Each slab block in the slab contains about 8 objects (slab entries)
* as proposed in the paper by Bonwick and block sizes are multiples of
* page size.
*/
static size_t _calculate_block_size(size_t object_size)
{
size_t block_size = 8 * (object_size + sizeof(Genode::Slab_entry))
+ sizeof(Genode::Slab_block);
return Genode::align_addr(block_size, 12);
}
public:
Slab_alloc(size_t object_size, Slab_backend_alloc &allocator)
: Slab(object_size, _calculate_block_size(object_size), 0, &allocator) { }
/**
* Convenience slabe-entry allocation
*/
Genode::addr_t alloc()
{
Genode::addr_t result;
return (Slab::alloc(slab_size(), (void **)&result) ? result : 0);
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__SLAB_ALLOC_H_ */

View File

@ -0,0 +1,173 @@
/*
* \brief Back-end allocator for Genode's slab allocator
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_
#define _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_
/* Genode includes */
#include <base/env.h>
#include <base/allocator_avl.h>
#include <rm_session/connection.h>
#include <dataspace/client.h>
namespace Lx {
Genode::Ram_dataspace_capability
backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached);
void backend_free(Genode::Ram_dataspace_capability cap);
class Slab_backend_alloc;
}
class Lx::Slab_backend_alloc : public Genode::Allocator,
public Genode::Rm_connection
{
private:
typedef Genode::addr_t addr_t;
enum {
VM_SIZE = 24 * 1024 * 1024, /* size of VM region to reserve */
BLOCK_SIZE = 1024 * 1024, /* 1 MiB */
ELEMENTS = VM_SIZE / BLOCK_SIZE, /* MAX number of dataspaces in VM */
};
addr_t _base; /* virt. base address */
Genode::Cache_attribute _cached; /* non-/cached RAM */
Genode::Ram_dataspace_capability _ds_cap[ELEMENTS]; /* dataspaces to put in VM */
addr_t _ds_phys[ELEMENTS]; /* physical bases of dataspaces */
int _index; /* current index in ds_cap */
Genode::Allocator_avl _range; /* manage allocations */
bool _alloc_block()
{
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
try {
_ds_cap[_index] = Lx::backend_alloc(BLOCK_SIZE, _cached);
/* attach at index * BLOCK_SIZE */
Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
/* lookup phys. address */
_ds_phys[_index] = Genode::Dataspace_client(_ds_cap[_index]).phys_addr();
} catch (...) { return false; }
/* return base + offset in VM area */
addr_t block_base = _base + (_index * BLOCK_SIZE);
++_index;
_range.add_range(block_base, BLOCK_SIZE);
return true;
}
public:
Slab_backend_alloc(Genode::Cache_attribute cached)
:
Rm_connection(0, VM_SIZE),
_cached(cached), _index(0), _range(Genode::env()->heap())
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
/**
* Allocate
*/
bool alloc(size_t size, void **out_addr) override
{
bool done = _range.alloc(size, out_addr);
if (done)
return done;
done = _alloc_block();
if (!done) {
PERR("Backend allocator exhausted\n");
return false;
}
return _range.alloc(size, out_addr);
}
void free(void *addr, size_t /* size */) override { }
size_t overhead(size_t size) const override { return 0; }
bool need_size_for_free() const override { return false; }
/**
* Return phys address for given virtual addr.
*/
addr_t phys_addr(addr_t addr)
{
if (addr < _base || addr >= (_base + VM_SIZE))
return ~0UL;
int index = (addr - _base) / BLOCK_SIZE;
/* physical base of dataspace */
addr_t phys = _ds_phys[index];
if (!phys)
return ~0UL;
/* add offset */
phys += (addr - _base - (index * BLOCK_SIZE));
return phys;
}
/**
* Translate given physical address to virtual address
*
* \return virtual address, or 0 if no translation exists
*/
addr_t virt_addr(addr_t phys)
{
for (unsigned i = 0; i < ELEMENTS; i++) {
if (_ds_cap[i].valid() &&
phys >= _ds_phys[i] && phys < _ds_phys[i] + BLOCK_SIZE)
return _base + i*BLOCK_SIZE + phys - _ds_phys[i];
}
PWRN("virt_addr(0x%lx) - no translation", phys);
return 0;
}
addr_t start() const { return _base; }
addr_t end() const { return _base + VM_SIZE - 1; }
/**
* Cached memory backend allocator
*/
static Slab_backend_alloc & mem()
{
static Slab_backend_alloc inst(Genode::CACHED);
return inst;
}
/**
* DMA memory backend allocator
*/
static Slab_backend_alloc & dma()
{
static Slab_backend_alloc inst(Genode::UNCACHED);
return inst;
}
};
#endif /* _LX_EMUL__IMPL__INTERNAL__SLAB_BACKEND_ALLOC_H_ */

View File

@ -0,0 +1,255 @@
/*
* \brief Lx::Task represents a cooperatively scheduled thread of control
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__TASK_H_
#define _LX_EMUL__IMPL__INTERNAL__TASK_H_
/* libc includes */
#include <setjmp.h>
/* Genode includes */
#include <base/sleep.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/list.h>
#include <lx_emul/impl/internal/arch_execute.h>
namespace Lx {
class Scheduler;
class Task;
}
/**
* Allows pseudo-parallel execution of functions
*/
class Lx::Task : public Lx::List<Lx::Task>::Element
{
public:
/**
* TODO generalize - higher is more important
*/
enum Priority { PRIORITY_0, PRIORITY_1, PRIORITY_2, PRIORITY_3 };
/**
* Runtime state
*
* INIT
* |
* [run]
* v
* BLOCKED <--[block]--- RUNNING ---[mutex_block]--> MUTEX_BLOCKED
* --[unblock]-> <-[mutex_unblock]--
*
* Transitions between BLOCKED and MUTEX_BLOCKED are not possible.
*/
enum State { STATE_INIT, STATE_RUNNING, STATE_BLOCKED, STATE_MUTEX_BLOCKED, STATE_WAIT_BLOCKED };
/**
* List element type
*/
typedef Lx::List_element<Lx::Task> List_element;
/**
* List type
*/
typedef Lx::List<List_element> List;
private:
bool verbose = true;
State _state = STATE_INIT;
/* sub-classes may overwrite the runnable condition */
virtual bool _runnable() const
{
switch (_state) {
case STATE_INIT: return true;
case STATE_RUNNING: return true;
case STATE_BLOCKED: return false;
case STATE_MUTEX_BLOCKED: return false;
case STATE_WAIT_BLOCKED: return false;
}
PERR("state %d not handled by switch", _state);
Genode::sleep_forever();
}
void *_stack = nullptr; /* stack pointer */
jmp_buf _env; /* execution state */
jmp_buf _saved_env; /* saved state of thread calling run() */
Priority _priority;
Scheduler &_scheduler; /* scheduler this task is attached to */
void (*_func)(void *); /* function to call*/
void *_arg; /* argument for function */
char const *_name; /* name of task */
List_element _mutex_le { this }; /* list element for mutex_blocked state */
List *_wait_list { 0 };
List_element _wait_le { this };
bool _wait_le_enqueued { false };
inline void _deinit();
public:
inline Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler);
virtual ~Task() { _deinit(); }
State state() const { return _state; }
Priority priority() const { return _priority; }
void wait_enqueue(List *list)
{
if (_wait_le_enqueued) {
PERR("%p already queued in %p", this, _wait_list);
Genode::sleep_forever();
}
_wait_le_enqueued = true;
_wait_list = list;
_wait_list->append(&_wait_le);
}
void wait_dequeue(List *list)
{
if (!_wait_le_enqueued) {
PERR("%p not queued", this);
Genode::sleep_forever();
}
if (_wait_list != list) {
PERR("especially not in list %p", list);
Genode::sleep_forever();
}
_wait_list->remove(&_wait_le);
_wait_list = 0;
_wait_le_enqueued = false;
}
/*******************************
** Runtime state transitions **
*******************************/
void block()
{
if (_state == STATE_RUNNING) {
_state = STATE_BLOCKED;
}
}
void unblock()
{
if (_state == STATE_BLOCKED) {
_state = STATE_RUNNING;
}
}
void mutex_block(List *list)
{
if (_state == STATE_RUNNING) {
_state = STATE_MUTEX_BLOCKED;
list->append(&_mutex_le);
}
}
void mutex_unblock(List *list)
{
if (_state == STATE_MUTEX_BLOCKED) {
_state = STATE_RUNNING;
list->remove(&_mutex_le);
}
}
/**
* Run task until next preemption point
*
* \return true if run, false if not runnable
*/
bool run()
{
if (!_runnable())
return false;
/*
* Save the execution environment. The scheduled task returns to this point
* after execution, i.e., at the next preemption point.
*/
if (_setjmp(_saved_env))
return true;
if (_state == STATE_INIT) {
/* setup execution environment and call task's function */
_state = STATE_RUNNING;
Genode::Thread_base *th = Genode::Thread_base::myself();
enum { STACK_SIZE = 32 * 1024 }; /* FIXME make stack size configurable */
_stack = th->alloc_secondary_stack(_name, STACK_SIZE);
/* switch stack and call '_func(_arg)' */
arch_execute(_stack, (void *)_func, _arg);
} else {
/* restore execution environment */
_longjmp(_env, 1);
}
/* never reached */
PERR("Unexpected return of Task");
Genode::sleep_forever();
}
/**
* Request scheduling (of other tasks)
*
* Note, this task may not be blocked when calling schedule() depending
* on the use case.
*/
void schedule()
{
/*
* Save the execution environment. The task will resume from here on next
* schedule.
*/
if (_setjmp(_env))
return;
/* return to thread calling run() */
_longjmp(_saved_env, 1);
}
/**
* Shortcut to enter blocking state and request scheduling
*/
void block_and_schedule()
{
block();
schedule();
}
/**
* Return the name of the task (mainly for debugging purposes)
*/
char const *name() { return _name; }
};
#endif /* _LX_EMUL__IMPL__INTERNAL__TASK_H_ */

View File

@ -0,0 +1,313 @@
/*
* \brief Timer
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Norman Feske
* \date 2014-10-10
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LX_EMUL__IMPL__INTERNAL__TIMER_H_
#define _LX_EMUL__IMPL__INTERNAL__TIMER_H_
/* Genode includes */
#include <os/server.h>
#include <base/tslab.h>
#include <timer_session/connection.h>
/* Linux emulation environment includes */
#include <lx_emul/impl/internal/task.h>
namespace Lx {
class Timer;
/**
* Return singleton instance of timer
*
* \param ep entrypoint used handle timeout signals,
* to be specified at the first call of the function,
* which implicitly initializes the timer
* \param jiffies_ptr pointer to jiffies counter to be periodically
* updated
*/
Timer &timer(Server::Entrypoint *ep = nullptr,
unsigned long *jiffies_ptr = nullptr);
/**
* Blue-print implementation of 'timer' function
*/
static inline Timer &_timer_impl(Server::Entrypoint *ep,
unsigned long *jiffies_ptr);
static inline void timer_update_jiffies();
static inline void run_timer(void *);
}
class Lx::Timer
{
public:
/**
* Context encapsulates a regular linux timer_list
*/
struct Context : public Lx::List<Context>::Element
{
enum { INVALID_TIMEOUT = ~0UL };
struct timer_list *timer;
bool pending { false };
unsigned long timeout { INVALID_TIMEOUT }; /* absolute in jiffies */
bool programmed { false };
Context(struct timer_list *timer) : timer(timer) { }
};
private:
unsigned long &_jiffies;
::Timer::Connection _timer_conn;
Lx::List<Context> _list;
Lx::Task _timer_task;
Genode::Signal_rpc_member<Lx::Timer> _dispatcher;
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
/**
* Lookup local timer
*/
Context *_find_context(struct timer_list const *timer)
{
for (Context *c = _list.first(); c; c = c->next())
if (c->timer == timer)
return c;
return 0;
}
/**
* Program the first timer in the list
*
* The first timer is programmed if the 'programmed' flag was not set
* before. The second timer is flagged as not programmed as
* 'Timer::trigger_once' invalidates former registered one-shot
* timeouts.
*/
void _program_first_timer()
{
Context *ctx = _list.first();
if (!ctx)
return;
if (ctx->programmed)
return;
/* calculate relative microseconds for trigger */
unsigned long us = ctx->timeout > _jiffies ?
jiffies_to_msecs(ctx->timeout - _jiffies) * 1000 : 0;
_timer_conn.trigger_once(us);
ctx->programmed = true;
/* possibly programmed successor must be reprogrammed later */
if (Context *next = ctx->next())
next->programmed = false;
}
/**
* Schedule timer
*
* Add the context to the scheduling list depending on its timeout
* and reprogram the first timer.
*/
void _schedule_timer(Context *ctx, unsigned long expires)
{
_list.remove(ctx);
ctx->timeout = expires;
ctx->pending = true;
ctx->programmed = false;
/*
* Also write the timeout value to the expires field in
* struct timer_list because the wireless stack checks
* it directly.
*/
ctx->timer->expires = expires;
Context *c;
for (c = _list.first(); c; c = c->next())
if (ctx->timeout <= c->timeout)
break;
_list.insert_before(ctx, c);
_program_first_timer();
}
/**
* Handle trigger_once signal
*/
void _handle(unsigned)
{
_timer_task.unblock();
Lx::scheduler().schedule();
}
public:
/**
* Constructor
*/
Timer(Server::Entrypoint &ep, unsigned long &jiffies)
:
_jiffies(jiffies),
_timer_task(run_timer, nullptr, "timer", Lx::Task::PRIORITY_2,
Lx::scheduler()),
_dispatcher(ep, *this, &Lx::Timer::_handle),
_timer_alloc(Genode::env()->heap())
{
_timer_conn.sigh(_dispatcher);
}
/**
* Add new linux timer
*/
void add(struct timer_list *timer)
{
Context *t = new (&_timer_alloc) Context(timer);
_list.append(t);
}
/**
* Delete linux timer
*/
int del(struct timer_list *timer)
{
Context *ctx = _find_context(timer);
/**
* If the timer expired it was already cleaned up after its
* execution.
*/
if (!ctx)
return 0;
int rv = ctx->timeout != Context::INVALID_TIMEOUT ? 1 : 0;
_list.remove(ctx);
destroy(&_timer_alloc, ctx);
return rv;
}
/**
* Initial scheduling of linux timer
*/
int schedule(struct timer_list *timer, unsigned long expires)
{
Context *ctx = _find_context(timer);
if (!ctx) {
PERR("schedule unknown timer %p", timer);
return -1; /* XXX better use 0 as rv? */
}
/*
* If timer was already active return 1, otherwise 0. The return
* value is needed by mod_timer().
*/
int rv = ctx->timeout != Context::INVALID_TIMEOUT ? 1 : 0;
_schedule_timer(ctx, expires);
return rv;
}
/**
* Schedule next linux timer
*/
void schedule_next() { _program_first_timer(); }
/**
* Check if the timer is currently pending
*/
bool pending(struct timer_list const *timer)
{
Context *ctx = _find_context(timer);
if (!ctx) {
return false;
}
return ctx->pending;
}
Context *find(struct timer_list const *timer) {
return _find_context(timer); }
/**
* Update jiffie counter
*/
void update_jiffies()
{
_jiffies = msecs_to_jiffies(_timer_conn.elapsed_ms());
}
/**
* Get first timer context
*/
Context* first() { return _list.first(); }
unsigned long jiffies() const { return _jiffies; }
};
void Lx::timer_update_jiffies()
{
timer().update_jiffies();
}
void Lx::run_timer(void *)
{
Timer &t = timer();
while (1) {
Lx::scheduler().current()->block_and_schedule();
while (Lx::Timer::Context *ctx = t.first()) {
if (ctx->timeout > t.jiffies())
break;
ctx->timer->function(ctx->timer->data);
t.del(ctx->timer);
}
t.schedule_next();
}
}
Lx::Timer &Lx::_timer_impl(Server::Entrypoint *ep, unsigned long *jiffies_ptr)
{
static bool initialized = false;
if (!initialized && !ep) {
PERR("attempt to use Lx::Timer before its construction");
class Lx_timer_not_constructed { };
throw Lx_timer_not_constructed();
}
static Lx::Timer inst(*ep, *jiffies_ptr);
initialized = true;
return inst;
}
#endif /* _LX_EMUL__IMPL__INTERNAL__TIMER_H_ */

View File

@ -0,0 +1,40 @@
/*
* \brief Implementation of linux/io.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/mapped_io_mem_range.h>
void *ioremap(resource_size_t phys_addr, unsigned long size)
{
return Lx::ioremap(phys_addr, size, Genode::UNCACHED);
}
void *ioremap_wc(resource_size_t phys_addr, unsigned long size)
{
return Lx::ioremap(phys_addr, size, Genode::WRITE_COMBINED);
}
/**********************
** asm-generic/io.h **
**********************/
void outb(u8 value, u32 port) { Lx::pci_dev_registry()->io_write<u8> (port, value); }
void outw(u16 value, u32 port) { Lx::pci_dev_registry()->io_write<u16>(port, value); }
void outl(u32 value, u32 port) { Lx::pci_dev_registry()->io_write<u32>(port, value); }
u8 inb(u32 port) { return Lx::pci_dev_registry()->io_read<u8> (port); }
u16 inw(u32 port) { return Lx::pci_dev_registry()->io_read<u16>(port); }
u32 inl(u32 port) { return Lx::pci_dev_registry()->io_read<u32>(port); }

View File

@ -0,0 +1,42 @@
/*
* \brief Implementation of linux/kernel.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/snprintf.h>
int sprintf(char *str, const char *format, ...)
{
enum { BUFFER_LEN = 128 };
va_list list;
va_start(list, format);
Genode::String_console sc(str, BUFFER_LEN);
sc.vprintf(format, list);
va_end(list);
return sc.len();
}
int snprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
Genode::String_console sc(buf, size);
sc.vprintf(fmt, args);
va_end(args);
return sc.len();
}

View File

@ -0,0 +1,104 @@
/*
* \brief Implementation of linux/mutex.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/scheduler.h>
enum { MUTEX_UNLOCKED = 1, MUTEX_LOCKED = 0, MUTEX_WAITERS = -1 };
void mutex_init(struct mutex *m)
{
static unsigned id = 0;
m->state = MUTEX_UNLOCKED;
m->holder = nullptr;
m->waiters = new (Genode::env()->heap()) Lx::Task::List;
m->id = ++id;
}
void mutex_destroy(struct mutex *m)
{
/* FIXME potentially blocked tasks are not unblocked */
Genode::destroy(Genode::env()->heap(), static_cast<Lx::Task::List *>(m->waiters));
m->holder = nullptr;
m->waiters = nullptr;
m->id = 0;
}
void mutex_lock(struct mutex *m)
{
while (1) {
if (m->state == MUTEX_UNLOCKED) {
m->state = MUTEX_LOCKED;
m->holder = Lx::scheduler().current();
break;
}
Lx::Task *t = reinterpret_cast<Lx::Task *>(m->holder);
if (t == Lx::scheduler().current()) {
PERR("Bug: mutex does not support recursive locking");
Genode::sleep_forever();
}
/* notice that a task waits for the mutex to be released */
m->state = MUTEX_WAITERS;
/* block until the mutex is released (and retry then) */
Lx::scheduler().current()->mutex_block(static_cast<Lx::Task::List *>(m->waiters));
Lx::scheduler().current()->schedule();
}
}
void mutex_unlock(struct mutex *m)
{
if (m->state == MUTEX_UNLOCKED) {
PERR("Bug: multiple mutex unlock detected");
Genode::sleep_forever();
}
if (m->holder != Lx::scheduler().current()) {
PERR("Bug: mutex unlock by task not holding the mutex");
Genode::sleep_forever();
}
Lx::Task::List *waiters = static_cast<Lx::Task::List *>(m->waiters);
if (m->state == MUTEX_WAITERS)
while (Lx::Task::List_element *le = waiters->first())
le->object()->mutex_unblock(waiters);
m->state = MUTEX_UNLOCKED;
m->holder = nullptr;
}
int mutex_is_locked(struct mutex *m)
{
return m->state != MUTEX_UNLOCKED;
}
int mutex_trylock(struct mutex *m)
{
if (mutex_is_locked(m))
return false;
mutex_lock(m);
return true;
}

View File

@ -0,0 +1,194 @@
/*
* \brief Implementation of linux/pci.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <io_mem_session/connection.h>
#include <lx_emul/impl/internal/pci_dev_registry.h>
#include <lx_emul/impl/internal/mapped_io_mem_range.h>
extern void pci_dev_put(struct pci_dev *pci_dev)
{
Genode::destroy(Genode::env()->heap(), pci_dev);
}
extern "C" int pci_register_driver(struct pci_driver *driver)
{
driver->driver.name = driver->name;
pci_device_id const *id_table = driver->id_table;
if (!id_table)
return -ENODEV;
using namespace Genode;
Lx::Pci_dev *pci_dev = nullptr;
auto lamda = [&] (Platform::Device_capability cap) {
Platform::Device_client client(cap);
/* request device ID from platform driver */
unsigned const device_id = client.device_id();
/* look if we find the device ID in the driver's 'id_table' */
pci_device_id const *matching_id = nullptr;
for (pci_device_id const *id = id_table; id->class_ != (unsigned)PCI_ANY_ID; id++)
if (id->device == device_id)
matching_id = id;
/* skip device that is not handled by driver */
if (!matching_id)
return false;
/* create 'pci_dev' struct for matching device */
pci_dev = new (env()->heap()) Lx::Pci_dev(cap);
/* enable ioremap to work */
Lx::pci_dev_registry()->insert(pci_dev);
/* register driver at the 'pci_dev' struct */
pci_dev->dev.driver = &driver->driver;
/* call probe function of the Linux driver */
if (!driver->probe(pci_dev, matching_id)) {
/* if the probing failed, revert the creation of 'pci_dev' */
pci_dev_put(pci_dev);
pci_dev = nullptr;
return false;
}
/* aquire the device, stop iterating */
return true;
};
Lx::for_each_pci_device(lamda);
return pci_dev ? 0 : -ENODEV;
}
extern "C" size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].start;
}
extern "C" size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
{
size_t start = pci_resource_start(dev, bar);
if (!start)
return 0;
return (dev->resource[bar].end - start) + 1;
}
extern "C" void *pci_ioremap_bar(struct pci_dev *dev, int bar)
{
using namespace Genode;
if (bar >= DEVICE_COUNT_RESOURCE || bar < 0)
return 0;
return Lx::ioremap(pci_resource_start(dev, bar),
pci_resource_len(dev, bar),
Genode::UNCACHED);
}
extern "C" unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar)
{
if (bar >= DEVICE_COUNT_RESOURCE)
return 0;
return dev->resource[bar].flags;
}
extern "C" int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int, int where, u8 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_word(struct pci_bus *bus, unsigned int, int where, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int, int where, u32 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_read(where, val);
return 0;
}
extern "C" int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int, int where, u8 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_word(struct pci_bus *bus, unsigned int, int where, u16 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int, int where, u32 val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)bus;
dev->config_write(where, val);
return 0;
}
extern "C" const char *pci_name(const struct pci_dev *pdev)
{
/* simply return driver name */
return "dummy";
}
extern "C" int pcie_capability_read_word(struct pci_dev *pdev, int pos, u16 *val)
{
Lx::Pci_dev *dev = (Lx::Pci_dev *)pdev->bus;
switch (pos) {
case PCI_EXP_LNKCTL:
dev->config_read(pdev->pcie_cap + PCI_EXP_LNKCTL, val);
return 0;
break;
default:
break;
}
return 1;
}
//

View File

@ -0,0 +1,39 @@
/*
* \brief Implementation of linux/sched.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/scheduler.h>
static void unblock_task(unsigned long task)
{
Lx::Task *t = (Lx::Task *)task;
t->unblock();
}
signed long schedule_timeout(signed long timeout)
{
struct timer_list timer;
setup_timer(&timer, unblock_task, (unsigned long)Lx::scheduler().current());
mod_timer(&timer, timeout);
Lx::scheduler().current()->block_and_schedule();
del_timer(&timer);
timeout = (timeout - jiffies);
return timeout < 0 ? 0 : timeout;
}

View File

@ -0,0 +1,175 @@
/*
* \brief Implementation of linux/slab.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/malloc.h>
void *kmalloc(size_t size, gfp_t flags)
{
if (flags & __GFP_DMA)
PWRN("GFP_DMA memory (below 16 MiB) requested (%p)", __builtin_return_address(0));
if (flags & __GFP_DMA32)
PWRN("GFP_DMA32 memory (below 4 GiB) requested (%p)", __builtin_return_address(0));
void *addr = flags & GFP_LX_DMA ? Lx::Malloc::dma().alloc(size, 12)
: Lx::Malloc::mem().alloc(size);
if ((Genode::addr_t)addr & 0x3)
PERR("unaligned kmalloc %lx", (Genode::addr_t)addr);
if (flags & __GFP_ZERO)
Genode::memset(addr, 0, size);
return addr;
}
void *kzalloc(size_t size, gfp_t flags)
{
return kmalloc(size, flags | __GFP_ZERO);
}
void *kzalloc_node(size_t size, gfp_t flags, int node)
{
return kzalloc(size, 0);
}
void *kcalloc(size_t n, size_t size, gfp_t flags)
{
if (size != 0 && n > (~0UL / size))
return 0;
return kzalloc(n * size, flags);
}
void kfree(void const *p)
{
if (!p) return;
if (Lx::Malloc::mem().inside((Genode::addr_t)p))
Lx::Malloc::mem().free(p);
else if (Lx::Malloc::dma().inside((Genode::addr_t)p))
Lx::Malloc::dma().free(p);
else
PERR("%s: unknown block at %p, called from %p", __func__,
p, __builtin_return_address(0));
}
static size_t _ksize(void *p)
{
size_t size = 0;
if (Lx::Malloc::mem().inside((Genode::addr_t)p))
size = Lx::Malloc::mem().size(p);
else if (Lx::Malloc::dma().inside((Genode::addr_t)p))
size = Lx::Malloc::dma().size(p);
else
PERR("%s: unknown block at %p", __func__, p);
return size;
}
size_t ksize(void *p)
{
return _ksize(p);
}
void kzfree(void const *p)
{
if (!p) return;
size_t len = ksize(const_cast<void*>(p));
Genode::memset((void*)p, 0, len);
kfree(p);
}
void *kmalloc_node_track_caller(size_t size, gfp_t flags, int node)
{
return kmalloc(size, flags);
}
void *krealloc(void *p, size_t size, gfp_t flags)
{
/* XXX handle short-cut where size == old_size */
void *addr = kmalloc(size, flags);
if (addr && p) {
size_t old_size = _ksize(p);
Genode::memcpy(addr, p, old_size);
kfree(p);
}
return addr;
}
void *kmemdup(const void *src, size_t size, gfp_t flags)
{
void *addr = kmalloc(size, flags);
if (addr)
Genode::memcpy(addr, src, size);
return addr;
}
struct kmem_cache : Lx::Slab_alloc
{
kmem_cache(size_t object_size, bool dma)
:
Lx::Slab_alloc(object_size, dma ? Lx::Slab_backend_alloc::dma()
: Lx::Slab_backend_alloc::mem())
{ }
};
struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
unsigned long flags, void (*ctor)(void *))
{
if (ctor) {
PERR("%s: ctor not supported", __func__);
return nullptr;
}
/*
* Copied from wifi_drv.
*
* XXX SLAB_LX_DMA is never used anywhere else, remove it?
*/
enum { SLAB_LX_DMA = 0x80000000ul, };
return new (Genode::env()->heap()) kmem_cache(size, flags & SLAB_LX_DMA);
}
void * kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
{
return (void *)cache->alloc();
}
void kmem_cache_free(struct kmem_cache *cache, void *objp)
{
cache->free(objp);
}

View File

@ -0,0 +1,17 @@
/*
* \brief Implementation of linux/spinlock.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
void spin_lock_init(spinlock_t *lock) { TRACE; }
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags) { }
void spin_unlock(spinlock_t *lock) { TRACE; }
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { }

View File

@ -0,0 +1,52 @@
/*
* \brief Implementation of linux/timer.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <lx_emul/impl/internal/timer.h>
void init_timer(struct timer_list *timer) { }
int mod_timer(struct timer_list *timer, unsigned long expires)
{
if (!Lx::timer().find(timer))
Lx::timer().add(timer);
return Lx::timer().schedule(timer, expires);
}
void setup_timer(struct timer_list *timer,void (*function)(unsigned long),
unsigned long data)
{
timer->function = function;
timer->data = data;
init_timer(timer);
}
int timer_pending(const struct timer_list *timer)
{
bool pending = Lx::timer().pending(timer);
return pending;
}
int del_timer(struct timer_list *timer)
{
int rv = Lx::timer().del(timer);
Lx::timer().schedule_next();
return rv;
}

View File

@ -0,0 +1,47 @@
/*
* \brief Implementation of linux/wait.h
* \author Norman Feske
* \date 2015-09-09
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *w, int state)
{
if (!q) {
PWRN("prepare_to_wait: wait_queue_head_t is 0, ignore, called from: %p",
__builtin_return_address(0));
return;
}
Wait_list *list = static_cast<Wait_list *>(q->list);
Lx::Task *task = Lx::scheduler().current();
task->wait_enqueue(list);
}
void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *w, int state)
{
prepare_to_wait(q, w, state);
}
void finish_wait(wait_queue_head_t *q, wait_queue_t *w)
{
if (!q) {
PWRN("finish_wait: wait_queue_head_t is 0, ignore, called from: %p",
__builtin_return_address(0));
return;
}
Wait_list *list = static_cast<Wait_list *>(q->list);
Lx::Task *task = Lx::scheduler().current();
task->wait_dequeue(list);
}

View File

@ -0,0 +1,47 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/********************
** linux/ioport.h **
********************/
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
struct resource
{
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
};
struct device;
struct resource *request_region(resource_size_t start, resource_size_t n,
const char *name);
struct resource *request_mem_region(resource_size_t start, resource_size_t n,
const char *name);
struct resource * devm_request_mem_region(struct device *dev, resource_size_t start,
resource_size_t n, const char *name);
void release_region(resource_size_t start, resource_size_t n);
void release_mem_region(resource_size_t start, resource_size_t n);
resource_size_t resource_size(const struct resource *res);

View File

@ -0,0 +1,26 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/***********************
** linux/irqreturn.h **
***********************/
typedef enum irqreturn {
IRQ_NONE = 0,
IRQ_HANDLED = 1,
IRQ_WAKE_THREAD = 2,
} irqreturn_t;

View File

@ -0,0 +1,46 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*********************
** linux/jiffies.h **
*********************/
#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1)
extern unsigned long jiffies;
enum {
JIFFIES_TICK_MS = 1000/HZ,
JIFFIES_TICK_US = 1000*1000/HZ,
};
static inline unsigned long msecs_to_jiffies(const unsigned int m) { return m / JIFFIES_TICK_MS; }
static inline unsigned int jiffies_to_msecs(const unsigned long j) { return j * JIFFIES_TICK_MS; }
static inline unsigned long usecs_to_jiffies(const unsigned int u) { return u / JIFFIES_TICK_US; }
clock_t jiffies_to_clock_t(unsigned long x);
static inline clock_t jiffies_delta_to_clock_t(long delta)
{
return jiffies_to_clock_t(max(0L, delta));
}
#define time_after(a,b) ((long)((b) - (a)) < 0)
#define time_after_eq(a,b) ((long)((a) - (b)) >= 0)
#define time_before(a,b) time_after(b,a)
#define time_before_eq(a,b) time_after_eq(b,a)
#define time_is_after_jiffies(a) time_before(jiffies, a)

View File

@ -0,0 +1,172 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*********************
** linux/kconfig.h **
*********************/
#define IS_ENABLED(x) x
/********************
** linux/kernel.h **
********************/
/*
* Log tags
*/
#define KERN_ALERT "ALERT: "
#define KERN_CRIT "CRTITCAL: "
#define KERN_DEBUG "DEBUG: "
#define KERN_EMERG "EMERG: "
#define KERN_ERR "ERROR: "
#define KERN_INFO "INFO: "
#define KERN_NOTICE "NOTICE: "
#define KERN_WARNING "WARNING: "
#define KERN_WARN "WARNING: "
/*
* Debug macros
*/
#if DEBUG_LINUX_PRINTK
#define printk _printk
#define vprintk lx_vprintf
#else
#define printk(...)
#define vprintk(...)
#endif
static inline __printf(1, 2) void panic(const char *fmt, ...) __noreturn;
static inline void panic(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
lx_vprintf(fmt, args);
va_end(args);
lx_printf("panic()");
while (1) ;
}
/*
* Bits and types
*/
/* needed by linux/list.h */
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
/* normally provided by linux/stddef.h, needed by linux/list.h */
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define max_t(type, x, y) ({ \
type __max1 = (x); \
type __max2 = (y); \
__max1 > __max2 ? __max1: __max2; })
/**
* Return minimum of two given values
*
* XXX check how this function is used (argument types)
*/
static inline size_t min(size_t a, size_t b) {
return a < b ? a : b; }
/**
* Return maximum of two given values
*
* XXX check how this function is used (argument types)
*/
#define max(x, y) ({ \
typeof(x) _max1 = (x); \
typeof(y) _max2 = (y); \
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1: __min2; })
#define abs(x) ( { \
typeof (x) _x = (x); \
_x < 0 ? -_x : _x; })
#define lower_32_bits(n) ((u32)(n))
#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
#define roundup(x, y) ( \
{ \
const typeof(y) __y = y; \
(((x) + (__y - 1)) / __y) * __y; \
})
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
#define round_down(x, y) ((x) & ~__round_mask(x, y))
#define clamp_val(val, min, max) ({ \
typeof(val) __val = (val); \
typeof(val) __min = (min); \
typeof(val) __max = (max); \
__val = __val < __min ? __min: __val; \
__val > __max ? __max: __val; })
#define clamp_t(type, val, min, max) ({ \
type __val = (val); \
type __min = (min); \
type __max = (max); \
__val = __val < __min ? __min: __val; \
__val > __max ? __max: __val; })
#define DIV_ROUND_CLOSEST(x, divisor)( \
{ \
typeof(x) __x = x; \
typeof(divisor) __d = divisor; \
(((typeof(x))-1) > 0 || \
((typeof(divisor))-1) > 0 || (__x) > 0) ? \
(((__x) + ((__d) / 2)) / (__d)) : \
(((__x) - ((__d) / 2)) / (__d)); \
})
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define BUILD_BUG_ON(condition)
#define _RET_IP_ (unsigned long)__builtin_return_address(0)
void might_sleep();
#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)
#define INT_MAX ((int)(~0U>>1))
#define UINT_MAX (~0U)
#define INT_MIN (-INT_MAX - 1)
#define USHRT_MAX ((u16)(~0U))
#define LONG_MAX ((long)(~0UL>>1))
#define SHRT_MAX ((s16)(USHRT_MAX>>1))
#define SHRT_MIN ((s16)(-SHRT_MAX - 1))
#define ULONG_MAX (~0UL)
#define swap(a, b) \
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)

View File

@ -0,0 +1,44 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/******************
** linux/kref.h **
******************/
struct kref { atomic_t refcount; };
void kref_init(struct kref *kref);
void kref_get(struct kref *kref);
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
/*********************
** linux/kobject.h **
*********************/
struct kobject { struct kobject *parent; };
struct kobj_uevent_env
{
char buf[32];
int buflen;
};
struct kobj_uevent_env;
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
char *kobject_name(const struct kobject *kobj);
char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask);

View File

@ -0,0 +1,43 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/********************
** linux/poison.h **
********************/
/*
* In list.h, LIST_POISON1 and LIST_POISON2 are assigned to 'struct list_head
* *' as well as 'struct hlist_node *' pointers. Consequently, C++ compiler
* produces an error "cannot convert... in assignment". To compile 'list.h'
* included by C++ source code, we have to define these macros to the only
* value universally accepted for pointer assigments.h
*/
#ifdef __cplusplus
#define LIST_POISON1 nullptr
#define LIST_POISON2 nullptr
#else
#define LIST_POISON1 ((void *)0x00100100)
#define LIST_POISON2 ((void *)0x00200200)
#endif /* __cplusplus */
/******************
** linux/list.h **
******************/
#include <linux/list.h>

View File

@ -0,0 +1,30 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/**********************
** asm-generic/io.h **
**********************/
#define writeq(value, addr) (*(volatile uint64_t *)(addr) = (value))
#define writel(value, addr) (*(volatile uint32_t *)(addr) = (value))
#define writew(value, addr) (*(volatile uint16_t *)(addr) = (value))
#define writeb(value, addr) (*(volatile uint8_t *)(addr) = (value))
#define readq(addr) (*(volatile uint64_t *)(addr))
#define readl(addr) (*(volatile uint32_t *)(addr))
#define readw(addr) (*(volatile uint16_t *)(addr))
#define readb(addr) (*(volatile uint8_t *)(addr))

View File

@ -0,0 +1,70 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/******************
** linux/init.h **
******************/
#define __init
#define __exit
#define __devinitconst
#define _SETUP_CONCAT(a, b) __##a##b
#define SETUP_CONCAT(a, b) _SETUP_CONCAT(a, b)
#define __setup(str, fn) static void SETUP_CONCAT(fn, SETUP_SUFFIX)(void *addrs) { fn(addrs); }
#define core_initcall(fn) void core_##fn(void) { fn(); }
#define subsys_initcall(fn) void subsys_##fn(void) { fn(); }
#define pure_initcall(fd) void pure_##fn(void) { printk("PURE_INITCALL"); fn(); }
/********************
** linux/module.h **
********************/
#define EXPORT_SYMBOL(x)
#define EXPORT_SYMBOL_GPL(x)
#define MODULE_LICENSE(x)
#define MODULE_NAME_LEN (64 - sizeof(long))
#define MODULE_ALIAS(name)
#define MODULE_AUTHOR(name)
#define MODULE_DESCRIPTION(desc)
#define MODULE_VERSION(version)
#define THIS_MODULE 0
#define MODULE_FIRMWARE(_firmware)
#define MODULE_DEVICE_TABLE(type, name)
struct module;
#define module_init(fn) void module_##fn(void) { fn(); }
#define module_exit(fn) void module_exit_##fn(void) { fn(); }
void module_put_and_exit(int);
void module_put(struct module *);
void __module_get(struct module *module);
int try_module_get(struct module *);
/*************************
** linux/moduleparam.h **
*************************/
#define module_param(name, type, perm)
#define module_param_named(name, value, type, perm)
#define MODULE_PARM_DESC(_parm, desc)
#define kparam_block_sysfs_write(name)
#define kparam_unblock_sysfs_write(name)

View File

@ -0,0 +1,43 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************
** linux/mutex.h **
*******************/
struct mutex
{
int state;
void *holder;
void *waiters;
unsigned id; /* for debugging */
};
#define DEFINE_MUTEX(mutexname) \
struct mutex mutexname; \
static void __attribute__((constructor)) mutex_init_ ## mutexname(void) \
{ mutex_init(&mutexname); }
void mutex_init(struct mutex *m);
void mutex_destroy(struct mutex *m);
void mutex_lock(struct mutex *m);
void mutex_unlock(struct mutex *m);
int mutex_trylock(struct mutex *m);
int mutex_is_locked(struct mutex *m);
/* special case in net/wireless/util.c:1357 */
#define mutex_lock_nested(lock, subclass) mutex_lock(lock)

View File

@ -0,0 +1,149 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*****************
** linux/pci.h **
*****************/
#include <linux/pci_ids.h>
#include <uapi/linux/pci_regs.h>
enum {
PCI_DMA_BIDIRECTIONAL = 0,
PCI_DMA_TODEVICE,
PCI_DMA_FROMDEVICE,
PCI_DMA_NONE
};
enum { PCI_ANY_ID = ~0U };
typedef enum {
PCI_D0 = 0,
PCI_D1 = 1,
PCI_D3hot = 3,
PCI_D3cold = 4,
} pci_power_t;
/*
* PCI types
*/
struct pci_bus;
struct pci_dev;
struct pci_driver {
char *name;
const struct pci_device_id *id_table;
int (*probe) (struct pci_dev *dev,
const struct pci_device_id *id);
void (*remove) (struct pci_dev *dev);
struct device_driver driver;
};
static inline uint32_t PCI_DEVFN(unsigned slot, unsigned func) {
return ((slot & 0x1f) << 3) | (func & 0x07); }
static inline uint32_t PCI_FUNC(unsigned devfn) { return devfn & 0x07; }
static inline uint32_t PCI_SLOT(unsigned devfn) { return ((devfn) >> 3) & 0x1f; }
int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val);
int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val);
int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val);
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val);
static inline
int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) {
return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val); }
static inline
int pci_read_config_word(struct pci_dev *dev, int where, u16 *val) {
return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); }
static inline
int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val) {
return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val); }
static inline
int pci_write_config_byte(struct pci_dev *dev, int where, u8 val) {
return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val); }
static inline
int pci_write_config_word(struct pci_dev *dev, int where, u16 val) {
return pci_bus_write_config_word(dev->bus, dev->devfn, where, val); }
static inline
int pci_write_config_dword(struct pci_dev *dev, int where, u32 val) {
return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); }
size_t pci_resource_len(struct pci_dev *dev, unsigned bar);
size_t pci_resource_start(struct pci_dev *dev, unsigned bar);
void pci_dev_put(struct pci_dev *dev);
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from);
int pci_enable_device(struct pci_dev *dev);
void pci_disable_device(struct pci_dev *dev);
int pci_register_driver(struct pci_driver *driver);
void pci_unregister_driver(struct pci_driver *driver);
const char *pci_name(const struct pci_dev *pdev);
bool pci_dev_run_wake(struct pci_dev *dev);
unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar);
void pci_set_master(struct pci_dev *dev);
int pci_set_mwi(struct pci_dev *dev);
bool pci_pme_capable(struct pci_dev *dev, pci_power_t state);
int pci_find_capability(struct pci_dev *dev, int cap);
struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
int pci_request_regions(struct pci_dev *dev, const char *res_name);
void pci_release_regions(struct pci_dev *dev);
void *pci_ioremap_bar(struct pci_dev *pdev, int bar);
void pci_disable_link_state(struct pci_dev *pdev, int state);
int pci_enable_msi(struct pci_dev *dev);
void pci_disable_msi(struct pci_dev *dev);
#define DEFINE_PCI_DEVICE_TABLE(_table) \
const struct pci_device_id _table[] __devinitconst
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
int pci_register_driver(struct pci_driver *driver);
int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
void *pci_get_drvdata(struct pci_dev *pdev);
#define dev_is_pci(d) (1)
int pci_num_vf(struct pci_dev *dev);
/* XXX will this cast ever work? */
#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf((struct pci_dev *)d) : 0))
/**********************
** linux/pci-aspm.h **
**********************/
#define PCIE_LINK_STATE_L0S 1
#define PCIE_LINK_STATE_L1 2
#define PCIE_LINK_STATE_CLKPM 4

View File

@ -0,0 +1,43 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/****************
** linux/pm.h **
****************/
struct device;
typedef struct pm_message { int event; } pm_message_t;
struct dev_pm_info { pm_message_t power_state; };
struct dev_pm_ops {
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*freeze)(struct device *dev);
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
};
#define PMSG_IS_AUTO(msg) 0
enum { PM_EVENT_AUTO_SUSPEND = 0x402 };
#define PM_EVENT_SUSPEND 0x0002

View File

@ -0,0 +1,32 @@
/*
* \brief Debugging utilities
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
void lx_printf(char const *, ...) __attribute__((format(printf, 1, 2)));
void lx_vprintf(char const *, va_list);
#define lx_printfln(args...) \
do { \
lx_printf(args); \
lx_printf("\n"); \
} while (0);
#define lx_log(doit, msg...) \
do { \
if (doit) { \
lx_printf("%s(): ", __func__); \
lx_printf(msg); \
lx_printf("\n"); \
} \
} while(0)

View File

@ -0,0 +1,91 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*************************
** linux/scatterlist.h **
*************************/
enum {
SG_MITER_TO_SG = 2,
SG_MITER_FROM_SG = 4,
};
struct scatterlist {
unsigned long page_link;
unsigned int offset;
unsigned int length;
dma_addr_t dma_address;
int last;
};
struct sg_table
{
struct scatterlist *sgl; /* the list */
unsigned int nents; /* number of mapped entries */
};
struct sg_page_iter
{
struct scatterlist *sg;
unsigned int sg_pgoffset; /* page offset within the sg */
};
struct sg_mapping_iter
{
void *addr;
size_t length;
struct sg_page_iter piter;
};
struct page;
void sg_init_table(struct scatterlist *, unsigned int);
void sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen);
void sg_set_page(struct scatterlist *sg, struct page *page,
unsigned int len, unsigned int offset);
struct page *sg_page(struct scatterlist *sg);
void *sg_virt(struct scatterlist *sg);
struct scatterlist *sg_next(struct scatterlist *);
int sg_nents(struct scatterlist *sg);
size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen);
size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents,
void *buf, size_t buflen);
bool __sg_page_iter_next(struct sg_page_iter *piter);
void __sg_page_iter_start(struct sg_page_iter *piter,
struct scatterlist *sglist, unsigned int nents,
unsigned long pgoffset);
#define for_each_sg(sglist, sg, nr, __i) \
for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
#define for_each_sg_page(sglist, piter, nents, pgoffset) \
for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \
__sg_page_iter_next(piter);)
#define sg_dma_address(sg) ((sg)->dma_address)
#define sg_dma_len(sg) ((sg)->length)
void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl,
unsigned int nents, unsigned int flags);
bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset);
bool sg_miter_next(struct sg_mapping_iter *miter);
void sg_miter_stop(struct sg_mapping_iter *miter);

View File

@ -0,0 +1,34 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************
** linux/rwsem.h **
*******************/
struct rw_semaphore { int dummy; };
#define DECLARE_RWSEM(name) \
struct rw_semaphore name = { 0 }
#define init_rwsem(sem) do { (void)sem; } while (0)
void down_read(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);
void down_write(struct rw_semaphore *sem);
void up_write(struct rw_semaphore *sem);
#define __RWSEM_INITIALIZER(name) { 0 }

View File

@ -0,0 +1,44 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/**********************
** linux/spinlock.h **
**********************/
typedef struct spinlock { unsigned unused; } spinlock_t;
#define DEFINE_SPINLOCK(name) spinlock_t name
void spin_lock(spinlock_t *lock);
void spin_lock_nested(spinlock_t *lock, int subclass);
void spin_unlock(spinlock_t *lock);
void spin_lock_init(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_unlock_irq(spinlock_t *lock);
void assert_spin_locked(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
int spin_trylock(spinlock_t *lock);
/****************************
** linux/spinlock_types.h **
****************************/
#define __SPIN_LOCK_UNLOCKED(x) 0

View File

@ -0,0 +1,43 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/********************
** linux/string.h **
********************/
#undef memcpy
void *memcpy(void *d, const void *s, size_t n);
void *memset(void *s, int c, size_t n);
int memcmp(const void *, const void *, size_t);
void *memscan(void *addr, int c, size_t size);
char *strcat(char *dest, const char *src);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *cs, const char *ct, size_t count);
char *strcpy(char *to, const char *from);
char *strncpy(char *, const char *, size_t);
char *strchr(const char *, int);
char *strrchr(const char *,int);
size_t strlcat(char *dest, const char *src, size_t n);
size_t strlcpy(char *dest, const char *src, size_t size);
size_t strlen(const char *);
size_t strnlen(const char *, size_t);
char * strsep(char **,const char *);
char *strstr(const char *, const char *);
char *kstrdup(const char *s, gfp_t gfp);
void *kmemdup(const void *src, size_t len, gfp_t gfp);
void *memmove(void *, const void *, size_t);
void * memchr(const void *, int, size_t);

View File

@ -0,0 +1,82 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/******************
** linux/time.h **
******************/
struct timespec {
__kernel_time_t tv_sec;
long tv_nsec;
};
struct timeval { };
struct timespec current_kernel_time(void);
void do_gettimeofday(struct timeval *tv);
#define CURRENT_TIME (current_kernel_time())
enum {
CLOCK_REALTIME = 0,
CLOCK_MONOTONIC = 1,
NSEC_PER_USEC = 1000L,
NSEC_PER_MSEC = 1000000L,
NSEC_PER_SEC = 1000L * NSEC_PER_MSEC,
};
/*******************
** linux/ktime.h **
*******************/
union ktime { s64 tv64; };
typedef union ktime ktime_t;
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec);
static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec)
{
return ktime_add_ns(kt, usec * 1000);
}
static inline ktime_t ktime_get(void)
{
return (ktime_t){ .tv64 = (s64)jiffies * HZ * NSEC_PER_MSEC /* ns */ };
}
static inline ktime_t ktime_set(const long sec, const unsigned long nsec)
{
return (ktime_t){ .tv64 = (s64)sec * NSEC_PER_SEC + (s64)nsec /* ns */ };
}
static inline ktime_t ktime_add(const ktime_t a, const ktime_t b)
{
return (ktime_t){ .tv64 = a.tv64 + b.tv64 /* ns */ };
}
s64 ktime_us_delta(const ktime_t later, const ktime_t earlier);
struct timeval ktime_to_timeval(const ktime_t);
ktime_t ktime_get_real(void);
ktime_t ktime_sub(const ktime_t, const ktime_t);
ktime_t ktime_get_monotonic_offset(void);

View File

@ -0,0 +1,50 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************
** linux/timer.h **
*******************/
struct tvec_base;
extern struct tvec_base boot_tvec_bases; /* needed by 'dwc_common_linux.c' */
struct timer_list
{
void (*function)(unsigned long);
unsigned long data;
void *timer;
unsigned long expires;
struct tvec_base *base; /* needed by 'dwc_common_linux.c' */
};
void init_timer(struct timer_list *);
void init_timer_deferrable(struct timer_list *);
int mod_timer(struct timer_list *timer, unsigned long expires);
int del_timer(struct timer_list * timer);
void setup_timer(struct timer_list *timer, void (*function)(unsigned long),
unsigned long data);
int timer_pending(const struct timer_list * timer);
unsigned long round_jiffies(unsigned long j);
unsigned long round_jiffies_relative(unsigned long j);
unsigned long round_jiffies_up(unsigned long j);
void set_timer_slack(struct timer_list *time, int slack_hz);
static inline void add_timer(struct timer_list *timer) { mod_timer(timer, timer->expires); }
static inline
int del_timer_sync(struct timer_list * timer) { return del_timer(timer); }

View File

@ -0,0 +1,106 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*******************
** linux/types.h **
*******************/
typedef genode_int8_t int8_t;
typedef genode_uint8_t uint8_t;
typedef genode_int16_t int16_t;
typedef genode_uint16_t uint16_t;
typedef genode_int32_t int32_t;
typedef genode_uint32_t uint32_t;
typedef __SIZE_TYPE__ size_t;
typedef genode_int64_t int64_t;
typedef genode_uint64_t uint64_t;
typedef uint32_t uint;
typedef unsigned long ulong;
typedef int8_t s8;
typedef uint8_t u8;
typedef int16_t s16;
typedef uint16_t u16;
typedef int32_t s32;
typedef uint32_t u32;
typedef int64_t s64;
typedef uint64_t u64;
typedef int8_t __s8;
typedef uint8_t __u8;
typedef int16_t __s16;
typedef uint16_t __u16;
typedef int32_t __s32;
typedef uint32_t __u32;
typedef int64_t __s64;
typedef uint64_t __u64;
struct list_head {
struct list_head *next, *prev;
};
struct hlist_head {
struct hlist_node *first;
};
struct hlist_node {
struct hlist_node *next, **pprev;
};
#ifndef __cplusplus
typedef _Bool bool;
enum { true = 1, false = 0 };
#endif /* __cplusplus */
#ifndef NULL
#ifdef __cplusplus
#define NULL nullptr
#else
#define NULL ((void *)0)
#endif /* __cplusplus */
#endif /* NULL */
typedef unsigned gfp_t;
typedef unsigned long dma_addr_t;
typedef unsigned long pgoff_t;
typedef long long loff_t;
typedef long ssize_t;
typedef unsigned long uintptr_t;
typedef int dev_t;
typedef size_t resource_size_t;
typedef long off_t;
typedef int pid_t;
typedef unsigned fmode_t;
typedef u32 uid_t;
typedef u32 gid_t;
typedef unsigned kuid_t;
typedef unsigned kgid_t;
typedef long __kernel_time_t;
typedef unsigned short umode_t;
typedef __u16 __be16;
typedef __u32 __be32;
typedef long clock_t;
#ifndef __cplusplus
typedef u16 wchar_t;
#endif
/*
* XXX 'mode_t' is 'unsigned int' on x86_64
*/
typedef unsigned short mode_t;

View File

@ -0,0 +1,203 @@
/*
* \brief Linux kernel API
* \author Norman Feske
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2014-08-21
*
* Based on the prototypes found in the Linux kernel's 'include/'.
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/***********************
** linux/workqueue.h **
***********************/
enum {
WQ_MEM_RECLAIM,
WQ_CPU_INTENSIVE,
};
struct work_struct;
typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
work_func_t func;
struct list_head entry;
};
struct delayed_work {
struct timer_list timer;
struct work_struct work;
};
bool cancel_work_sync(struct work_struct *work);
bool cancel_delayed_work_sync(struct delayed_work *work);
bool cancel_delayed_work(struct delayed_work *dwork);
int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
int schedule_work(struct work_struct *work);
void flush_scheduled_work(void);
bool flush_work(struct work_struct *work);
bool flush_work_sync(struct work_struct *work);
#define PREPARE_WORK(_work, _func) \
do { (_work)->func = (_func); } while (0)
#define PREPARE_DELAYED_WORK(_work, _func) \
PREPARE_WORK(&(_work)->work, (_func))
#define __INIT_WORK(_work, _func, on_stack) \
do { \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
#define INIT_WORK(_work, _func)\
do { __INIT_WORK((_work), (_func), 0); } while (0)
#define INIT_DELAYED_WORK(_work, _func) \
do { \
INIT_WORK(&(_work)->work, (_func)); \
init_timer(&(_work)->timer); \
} while (0)
/* dummy for queue_delayed_work call in storage/usb.c */
#define system_freezable_wq 0
struct workqueue_struct { unsigned unused; };
struct workqueue_struct *create_singlethread_workqueue(const char *name);
struct workqueue_struct *alloc_ordered_workqueue(const char *fmt, unsigned int flags, ...) __printf(1, 3);
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags,
int max_active, ...) __printf(1, 4);
void destroy_workqueue(struct workqueue_struct *wq);
void flush_workqueue(struct workqueue_struct *wq);
bool queue_delayed_work(struct workqueue_struct *, struct delayed_work *, unsigned long);
bool flush_delayed_work(struct delayed_work *dwork);
bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
#define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n
bool mod_delayed_work(struct workqueue_struct *, struct delayed_work *,
unsigned long);
static inline struct delayed_work *to_delayed_work(struct work_struct *work)
{
return container_of(work, struct delayed_work, work);
}
extern struct workqueue_struct *system_wq;
enum {
WORK_STRUCT_STATIC = 0,
WORK_STRUCT_COLOR_SHIFT = 4,
WORK_STRUCT_COLOR_BITS = 4,
WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + WORK_STRUCT_COLOR_BITS,
WORK_OFFQ_FLAG_BASE = WORK_STRUCT_FLAG_BITS,
WORK_OFFQ_FLAG_BITS = 1,
WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT,
WORK_OFFQ_POOL_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31,
WORK_OFFQ_POOL_NONE = (1LU << WORK_OFFQ_POOL_BITS) - 1,
WORK_STRUCT_NO_POOL = (unsigned long)WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT,
};
#define WORK_DATA_STATIC_INIT() \
ATOMIC_LONG_INIT(WORK_STRUCT_NO_POOL | WORK_STRUCT_STATIC)
#define __WORK_INIT_LOCKDEP_MAP(n, k)
#define __WORK_INITIALIZER(n, f) { \
.data = WORK_DATA_STATIC_INIT(), \
.entry = { &(n).entry, &(n).entry }, \
.func = (f), \
__WORK_INIT_LOCKDEP_MAP(#n, &(n)) \
}
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
/******************
** linux/wait.h **
******************/
typedef struct wait_queue_head { void *list; } wait_queue_head_t;
typedef struct wait_queue { unsigned unused; } wait_queue_t;
#define DEFINE_WAIT(name) \
wait_queue_t name;
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { 0 }
#define DECLARE_WAITQUEUE(name, tsk) \
wait_queue_t name
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
#define DEFINE_WAIT_FUNC(name, function) \
wait_queue_t name
/* simplified signature */
void __wake_up(wait_queue_head_t *q, bool all);
#define wake_up(x) __wake_up(x, false)
#define wake_up_all(x) __wake_up(x, true)
#define wake_up_interruptible(x) __wake_up(x, false)
#define wake_up_interruptible_all(x) __wake_up(x, true)
void init_waitqueue_head(wait_queue_head_t *);
int waitqueue_active(wait_queue_head_t *);
/* void wake_up_interruptible(wait_queue_head_t *); */
void wake_up_interruptible_sync_poll(wait_queue_head_t *, int);
void wake_up_interruptible_poll(wait_queue_head_t *, int);
void prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int);
void prepare_to_wait_exclusive(wait_queue_head_t *, wait_queue_t *, int);
void finish_wait(wait_queue_head_t *, wait_queue_t *);
int autoremove_wake_function(wait_queue_t *, unsigned, int, void *);
void add_wait_queue(wait_queue_head_t *, wait_queue_t *);
void add_wait_queue_exclusive(wait_queue_head_t *, wait_queue_t *);
void remove_wait_queue(wait_queue_head_t *, wait_queue_t *);
/* our wait event implementation - it's okay as value */
void __wait_event(wait_queue_head_t);
#define _wait_event(wq, condition) while (!(condition)) { __wait_event(wq); }
#define wait_event(wq, condition) ({ _wait_event(wq, condition); })
#define wait_event_interruptible(wq, condition) ({ _wait_event(wq, condition); 0; })
#define _wait_event_timeout(wq, condition, timeout) \
({ int res = 1; \
prepare_to_wait(&wq, 0, 0); \
while (1) { \
if ((condition) || !res) { \
break; \
} \
res = schedule_timeout(jiffies + timeout); \
} \
finish_wait(&wq, 0); \
res; \
})
#define wait_event_timeout(wq, condition, timeout) \
({ \
int ret = _wait_event_timeout(wq, (condition), timeout); \
ret; \
})

View File

@ -0,0 +1,27 @@
/*
* \brief Architecture-specific code
* \author Sebastian Sumpf
* \date 2012-06-10
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ARCH_EXECUTE_H_
#define _ARCH_EXECUTE_H_
static inline
void arch_execute(void *sp, void *func, void *arg)
{
asm volatile ("movl %2, 0(%0);"
"movl %1, -0x4(%0);"
"movl %0, %%esp;"
"call *-4(%%esp);"
: : "r" (sp), "r" (func), "r" (arg));
}
#endif /* _ARCH_EXECUTE_H_ */

View File

@ -0,0 +1,28 @@
/*
* \brief Architecture-specific code
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \date 2012-06-10
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _ARCH_EXECUTE_H_
#define _ARCH_EXECUTE_H_
static inline
void arch_execute(void *sp, void *func, void *arg)
{
asm volatile ("movq %2, %%rdi;"
"movq %1, 0(%0);"
"movq %0, %%rsp;"
"call *0(%%rsp);"
: "+r" (sp), "+r" (func), "+r" (arg) : : "memory");
}
#endif /* _ARCH_EXECUTE_H_ */

View File

@ -0,0 +1,19 @@
/*******************
** asm/barrier.h **
*******************/
#define mb() asm volatile ("mfence": : :"memory")
#define rmb() asm volatile ("lfence": : :"memory")
#define wmb() asm volatile ("sfence": : :"memory")
/*
* This is the "safe" implementation as needed for a configuration
* with SMP enabled.
*/
#define smp_mb() mb()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
static inline void barrier() { asm volatile ("": : :"memory"); }