dde_bsd: add audio drivers ported from OpenBSD

These audio drivers enable support for Intel HD Audio (Azalia) and
Ensoniq AudioPCI (ES1370) compatible soundcards. They are ported
from OpenBSD 5.7.

Fixes #1498.
This commit is contained in:
Josef Söntgen 2015-04-29 17:00:04 +02:00
parent df04b17594
commit 49dd9242f7
33 changed files with 4035 additions and 0 deletions

24
repos/dde_bsd/Makefile Normal file
View File

@ -0,0 +1,24 @@
#
# \brief Download, and unpack BSD kernel sources
# \author Josef Soentgen
# \date 2014-11-09
#
VERBOSE ?= @
ECHO := @echo
#
# Print help information by default
#
help::
prepare:
$(VERBOSE)../../tool/ports/prepare_port dde_bsd
help::
$(ECHO)
$(ECHO) "Prepare the dde_bsd repository"
$(ECHO)
$(ECHO) "--- available commands ---"
$(ECHO) "prepare - checkout upstream source codes"
$(ECHO)

29
repos/dde_bsd/README Normal file
View File

@ -0,0 +1,29 @@
This repository contains device drivers ported from OpenBSD.
Audio
#####
The audio driver is ported from OpenBSD 5.7 and includes support for
Intel HD Audio as well as for Ensoniq AudioPCI (ES1370) compatible
soundcards. The HDA driver works on real hardware and Virtualbox
whereas the ES1370 driver is only used in Qemu.
Usage
=====
You have to prepare the contrib sources for this repository by
executing _tool/ports/prepare_port dde_bsd_. Also you need to make
sure to add the 'dde_bsd' repository to the REPOSITORIES variable
in your 'etc/build.conf'.
Example
=======
The driver can be tested by executing the run script 'run/audio_out.run'.
This example plays a sample file in a loop. The file format is header less
two channel float 32 at 44100 Hz. You may use the 'sox' utility to create
these audio files:
! sox -c 2 -r 44100 foo.wav foo.f32

18
repos/dde_bsd/audio.list Normal file
View File

@ -0,0 +1,18 @@
./sys/dev/audio.c
./sys/dev/audio_if.h
./sys/dev/pci/azalia.c
./sys/dev/pci/azalia.h
./sys/dev/pci/azalia_codec.c
./sys/dev/pci/eap.c
./sys/dev/pci/eapreg.h
./sys/dev/pci/pcidevs.h
./sys/dev/pci/pcidevs_data.h
./sys/dev/auconv.c
./sys/dev/auconv.h
./sys/dev/mulaw.c
./sys/dev/mulaw.h
./sys/dev/ic/ac97.c
./sys/dev/ic/ac97.h
./sys/sys/audioio.h
./sys/sys/device.h
./sys/sys/queue.h

View File

@ -0,0 +1,40 @@
/*
* \brief Audio library interface
* \author Josef Soentgen
* \date 2014-12-27
*
* This header declares the private Audio namespace. It contains
* functions called by the driver frontend that are implemented
* by the driver library.
*/
/*
* 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 _AUDIO__AUDIO_H_
#define _AUDIO__AUDIO_H_
#include <os/server.h>
/*****************************
** private Audio namespace **
*****************************/
namespace Audio {
enum Channel_number { LEFT, RIGHT, MAX_CHANNELS, INVALID = MAX_CHANNELS };
void init_driver(Server::Entrypoint &ep);
bool driver_active();
void dma_notifier(Genode::Signal_context_capability cap);
int play(short *data, Genode::size_t size);
}
#endif /* _AUDIO__AUDIO_H_ */

View File

@ -0,0 +1,77 @@
LIB_DIR = $(REP_DIR)/src/lib/audio
LIB_INC_DIR = $(LIB_DIR)/include
AUDIO_CONTRIB_DIR := $(call select_from_ports,dde_bsd)/src/lib/audio
INC_DIR += $(LIB_DIR)
INC_DIR += $(LIB_INC_DIR)
INC_DIR += $(AUDIO_CONTRIB_DIR)
SRC_CC += bus.cc dummies.cc driver.cc irq.cc mem.cc misc.cc scheduler.cc timer.cc
SRC_C += bsd_emul.c
SRC_S += setjmp.S
CC_OPT += -Wno-unused-but-set-variable
# disable builtins
CC_OPT += -fno-builtin-printf -fno-builtin-snprintf -fno-builtin-vsnprintf \
-fno-builtin-malloc -fno-builtin-free -fno-builtin-log -fno-builtin-log2
CC_OPT += -D_KERNEL
# enable when debugging
# CC_OPT += -DAUDIO_DEBUG
# CC_OPT += -DAZALIA_DEBUG
# CC_OPT += -DDIAGNOSTIC
# audio interface
SRC_C += dev/audio.c dev/auconv.c
# AC97 codec
SRC_C += dev/ic/ac97.c
# HDA driver
SRC_C += dev/pci/azalia.c dev/pci/azalia_codec.c
# ES1370
SRC_C += dev/pci/eap.c
SRC_C += dev/mulaw.c
#
# Determine the header files included by the contrib code. For each
# of these header files we create a symlink to 'bsd_emul.h'.
#
GEN_INCLUDES := $(shell grep -rh "^\#include .*" $(AUDIO_CONTRIB_DIR) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" | sort | uniq)
#
# Filter out original BSD headers that exist in the contrib directory
#
NO_GEN_INCLUDES := $(shell cd $(AUDIO_CONTRIB_DIR); find -name "*.h" | sed "s/.\///" | sed "s/.*include\///")
GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES))
#
# Put BSD headers in 'GEN_INC' dir
#
GEN_INC := $(shell pwd)/include
$(shell mkdir -p $(GEN_INC))
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
INC_DIR += $(GEN_INC)
#
# Make sure to create the header symlinks prior building
#
$(SRC_C:.c=.o) $(SRC_CC:.cc=.o): $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -s $(LIB_INC_DIR)/bsd_emul.h $@
vpath %.c $(AUDIO_CONTRIB_DIR)
vpath %.c $(LIB_DIR)
vpath %.cc $(LIB_DIR)
# vi: set ft=make :

View File

@ -0,0 +1,5 @@
INC_DIR += $(LIB_INC_DIR)/x86_32 $(LIB_INC_DIR)/x86
include $(REP_DIR)/lib/mk/audio.inc
vpath %.S $(LIB_DIR)/x86_32

View File

@ -0,0 +1,5 @@
INC_DIR += $(LIB_INC_DIR)/x86_64 $(LIB_INC_DIR)/x86
include $(REP_DIR)/lib/mk/audio.inc
vpath %.S $(LIB_DIR)/x86_64

View File

@ -0,0 +1,14 @@
dev/audio.c:XXX:Y: warning: type may be used uninitialized in this function [-Wmaybe-uninitialized]
diff --git a/dev/audio.c b/dev/audio.c
index a9fa22b..da8a783 100644
--- a/dev/audio.c
+++ b/dev/audio.c
@@ -639,7 +639,7 @@ int
audioprint(void *aux, const char *pnp)
{
struct audio_attach_args *arg = aux;
- const char *type;
+ const char *type = "never printed";
if (pnp != NULL) {
switch (arg->type) {

View File

@ -0,0 +1 @@
74279f98408dcf0fcd90849659e73fd1cbb82e78

View File

@ -0,0 +1,25 @@
LICENSE := BSD
VERSION := 1
DOWNLOADS := audio.archive
#
# Audio drivers from OpenBSD 5.7
#
SRC_DIR_AUDIO := src/lib/audio
VERSION_AUDIO := 5.7
URL(audio) := http://openbsd.cs.fau.de/pub/OpenBSD/$(VERSION_AUDIO)/sys.tar.gz
SHA(audio) := 1a60125a7fce6524b0d62643db47acca0b11506a
DIR(audio) := $(SRC_DIR_AUDIO)
TAR_OPT(audio) := --strip-components=2 --files-from $(REP_DIR)/audio.list
HASH_INPUT += $(REP_DIR)/audio.list
#
# Patches
#
PATCHES := $(addprefix patches/,$(notdir $(wildcard $(REP_DIR)/patches/*.patch)))
AUDIO_OPT := -p1 -d$(SRC_DIR_AUDIO)
PATCH_OPT(patches/oppress_warning.patch) := $(AUDIO_OPT)
PATCH_OPT(patches/eap_c.patch) := $(AUDIO_OPT)
# vi: set ft=make :

View File

@ -0,0 +1,166 @@
assert_spec x86
#
# Check used commands
#
set wget [check_installed wget]
#
# Configure
#
set use_mixer 0
#
# Build
#
set build_components {
core init
drivers/timer
drivers/audio_out
drivers/pci
test/audio_out
}
lappend_if [have_spec acpi] build_components drivers/acpi
lappend_if [have_spec pci] build_components drivers/pci/device_pd
lappend_if $use_mixer build_components server/mixer
build $build_components
create_boot_directory
#
# 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>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>}
append_if [have_spec acpi] config {
<start name="acpi_drv">
<resource name="RAM" quantum="6M"/>
<provides>
<service name="PCI"/>
<service name="IRQ" />
</provides>
<route>
<any-service> <parent/> <any-child /> </any-service>
</route>
<config>
<policy label="acpi_drv">
<pci class="ALL"/>
</policy>
<policy label="audio_out_drv">
<pci class="AUDIO"/>
</policy>
</config>
</start>}
append_if [expr ![have_spec acpi] && [have_spec pci]] config {
<start name="pci_drv">
<resource name="RAM" quantum="4M" constrain_phys="yes"/>
<provides> <service name="PCI"/> </provides>
<config>
<policy label="audio_out_drv">
<pci class="AUDIO"/>
</policy>
</config>
</start>}
append_if $use_mixer config {
<start name="mixer">
<resource name="RAM" quantum="2M"/>
<provides><service name="Audio_out"/></provides>
<route>
<service name="Audio_out"> <child name="audio_out_drv"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append config {
<start name="audio_out_drv">
<resource name="RAM" quantum="8M"/>
<provides>
<service name="Audio_out"/>
</provides>
</start>
<start name="test-audio_out">
<resource name="RAM" quantum="4M"/>
<config>
<filename>sample.raw</filename>
</config>
<route>}
append_if $use_mixer config {
<service name="Audio_out"><child name="mixer"/></service>}
append config {
<any-service><parent/><any-child/></any-service>
</route>
</start>
</config>}
install_config $config
#
# Get sample file
#
if {[info exists env(GENODE_SAMPLE_RAW)]} {
catch { exec $wget $::env(GENODE_SAMPLE_RAW) -O bin/sample.raw }
}
if {![file exists bin/sample.raw]} {
puts ""
puts "The sample file is missing. Please take a look at"
puts "repos/dde_bsd/README, create 'sample.raw' and put"
puts "the file into './bin'. afterwards"
puts ""
exit 1
}
#
# Boot modules
#
set boot_modules {
core init timer audio_out_drv test-audio_out sample.raw }
lappend_if $use_mixer boot_modules mixer
# platform-specific modules
lappend_if [have_spec acpi] boot_modules acpi_drv
lappend_if [have_spec pci] boot_modules pci_drv
lappend_if [have_spec nova] boot_modules pci_device_pd
build_boot_image $boot_modules
append qemu_args " -m 128 -nographic -soundhw es1370 "
#
# For obvious reasons the timeout depends on the total
# length of the used sample file.
#
run_genode_until {.*played.*1 time\(s\)} 60

View File

@ -0,0 +1,297 @@
/*
* \brief Startup audio driver library
* \author Josef Soentgen
* \date 2014-11-09
*/
#include <audio_out_session/rpc_object.h>
#include <base/env.h>
#include <base/sleep.h>
#include <cap_session/connection.h>
#include <os/server.h>
#include <root/component.h>
#include <util/misc_math.h>
#include <audio/audio.h>
static bool const verbose = false;
using namespace Genode;
using namespace Audio;
namespace Audio_out {
class Session_component;
class Out;
class Root;
struct Root_policy;
static Session_component *channel_acquired[MAX_CHANNELS];
}
class Audio_out::Session_component : public Audio_out::Session_rpc_object
{
private:
Channel_number _channel;
public:
Session_component(Channel_number channel, Signal_context_capability cap)
:
Session_rpc_object(cap), _channel(channel)
{
Audio_out::channel_acquired[_channel] = this;
}
~Session_component()
{
Audio_out::channel_acquired[_channel] = 0;
}
};
class Audio_out::Out
{
private:
Server::Entrypoint &_ep;
Genode::Signal_rpc_member<Audio_out::Out> _data_avail_dispatcher;
Genode::Signal_rpc_member<Audio_out::Out> _dma_notify_dispatcher;
bool _active() {
return channel_acquired[LEFT] && channel_acquired[RIGHT] &&
channel_acquired[LEFT]->active() && channel_acquired[RIGHT]->active();
}
Stream *left() { return channel_acquired[LEFT]->stream(); }
Stream *right() { return channel_acquired[RIGHT]->stream(); }
void _advance_position(Packet *l, Packet *r)
{
bool full_left = left()->full();
bool full_right = right()->full();
left()->pos(left()->packet_position(l));
right()->pos(right()->packet_position(r));
left()->increment_position();
right()->increment_position();
Session_component *channel_left = channel_acquired[LEFT];
Session_component *channel_right = channel_acquired[RIGHT];
if (full_left)
channel_left->alloc_submit();
if (full_right)
channel_right->alloc_submit();
channel_left->progress_submit();
channel_right->progress_submit();
}
void _play_silence()
{
static short silence[2 * Audio_out::PERIOD] = { 0 };
if (int err = Audio::play(silence, sizeof(silence)))
PWRN("Error %d during silence playback", err);
}
void _play_packet()
{
Packet *p_left = left()->get(left()->pos());
Packet *p_right = right()->get(right()->pos());
if ((p_left->valid() && p_right->valid())) {
/* convert float to S16LE */
static short data[2 * Audio_out::PERIOD];
for (int i = 0; i < 2 * Audio_out::PERIOD; i += 2) {
data[i] = p_left->content()[i / 2] * 32767;
data[i + 1] = p_right->content()[i / 2] * 32767;
}
/* send to driver */
if (int err = Audio::play(data, sizeof(data)))
PWRN("Error %d during playback", err);
} else
_play_silence();
p_left->invalidate();
p_right->invalidate();
p_left->mark_as_played();
p_right->mark_as_played();
_advance_position(p_left, p_right);
}
/*
* Data available in session buffer
*
* We do not care about this signal because we already have
* started to play and we will keep doing it, even if it is
* silence.
*/
void _handle_data_avail(unsigned) { }
/*
* DMA block played
*
* After each block played from the DMA buffer, the hw will
* generated an interrupt. The IRQ handling code will notify
* us as soon as this happens and we will play the next
* packet.
*/
void _handle_dma_notify(unsigned)
{
if (!_active())
return;
_play_packet();
}
public:
Out(Server::Entrypoint &ep)
:
_ep(ep),
_data_avail_dispatcher(ep, *this, &Audio_out::Out::_handle_data_avail),
_dma_notify_dispatcher(ep, *this, &Audio_out::Out::_handle_dma_notify)
{
/* play a silence packet to get the driver running */
_play_silence();
}
Signal_context_capability data_avail() { return _data_avail_dispatcher; }
Signal_context_capability dma_notifier() { return _dma_notify_dispatcher; }
const char *debug() { return "Audio out"; }
};
static bool channel_number_from_string(const char *name,
Channel_number *out_number)
{
static struct Names {
const char *name;
Channel_number number;
} names[] = {
{ "left", LEFT }, { "front left", LEFT },
{ "right", RIGHT }, { "front right", RIGHT },
{ 0, INVALID }
};
for (Names *n = names; n->name; ++n)
if (!Genode::strcmp(name, n->name)) {
*out_number = n->number;
return true;
}
return false;
}
/**
* Session creation policy for our service
*/
struct Audio_out::Root_policy
{
void aquire(const char *args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
size_t session_size =
align_addr(sizeof(Audio_out::Session_component), 12);
if ((ram_quota < session_size) ||
(sizeof(Stream) > ram_quota - session_size)) {
PERR("insufficient 'ram_quota', got %zd, need %zd",
ram_quota, sizeof(Stream) + session_size);
throw ::Root::Quota_exceeded();
}
char channel_name[16];
Channel_number channel_number;
Arg_string::find_arg(args, "channel").string(channel_name,
sizeof(channel_name),
"left");
if (!channel_number_from_string(channel_name, &channel_number))
throw ::Root::Invalid_args();
if (Audio_out::channel_acquired[channel_number])
throw ::Root::Unavailable();
}
void release() { }
};
namespace Audio_out {
typedef Root_component<Session_component, Root_policy> Root_component;
}
/**
* Root component, handling new session requests.
*/
class Audio_out::Root : public Audio_out::Root_component
{
private:
Server::Entrypoint &_ep;
Signal_context_capability _cap;
protected:
Session_component *_create_session(const char *args)
{
char channel_name[16];
Channel_number channel_number = INVALID;
Arg_string::find_arg(args, "channel").string(channel_name,
sizeof(channel_name),
"left");
channel_number_from_string(channel_name, &channel_number);
return new (md_alloc())
Session_component(channel_number, _cap);
}
public:
Root(Server::Entrypoint &ep, Allocator &md_alloc,
Signal_context_capability cap)
:
Root_component(&ep.rpc_ep(), &md_alloc),
_ep(ep), _cap(cap)
{ }
};
struct Main
{
Server::Entrypoint &ep;
Main(Server::Entrypoint &ep) : ep(ep)
{
Audio::init_driver(ep);
if (Audio::driver_active()) {
static Audio_out::Out out(ep);
Audio::dma_notifier(out.dma_notifier());
static Audio_out::Root audio_root(ep, *env()->heap(), out.data_avail());
PINF("--- BSD Audio_out driver started ---");
env()->parent()->announce(ep.manage(audio_root));
}
}
};
namespace Server {
char const *name() { return "audio_drv_ep"; }
size_t stack_size() { return 4*1024*sizeof(long); }
void construct(Entrypoint &ep) { static Main server(ep); }
}

View File

@ -0,0 +1,5 @@
TARGET = audio_out_drv
REQUIRES = x86
SRC_CC = main.cc
LIBS = audio base config server
INC_DIR += $(REP_DIR)/include

View File

@ -0,0 +1,51 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-16
*/
/*
* Copyright (C) 2014-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 _BSD_H_
#define _BSD_H_
/* Genode includes */
#include <base/cache.h>
#include <irq_session/capability.h>
#include <os/server.h>
/* local includes */
#include <scheduler.h>
namespace Bsd {
int probe_drivers();
void irq_init(Server::Entrypoint &ep);
void timer_init(Server::Entrypoint &ep);
void update_time();
/**************************
** Bus_driver interface **
**************************/
struct Bus_driver
{
virtual Genode::Irq_session_capability irq_session() = 0;
virtual Genode::addr_t alloc(Genode::size_t size, int align) = 0;
virtual void free(Genode::addr_t virt, Genode::size_t size) = 0;
virtual Genode::addr_t virt_to_phys(Genode::addr_t virt) = 0;
virtual Genode::addr_t phys_to_virt(Genode::addr_t phys) = 0;
};
}
#endif /* _BSD_H_ */

View File

@ -0,0 +1,141 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-09
*/
/*
* Copyright (C) 2014-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 <bsd_emul.h>
#include <sys/device.h>
#include <dev/audio_if.h>
/******************
** sys/kernel.h **
******************/
int hz = HZ;
/* ioconf.c */
extern struct cfdriver audio_cd;
extern struct cfattach audio_ca;
extern struct cfdriver azalia_cd;
extern struct cfattach azalia_ca;
extern struct cfdriver eap_cd;
extern struct cfattach eap_ca;
/* original value */
enum { PCI_BUS_PARENT = 56 };
short pv[] = { -1, PCI_BUS_PARENT };
struct cfdata cfdata[] = {
{&audio_ca, &audio_cd, 0, 0, 0, 0, pv+0, 0, 0},
{&azalia_ca, &azalia_cd, 0, 0, 0, 0, pv+1, 0, 0},
{&eap_ca, &eap_cd, 0, 0, 0, 0, pv+1, 0, 0},
};
int enodev(void) { return ENODEV; }
/* global character device switch table */
struct cdevsw cdevsw[] = {
/* cdev_audio_init */
{
audioopen,
audioclose,
audioread,
audiowrite,
audioioctl,
(int (*)(struct tty*, int)) enodev,
0,
audiopoll,
audiommap,
0,
0,
audiokqfilter,
},
};
/* needed by dev/audio.c:522 */
int nchrdev = sizeof(cdevsw) / sizeof(struct cdevsw);
struct device pci_bus = { DV_DULL, { 0, 0 }, 0, 0, { 'p', 'c', 'i', '0'}, 0, 0, 0 };
/**
* This function is our little helper that matches and attaches
* the driver to the device.
*/
int probe_cfdata(struct pci_attach_args *pa)
{
size_t ncd = sizeof(cfdata) / sizeof(struct cfdata);
size_t i;
for (i = 0; i < ncd; i++) {
struct cfdata *cf = &cfdata[i];
struct cfdriver *cd = cf->cf_driver;
if (*cf->cf_parents != PCI_BUS_PARENT)
continue;
struct cfattach *ca = cf->cf_attach;
if (!ca->ca_match)
continue;
int rv = ca->ca_match(&pci_bus, 0, pa);
if (rv) {
struct device *dev = (struct device *) malloc(ca->ca_devsize,
M_DEVBUF, M_NOWAIT|M_ZERO);
snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", cd->cd_name,
dev->dv_unit);
printf("%s at %s\n", dev->dv_xname, pci_bus.dv_xname);
ca->ca_attach(&pci_bus, dev, pa);
return 1;
}
}
return 0;
}
struct device *config_found_sm(struct device *parent, void *aux, cfprint_t print,
cfmatch_t submatch)
{
struct cfdata *cf = &cfdata[0];
struct cfattach *ca = cf->cf_attach;
struct cfdriver *cd = cf->cf_driver;
int rv = ca->ca_match(parent, NULL, aux);
if (rv) {
struct device *dev = (struct device *) malloc(ca->ca_devsize, M_DEVBUF,
M_NOWAIT|M_ZERO);
snprintf(dev->dv_xname, sizeof(dev->dv_xname), "%s%d", cd->cd_name,
dev->dv_unit);
printf("%s at %s\n", dev->dv_xname, parent->dv_xname);
ca->ca_attach(parent, dev, aux);
audio_cd.cd_ndevs = 1;
audio_cd.cd_devs = malloc(sizeof(void*), 0, 0);
audio_cd.cd_devs[0] = dev;
return dev;
}
return 0;
}

View File

@ -0,0 +1,564 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-16
*/
/*
* Copyright (C) 2014-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/allocator_avl.h>
#include <base/object_pool.h>
#include <dataspace/client.h>
#include <io_port_session/connection.h>
#include <io_mem_session/connection.h>
#include <pci_session/connection.h>
#include <pci_device/client.h>
/* local includes */
#include "bsd.h"
#include <extern_c_begin.h>
# include <bsd_emul.h>
# include <dev/pci/pcidevs.h>
#include <extern_c_end.h>
extern "C" int probe_cfdata(struct pci_attach_args *);
namespace {
class Pci_driver : public Bsd::Bus_driver
{
public:
enum Pci_config { IRQ = 0x3c, CMD = 0x4,
CMD_IO = 0x1, CMD_MEMORY = 0x2, CMD_MASTER = 0x4 };
private:
struct pci_attach_args _pa { 0, 0, 0, 0, 0 };
Pci::Connection _pci;
Pci::Device_capability _cap;
Genode::Io_port_connection *_io_port { nullptr };
/**
* The Dma_region_manager provides memory used for DMA
* and manages its mappings.
*/
struct Dma_region_manager : public Genode::Allocator_avl
{
enum { BACKING_STORE_SIZE = 1024 * 1024 };
Genode::addr_t base;
Genode::addr_t mapped_base;
bool _dma_initialized { false };
Pci_driver &_drv;
Dma_region_manager(Genode::Allocator &alloc, Pci_driver &drv)
: Genode::Allocator_avl(&alloc), _drv(drv) { }
Genode::addr_t alloc(Genode::size_t size, int align)
{
using namespace Genode;
if (!_dma_initialized) {
try {
Ram_dataspace_capability cap = _drv._alloc_dma_memory(BACKING_STORE_SIZE);
mapped_base = (addr_t)env()->rm_session()->attach(cap);
base = Dataspace_client(cap).phys_addr();
Allocator_avl::add_range(mapped_base, BACKING_STORE_SIZE);
} catch (...) {
PERR("alloc DMA memory failed");
return 0;
}
_dma_initialized = true;
}
void *ptr = nullptr;
bool err = Allocator_avl::alloc_aligned(size, &ptr, align).is_error();
return err ? 0 : (addr_t)ptr;
}
void free(Genode::addr_t virt, Genode::size_t size) {
Genode::Allocator_avl::free((void*)virt, size); }
Genode::addr_t virt_to_phys(Genode::addr_t virt) {
return virt - mapped_base + base; }
Genode::addr_t phys_to_virt(Genode::addr_t phys) {
return phys - base + mapped_base; }
} _dma_region_manager;
/**
* Scan pci bus for sound devices
*/
Pci::Device_capability _scan_pci(Pci::Device_capability const &prev)
{
Pci::Device_capability cap;
/* shift values for Pci interface used by Genode */
cap = _pci.next_device(prev, PCI_CLASS_MULTIMEDIA << 16,
PCI_CLASS_MASK << 16);
if (prev.valid())
_pci.release_device(prev);
return cap;
}
/**
* Allocate DMA memory from the PCI driver
*/
Genode::Ram_dataspace_capability _alloc_dma_memory(Genode::size_t size)
{
try {
/* trigger that the device gets assigned to this driver (needed by IOMMUs) */
for (unsigned i = 0; i < 2; i++)
try {
_pci.config_extended(_cap);
break;
} catch (Pci::Device::Quota_exceeded) {
Genode::env()->parent()->upgrade(_pci.cap(), "ram_quota=4096");
}
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%zu", size);
Genode::env()->parent()->upgrade(_pci.cap(), buf);
return _pci.alloc_dma_buffer(size);
} catch (...) { return Genode::Ram_dataspace_capability(); }
}
public:
Pci_driver() : _dma_region_manager(*Genode::env()->heap(), *this) { }
Pci::Device_capability cap() { return _cap; }
Pci::Connection &pci() { return _pci; }
int probe()
{
/*
* We hide ourself in the bus_dma_tag_t as well as
* in the pci_chipset_tag_t field because they are
* used in all pci or bus related functions and are
* our access window, hence.
*/
_pa.pa_dmat = (bus_dma_tag_t)this;
_pa.pa_pc = (pci_chipset_tag_t)this;
int found = 0;
while ((_cap = _scan_pci(_cap)).valid()) {
Pci::Device_client device(_cap);
uint8_t bus, dev, func;
device.bus_address(&bus, &dev, &func);
/* XXX until we get the platform_drv, we blacklist HDMI/DP HDA devices */
if (device.device_id() == PCI_PRODUCT_INTEL_CORE4G_HDA_2) {
PWRN("ignore %u:%u:%u device, Intel Core 4G HDA not supported",
bus, dev, func);
continue;
}
/* we do the shifting to match OpenBSD's assumptions */
_pa.pa_tag = 0x80000000UL | (bus << 16) | (dev << 11) | (func << 8);
_pa.pa_class = device.class_code() << 8;
_pa.pa_id = device.vendor_id() | device.device_id() << 16;
if (probe_cfdata(&_pa)) {
found++;
break;
}
}
return found;
}
/**************************
** Bus_driver interface **
**************************/
Genode::Irq_session_capability irq_session() override {
return Pci::Device_client(_cap).irq(0); }
Genode::addr_t alloc(Genode::size_t size, int align) override {
return _dma_region_manager.alloc(size, align); }
void free(Genode::addr_t virt, Genode::size_t size) override {
_dma_region_manager.free(virt, size); }
Genode::addr_t virt_to_phys(Genode::addr_t virt) override {
return _dma_region_manager.virt_to_phys(virt); }
Genode::addr_t phys_to_virt(Genode::addr_t phys) override {
return _dma_region_manager.phys_to_virt(phys); }
};
/**********************
** Bus space helper **
**********************/
struct Bus_space
{
virtual unsigned read_1(unsigned long address) = 0;
virtual unsigned read_2(unsigned long address) = 0;
virtual unsigned read_4(unsigned long address) = 0;
virtual void write_1(unsigned long address, unsigned char value) = 0;
virtual void write_2(unsigned long address, unsigned short value) = 0;
virtual void write_4(unsigned long address, unsigned int value) = 0;
};
/*********************
** I/O port helper **
*********************/
struct Io_port : public Bus_space
{
Genode::Io_port_session_client _io;
Genode::addr_t _base;
Io_port(Genode::addr_t base, Genode::Io_port_session_capability cap)
: _io(cap), _base(base) { }
unsigned read_1(unsigned long address) {
return _io.inb(_base + address); }
unsigned read_2(unsigned long address) {
return _io.inw(_base + address); }
unsigned read_4(unsigned long address) {
return _io.inl(_base + address); }
void write_1(unsigned long address, unsigned char value) {
_io.outb(_base + address, value); }
void write_2(unsigned long address, unsigned short value) {
_io.outw(_base + address, value); }
void write_4(unsigned long address, unsigned int value) {
_io.outl(_base + address, value); }
};
/***********************
** I/O memory helper **
***********************/
struct Io_memory : public Bus_space
{
Genode::Io_mem_session_client _mem;
Genode::Io_mem_dataspace_capability _mem_ds;
Genode::addr_t _vaddr;
Io_memory(Genode::addr_t base, Genode::Io_mem_session_capability cap)
:
_mem(cap),
_mem_ds(_mem.dataspace())
{
if (!_mem_ds.valid())
throw Genode::Exception();
_vaddr = Genode::env()->rm_session()->attach(_mem_ds);
_vaddr |= base & 0xfff;
}
unsigned read_1(unsigned long address) {
return *(volatile unsigned char*)(_vaddr + address); }
unsigned read_2(unsigned long address) {
return *(volatile unsigned short*)(_vaddr + address); }
unsigned read_4(unsigned long address) {
return *(volatile unsigned int*)(_vaddr + address); }
void write_1(unsigned long address, unsigned char value) {
*(volatile unsigned char*)(_vaddr + address) = value; }
void write_2(unsigned long address, unsigned short value) {
*(volatile unsigned short*)(_vaddr + address) = value; }
void write_4(unsigned long address, unsigned int value) {
*(volatile unsigned int*)(_vaddr + address) = value; }
};
} /* anonymous namespace */
int Bsd::probe_drivers()
{
PINF("--- probe drivers ---");
static Pci_driver drv;
return drv.probe();
}
/**********************
** dev/pci/pcivar.h **
**********************/
extern "C" int pci_matchbyid(struct pci_attach_args *pa, const struct pci_matchid *ids, int num)
{
pci_vendor_id_t vid = PCI_VENDOR(pa->pa_id);
pci_product_id_t pid = PCI_PRODUCT(pa->pa_id);
for (int i = 0; i < num; i++) {
if (vid == ids[i].pm_vid && pid == ids[i].pm_pid)
return 1;
}
return 0;
}
extern "C" int pci_mapreg_map(struct pci_attach_args *pa,
int reg, pcireg_t type,
int flags, bus_space_tag_t *tagp,
bus_space_handle_t *handlep, bus_addr_t *basep,
bus_size_t *sizep, bus_size_t maxsize)
{
/* calculate BAR from given register */
int r = (reg - 0x10) / 4;
Pci_driver *drv = (Pci_driver*)pa->pa_pc;
Pci::Device_capability cap = drv->cap();
Pci::Device_client device(cap);
Pci::Device::Resource res = device.resource(r);
switch (res.type()) {
case Pci::Device::Resource::IO:
{
Io_port *iop = new (Genode::env()->heap())
Io_port(res.base(), device.io_port(r));
*tagp = (Genode::addr_t) iop;
break;
}
case Pci::Device::Resource::MEMORY:
{
Io_memory *iom = new (Genode::env()->heap())
Io_memory(res.base(), device.io_mem(r));
*tagp = (Genode::addr_t) iom;
break;
}
case Pci::Device::Resource::INVALID:
{
PERR("PCI resource type invalid");
return -1;
}
}
*handlep = res.base();
if (basep != 0)
*basep = res.base();
if (sizep != 0)
*sizep = maxsize > 0 && res.size() > maxsize ? maxsize : res.size();
/* enable bus master and I/O or memory bits */
uint16_t cmd = device.config_read(Pci_driver::CMD, Pci::Device::ACCESS_16BIT);
if (res.type() == Pci::Device::Resource::IO) {
cmd &= ~Pci_driver:: CMD_MEMORY;
cmd |= Pci_driver::CMD_IO;
} else {
cmd &= ~Pci_driver::CMD_IO;
cmd |= Pci_driver::CMD_MEMORY;
}
cmd |= Pci_driver::CMD_MASTER;
device.config_write(Pci_driver::CMD, cmd, Pci::Device::ACCESS_16BIT);
return 0;
}
/***************************
** machine/pci_machdep.h **
***************************/
extern "C" pcireg_t pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
{
Pci_driver *drv = (Pci_driver *)pc;
Pci::Device_client device(drv->cap());
return device.config_read(reg, Pci::Device::ACCESS_32BIT);
}
extern "C" void pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg,
pcireg_t val)
{
Pci_driver *drv = (Pci_driver *)pc;
Pci::Device_client device(drv->cap());
return device.config_write(reg, val, Pci::Device::ACCESS_32BIT);
}
/*******************
** machine/bus.h **
*******************/
extern "C" u_int8_t bus_space_read_1(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset)
{
Bus_space *bus = (Bus_space*)space;
return bus->read_1(offset);
}
extern "C" u_int16_t bus_space_read_2(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset)
{
Bus_space *bus = (Bus_space*)space;
return bus->read_2(offset);
}
extern "C" u_int32_t bus_space_read_4(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset)
{
Bus_space *bus = (Bus_space*)space;
return bus->read_4(offset);
}
extern "C" void bus_space_write_1(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset, u_int8_t value)
{
Bus_space *bus = (Bus_space*)space;
bus->write_1(offset, value);
}
extern "C" void bus_space_write_2(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset, u_int16_t value)
{
Bus_space *bus = (Bus_space*)space;
bus->write_2(offset, value);
}
extern "C" void bus_space_write_4(bus_space_tag_t space,
bus_space_handle_t handle,
bus_size_t offset, u_int32_t value)
{
Bus_space *bus = (Bus_space*)space;
bus->write_4(offset, value);
}
extern "C" int bus_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments,
bus_size_t maxsegsz, bus_size_t boundart,
int flags, bus_dmamap_t *dmamp)
{
struct bus_dmamap *map;
map = (struct bus_dmamap*) malloc(sizeof(struct bus_dmamap), M_DEVBUF, M_ZERO);
map->size = size;
map->maxsegsz = maxsegsz;
map->nsegments = nsegments;
*dmamp = map;
return 0;
}
extern "C" void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t map) {
free(map, 0, 0); }
extern "C" int bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf,
bus_size_t buflen, struct proc *p, int flags)
{
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
Genode::addr_t virt = (Genode::addr_t)buf;
dmam->dm_segs[0].ds_addr = drv->virt_to_phys(virt);
return 0;
}
extern "C" void bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t)
{
PDBG("not implemented, called from %p", __builtin_return_address(0));
}
extern "C" int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment,
bus_size_t boundary, bus_dma_segment_t *segs, int nsegs,
int *rsegs, int flags)
{
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
Genode::addr_t virt = drv->alloc(size, Genode::log2(alignment));
if (virt == 0)
return -1;
segs->ds_addr = drv->virt_to_phys(virt);
segs->ds_size = size;
*rsegs = 1;
return 0;
}
extern "C" void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs)
{
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
for (int i = 0; i < nsegs; i++) {
Genode::addr_t phys = (Genode::addr_t)segs[i].ds_addr;
Genode::addr_t virt = drv->phys_to_virt(phys);
drv->free(virt, segs[i].ds_size);
}
}
extern "C" int bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs,
size_t size, caddr_t *kvap, int flags)
{
if (nsegs > 1) {
PERR("%s: cannot map more than 1 segment", __func__);
return -1;
}
Bsd::Bus_driver *drv = (Bsd::Bus_driver *)tag;
Genode::addr_t phys = (Genode::addr_t)segs[0].ds_addr;
Genode::addr_t virt = drv->phys_to_virt(phys);
*kvap = (caddr_t)virt;
return 0;
}
extern "C" void bus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t) { }
extern "C" paddr_t bus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *,
int, off_t, int, int)
{
PDBG("not implemented, called from %p", __builtin_return_address(0));
return 0;
}

View File

@ -0,0 +1,168 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-09
*/
/*
* Copyright (C) 2014-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/signal.h> /* FIXME needed by audio_out_session.h */
#include <audio_out_session/audio_out_session.h>
#include <os/server.h>
/* local includes */
#include <audio/audio.h>
#include <bsd.h>
#include <extern_c_begin.h>
# include <bsd_emul.h>
# include <sys/device.h>
# include <sys/audioio.h>
#include <extern_c_end.h>
static bool const verbose = false;
extern struct cfdriver audio_cd;
static dev_t const adev = 0x80; /* audio0 128 */
static dev_t const mdev = 0x10; /* mixer0 16 */
static bool adev_usuable = false;
static bool drv_loaded() { return audio_cd.cd_ndevs > 0 ? true : false; }
static void dump_prinfo(struct audio_prinfo *prinfo)
{
struct audio_info ai;
int err = audioioctl(adev, AUDIO_GETINFO, (char*)&ai, 0, 0);
if (err) {
PERR("could not gather play information");
return;
}
PLOG("--- play information ---");
PLOG("sample_rate: %u", prinfo->sample_rate);
PLOG("channels: %u", prinfo->channels);
PLOG("precision: %u", prinfo->precision);
PLOG("bps: %u", prinfo->bps);
PLOG("encoding: %u", prinfo->encoding);
PLOG("gain: %u", prinfo->gain);
PLOG("port: %u", prinfo->port);
PLOG("seek: %u", prinfo->seek);
PLOG("avail_ports: %u", prinfo->avail_ports);
PLOG("buffer_size: %u", prinfo->buffer_size);
PLOG("block_size: %u", prinfo->block_size);
/* current state of the device */
PLOG("samples: %u", prinfo->samples);
PLOG("eof: %u", prinfo->eof);
PLOG("pause: %u", prinfo->pause);
PLOG("error: %u", prinfo->error);
PLOG("waiting: %u", prinfo->waiting);
PLOG("balance: %u", prinfo->balance);
PLOG("open: %u", prinfo->open);
PLOG("active: %u", prinfo->active);
}
static bool open_audio_device(dev_t dev)
{
if (!drv_loaded())
return false;
int err = audioopen(dev, FWRITE, 0 /* ifmt */, 0 /* proc */);
if (err)
return false;
return true;
}
static bool configure_audio_device(dev_t dev)
{
struct audio_info ai;
int err = audioioctl(adev, AUDIO_GETINFO, (char*)&ai, 0, 0);
if (err)
return false;
using namespace Audio;
/* configure the device according to our Audio_session settings */
ai.play.sample_rate = Audio_out::SAMPLE_RATE;
ai.play.channels = MAX_CHANNELS;
ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
ai.play.block_size = MAX_CHANNELS * sizeof(short) * Audio_out::PERIOD;
err = audioioctl(adev, AUDIO_SETINFO, (char*)&ai, 0, 0);
if (err)
return false;
if (verbose)
dump_prinfo(&ai.play);
return true;
}
static void run_bsd(void *)
{
if (!Bsd::probe_drivers()) {
PERR("no supported sound card found");
Genode::sleep_forever();
}
if (!open_audio_device(adev)) {
PERR("could not initialize sound card");
Genode::sleep_forever();
}
adev_usuable = configure_audio_device(adev);
while (true) {
Bsd::scheduler().current()->block_and_schedule();
}
}
static Bsd::Task *_task;
/*****************************
** private Audio namespace **
*****************************/
void Audio::init_driver(Server::Entrypoint &ep)
{
Bsd::irq_init(ep);
Bsd::timer_init(ep);
static Bsd::Task task_bsd(run_bsd, nullptr, "bsd",
Bsd::Task::PRIORITY_0, Bsd::scheduler(),
2048 * sizeof(long));
_task = &task_bsd;
Bsd::scheduler().schedule();
}
bool Audio::driver_active()
{
return drv_loaded() && adev_usuable;
}
int Audio::play(short *data, Genode::size_t size)
{
struct uio uio = { 0, size, data, size };
return audiowrite(adev, &uio, IO_NDELAY);
}

View File

@ -0,0 +1,67 @@
/**
* \brief Dummy functions
* \author Josef Soentgen
* \date 2014-11-13
*/
/*
* Copyright (C) 2014-2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
extern "C" {
typedef long DUMMY;
enum {
SHOW_DUMMY = 0,
SHOW_SKIP = 0,
SHOW_RET = 0,
};
#define DUMMY(retval, name) \
DUMMY name(void) { \
if (SHOW_DUMMY) \
PDBG( #name " called (from %p) not implemented", __builtin_return_address(0)); \
return retval; \
}
#define DUMMY_SKIP(retval, name) \
DUMMY name(void) { \
if (SHOW_SKIP) \
PLOG( #name " called (from %p) skipped", __builtin_return_address(0)); \
return retval; \
}
#define DUMMY_RET(retval, name) \
DUMMY name(void) { \
if (SHOW_RET) \
PWRN( #name " called (from %p) return %d", __builtin_return_address(0), retval); \
return retval; \
}
DUMMY_RET(1, pci_intr_map_msi) /* do not support MSI API */
DUMMY_RET(0, pci_intr_string)
DUMMY(0, bus_space_unmap)
DUMMY(0, config_activate_children)
DUMMY(0, config_deactivate)
DUMMY(0, config_detach)
DUMMY(0, config_detach_children)
DUMMY(0, cpu_info_primary)
DUMMY(0, pci_findvendor)
DUMMY(0, pci_intr_disestablish)
DUMMY(0, pci_set_powerstate)
DUMMY(0, psignal)
DUMMY(0, selrecord)
DUMMY(0, selwakeup)
DUMMY(0, timeout_add_msec)
DUMMY(0, timeout_del)
DUMMY(0, timeout_set)
DUMMY(0, tsleep)
DUMMY(0, vdevgone)
} /* extern "C" */

View File

@ -0,0 +1,670 @@
/*
* \brief Emulation of the OpenBSD kernel API
* \author Josef Soentgen
* \date 2014-11-09
*
* The content of this file, in particular data structures, is partially
* derived from OpenBSD-internal headers.
*/
/*
* Copyright (C) 2014-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 _BSD_EMUL_H_
#define _BSD_EMUL_H_
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*****************
** sys/types.h **
*****************/
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
typedef unsigned int uint;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
typedef __SIZE_TYPE__ size_t;
typedef signed long ssize_t;
typedef char * caddr_t;
typedef unsigned long paddr_t;
typedef signed int dev_t;
typedef signed long long off_t;
#define minor(x) ((int32_t)((x) & 0xff) | (((x) & 0xffff0000) >> 8))
/*****************
** sys/errno.h **
*****************/
enum {
EIO = 5,
ENXIO = 6,
ENOMEM = 12,
EACCES = 13,
EBUSY = 16,
ENODEV = 19,
EINVAL = 22,
ENOTTY = 25,
EAGAIN = 35,
EWOULDBLOCK = EAGAIN,
ETIMEDOUT = 60,
};
/******************
** sys/signal.h **
******************/
enum {
SIGIO = 23,
};
/******************
** sys/malloc.h **
******************/
enum {
/* malloc flags */
M_WAITOK = 0x01,
M_NOWAIT = 0x02,
M_ZERO = 0x08,
/* types of memory */
M_DEVBUF = 2,
};
void *malloc(size_t, int, int);
void *mallocarray(size_t, size_t, int, int);
void free(void *, int, size_t);
/*****************
** sys/param.h **
*****************/
enum {
PZERO = 22,
PWAIT = 32,
PCATCH = 0x100,
};
#ifdef __cplusplus
#define NULL 0
#else
#define NULL (void*)0
#endif /* __cplusplus */
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
/******************
** sys/kernel.h **
******************/
enum { HZ = 100 };
extern int hz;
/*****************
** sys/cdefs.h **
*****************/
#define __packed __attribute((__packed__))
/****************
** sys/proc.h **
****************/
struct proc { };
/****************
** sys/task.h **
****************/
struct task { };
/***************
** sys/uio.h **
***************/
struct uio
{
off_t uio_offset;
size_t uio_resid;
/* emul specific fields */
void *buf;
size_t buflen;
};
/*****************
** sys/event.h **
*****************/
enum {
EVFILT_READ = -1,
EVFILT_WRITE = -2,
};
struct kevent
{
short filter;
};
#include <sys/queue.h>
struct knote;
SLIST_HEAD(klist, knote);
struct filterops
{
int f_isfd;
int (*f_attach)(struct knote*);
void (*f_detach)(struct knote*);
int (*f_event)(struct knote*, long);
};
struct knote
{
SLIST_ENTRY(knote) kn_selnext;
struct kevent kn_kevent;
#define kn_filter kn_kevent.filter
const struct filterops *kn_fop;
void *kn_hook;
};
/*******************
** sys/selinfo.h **
*******************/
struct selinfo
{
struct klist si_note;
};
void selrecord(struct proc *selector, struct selinfo *);
void selwakeup(struct selinfo *);
/*******************
** machine/cpu.h **
*******************/
struct cpu_info { };
extern struct cpu_info cpu_info_primary;
#define curcpu() (&cpu_info_primary)
/*********************
** machine/mutex.h **
*********************/
#define MUTEX_INITIALIZER(ipl) { 0, (ipl), 0, NULL }
#define MUTEX_ASSERT_UNLOCK(mtx) do { \
if ((mtx)->mtx_owner != curcpu()) \
panic("mutex %p not held in %s\n", (mtx), __func__); \
} while (0)
#define MUTEX_ASSERT_LOCKED(mtx) do { \
if ((mtx)->mtx_owner != curcpu()) \
panic("mutex %p not held in %s\n", (mtx), __func__); \
} while (0)
#define MUTEX_ASSERT_UNLOCKED(mtx) do { \
if ((mtx)->mtx_owner == curcpu()) \
panic("mutex %p held in %s\n", (mtx), __func__); \
} while (0)
struct mutex
{
volatile int mtx_lock;
int mtx_wantipl; /* interrupt priority level */
int mtx_oldipl;
void *mtx_owner;
};
/*****************
** sys/mutex.h **
*****************/
void mtx_enter(struct mutex *);
void mtx_leave(struct mutex *);
/*****************
** sys/systm.h **
*****************/
extern int nchrdev;
int enodev(void);
int printf(const char *, ...);
int snprintf(char *buf, size_t, const char *, ...);
void panic(const char *, ...);
void bcopy(const void *, void *, size_t);
void bzero(void *, size_t);
void *memcpy(void *, const void *, size_t);
void *memset(void *, int, size_t);
void wakeup(const volatile void*);
int tsleep(const volatile void *, int, const char *, int);
int msleep(const volatile void *, struct mutex *, int, const char*, int);
int uiomovei(void *, int, struct uio *);
/*******************
** lib/libkern.h **
*******************/
static inline u_int max(u_int a, u_int b) { return (a > b ? a : b); }
static inline u_int min(u_int a, u_int b) { return (a < b ? a : b); }
size_t strlcpy(char *, const char *, size_t);
int strcmp(const char *, const char *);
/*********************
** machine/param.h **
*********************/
#define DELAY(x) delay(x)
void delay(int);
/*******************************
** machine/intrdefs.h **
*******************************/
enum {
IPL_AUDIO = 8,
IPL_MPSAFE = 0x100,
};
/*****************
** sys/fcntl.h **
*****************/
enum {
FREAD = 0x0001,
FWRITE = 0x0002,
};
/****************
** sys/poll.h **
****************/
enum {
POLLIN = 0x0001,
POLLOUT = 0x0004,
POLLERR = 0x0008,
POLLRDNORM = 0x0040,
POLLWRNORM = POLLOUT,
};
/*****************
** sys/vnode.h **
*****************/
enum vtype {
VCHR,
};
enum {
IO_NDELAY = 0x10,
};
void vdevgone(int, int, int, enum vtype);
/******************
** sys/ioccom.h **
******************/
#define IOCPARM_MASK 0x1fff
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#define IOCGROUP(x) (((x) >> 8) & 0xff)
#define IOC_VOID (unsigned long)0x20000000
#define IOC_OUT (unsigned long)0x40000000
#define IOC_IN (unsigned long)0x80000000
#define IOC_INOUT (IOC_IN|IOC_OUT)
#define _IOC(inout,group,num,len) \
(inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0)
#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
/*****************
** sys/filio.h **
*****************/
#define FIONBIO _IOW('f', 126, int)
#define FIOASYNC _IOW('f', 125, int)
/***************
** sys/tty.h **
***************/
struct tty { };
/****************
** sys/conf.h **
****************/
struct cdevsw
{
int (*d_open)(dev_t dev, int oflags, int devtype, struct proc *p);
int (*d_close)(dev_t dev, int fflag, int devtype, struct proc *);
int (*d_read)(dev_t dev, struct uio *uio, int ioflag);
int (*d_write)(dev_t dev, struct uio *uio, int ioflag);
int (*d_ioctl)(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p);
int (*d_stop)(struct tty *tp, int rw);
struct tty *(*d_tty)(dev_t dev);
int (*d_poll)(dev_t dev, int events, struct proc *p);
paddr_t (*d_mmap)(dev_t, off_t, int);
u_int d_type;
u_int d_flags;
int (*d_kqfilter)(dev_t dev, struct knote *kn);
};
extern struct cdevsw cdevsw[];
/**
* Normally these functions are defined by macro magic but we declare
* them verbatim.
*/
int audioopen(dev_t, int, int, struct proc *);
int audioclose(dev_t, int, int, struct proc *);
int audioread(dev_t, struct uio *, int);
int audiowrite(dev_t, struct uio *, int);
int audioioctl(dev_t, u_long, caddr_t, int, struct proc *);
int audiostop(struct tty *, int);
struct tty *audiotty(dev_t);
int audiopoll(dev_t, int, struct proc *);
paddr_t audiommap(dev_t, off_t, int);
int audiokqfilter(dev_t, struct knote *);
#define NMIDI 0
/******************
** sys/select.h **
******************/
enum {
NBBY = 8, /* num of bits in byte */
};
/*********************
** sys/singalvar.h **
*********************/
void psignal(struct proc *p, int sig);
/******************
** sys/rndvar.h **
******************/
#define add_audio_randomness(d)
/*******************
** machine/bus.h **
*******************/
typedef u_long bus_addr_t;
typedef u_long bus_size_t;
typedef u_long bus_space_handle_t;
struct bus_dma_segment
{
bus_addr_t ds_addr;
/* emul specific fields */
bus_size_t ds_size;
};
typedef struct bus_dma_segment bus_dma_segment_t;
typedef struct bus_dmamap* bus_dmamap_t;
struct bus_dmamap
{
bus_dma_segment_t dm_segs[1];
/* emul specific fields */
bus_size_t size;
bus_size_t maxsegsz;
int nsegments;
};
typedef struct bus_dma_tag *bus_dma_tag_t;
struct bus_dma_tag
{
void *_cookie; /* cookie used in the guts */
/*
* DMA mapping methods.
*/
int (*_dmamap_create)(bus_dma_tag_t, bus_size_t, int,
bus_size_t, bus_size_t, int, bus_dmamap_t *);
void (*_dmamap_destroy)(bus_dma_tag_t, bus_dmamap_t);
int (*_dmamap_load)(bus_dma_tag_t, bus_dmamap_t, void *,
bus_size_t, struct proc *, int);
void (*_dmamap_unload)(bus_dma_tag_t, bus_dmamap_t);
/*
* DMA memory utility functions.
*/
int (*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t,
bus_size_t, bus_dma_segment_t *, int, int *, int);
void (*_dmamem_free)(bus_dma_tag_t, bus_dma_segment_t *, int);
int (*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *,
int, size_t, caddr_t *, int);
void (*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t);
paddr_t (*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
int, off_t, int, int);
};
int bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, bus_size_t, int, bus_dmamap_t *);
void bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t);
int bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, struct proc *, int);
void bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t);
int bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int);
void bus_dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int);
int bus_dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, int, size_t, caddr_t *, int);
void bus_dmamem_unmap(bus_dma_tag_t, caddr_t, size_t);
paddr_t bus_dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, int, off_t, int, int);
typedef u_long bus_space_tag_t;
void bus_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t);
u_int8_t bus_space_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t);
u_int16_t bus_space_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t);
u_int32_t bus_space_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t);
void bus_space_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int8_t);
void bus_space_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int16_t);
void bus_space_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
enum {
BUS_DMA_WAITOK = 0x0000,
BUS_DMA_NOWAIT = 0x0001,
BUS_DMA_COHERENT = 0x0004,
};
/**********************
** dev/pci/pcireg.h **
**********************/
typedef u_int16_t pci_vendor_id_t;
typedef u_int16_t pci_product_id_t;
#define PCI_VENDOR_SHIFT 0
#define PCI_VENDOR_MASK 0xffff
#define PCI_VENDOR(id) \
(((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK)
#define PCI_PRODUCT_SHIFT 16
#define PCI_PRODUCT_MASK 0xffff
#define PCI_PRODUCT(id) \
(((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK)
#define PCI_CLASS_SHIFT 24
#define PCI_CLASS_MASK 0xff
#define PCI_CLASS(cr) \
(((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK)
#define PCI_SUBCLASS_SHIFT 16
#define PCI_SUBCLASS_MASK 0xff
#define PCI_SUBCLASS(cr) \
(((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK)
#define PCI_REVISION_SHIFT 0
#define PCI_REVISION_MASK 0xff
#define PCI_REVISION(cr) \
(((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK)
enum {
PCI_COMMAND_IO_ENABLE = 0x00000001,
PCI_COMMAND_STATUS_REG = 0x04,
PCI_COMMAND_BACKTOBACK_ENABLE = 0x00000200,
PCI_CLASS_MULTIMEDIA = 0x04,
PCI_SUBCLASS_MULTIMEDIA_HDAUDIO = 0x03,
PCI_MAPREG_TYPE_MASK = 0x00000001,
PCI_MAPREG_MEM_TYPE_MASK = 0x00000006,
PCI_MAPREG_TYPE_IO = 0x00000001,
PCI_MAPREG_TYPE_MEM = 0x00000000,
PCI_SUBSYS_ID_REG = 0x2c,
PCI_PMCSR_STATE_D0 = 0x0000,
};
#define PCI_MAPREG_IO_ADDR(mr) \
((mr) & PCI_MAPREG_IO_ADDR_MASK)
#define PCI_MAPREG_IO_SIZE(mr) \
(PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr))
#define PCI_MAPREG_IO_ADDR_MASK 0xfffffffe
/**********************
** dev/pci/pcivar.h **
**********************/
/* actually from pci_machdep.h */
typedef void *pci_chipset_tag_t;
typedef uint32_t pcitag_t;
typedef uint32_t pcireg_t;
struct pci_attach_args
{
bus_dma_tag_t pa_dmat;
pci_chipset_tag_t pa_pc;
pcitag_t pa_tag;
pcireg_t pa_id;
pcireg_t pa_class;
};
struct pci_matchid {
pci_vendor_id_t pm_vid;
pci_product_id_t pm_pid;
};
int pci_matchbyid(struct pci_attach_args *, const struct pci_matchid *, int);
int pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int);
int pci_mapreg_map(struct pci_attach_args *, int, pcireg_t, int,
bus_space_tag_t *, bus_space_handle_t *, bus_addr_t *,
bus_size_t *, bus_size_t);
const char *pci_findvendor(pcireg_t);
/***************************
** machine/pci_machdep.h **
***************************/
struct pci_intr_handle { unsigned irq; };
typedef struct pci_intr_handle pci_intr_handle_t;
int pci_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *);
int pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
const char *pci_intr_string(pci_chipset_tag_t, pci_intr_handle_t);
void *pci_intr_establish(pci_chipset_tag_t, pci_intr_handle_t,
int, int (*)(void *), void *, const char *);
void pci_intr_disestablish(pci_chipset_tag_t, void *);
pcireg_t pci_conf_read(pci_chipset_tag_t, pcitag_t, int);
void pci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
/*******************
** sys/timeout.h **
*******************/
struct timeout { };
void timeout_set(struct timeout *, void (*)(void *), void *);
int timeout_add_msec(struct timeout *, int);
int timeout_del(struct timeout *);
/******************
** sys/endian.h **
******************/
#define htole32(x) ((uint32_t)(x))
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _BSD_EMUL_H_ */

View File

@ -0,0 +1,26 @@
/*
* \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.
*/
#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_

View File

@ -0,0 +1,20 @@
/*
* \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.
*/
#undef new
#undef class
#undef private
#pragma GCC diagnostic pop
} /* extern "C" */

View File

@ -0,0 +1,99 @@
/*
* \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 _LIST_H_
#define _LIST_H_
#include <util/list.h>
namespace Bsd {
template <typename> class List;
template <typename> class List_element;
}
template <typename LT>
class Bsd::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;
}
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 Bsd::List_element : public Bsd::List<List_element<T> >::Element
{
private:
T *_object;
public:
List_element(T *object) : _object(object) { }
T *object() const { return _object; }
};
#endif /* _LIST_H_ */

View File

@ -0,0 +1,179 @@
/*
* \brief User-level scheduling
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Christian Helmuth
* \date 2012-04-25
*/
/*
* Copyright (C) 2012-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 _SCHEDULER_H_
#define _SCHEDULER_H_
/* Genode includes */
#include <base/env.h>
#include <base/lock.h>
#include <base/sleep.h>
/* local includes */
#include <list.h>
#include <platform/platform.h>
namespace Bsd {
class Scheduler;
class Task;
Scheduler &scheduler();
};
/**
* Allows pseudo-parallel execution of functions
*/
class Bsd::Task : public Bsd::List<Bsd::Task>::Element
{
public:
enum Priority { PRIORITY_0, PRIORITY_1, PRIORITY_2, PRIORITY_3 };
/**
* Runtime state
*
* INIT
* |
* [run]
* v
* BLOCKED <--[block/unblock]--> RUNNING
*/
enum State { STATE_INIT, STATE_RUNNING, STATE_BLOCKED };
private:
State _state = STATE_INIT;
/* sub-classes may overwrite the runnable condition */
virtual bool _runnable() const;
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 */
int const _stack_size; /* size of the stack of task */
public:
Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler, int stack_size);
virtual ~Task();
State state() const { return _state; }
Priority priority() const { return _priority; }
/*******************************
** Runtime state transitions **
*******************************/
void block()
{
if (_state == STATE_RUNNING) {
_state = STATE_BLOCKED;
}
}
void unblock()
{
if (_state == STATE_BLOCKED) {
_state = STATE_RUNNING;
}
}
/**
* Run task until next preemption point
*
* \return true if run, false if not runnable
*/
bool run();
/**
* Request scheduling (of other tasks)
*
* Note, this task may not be blocked when calling schedule() depending
* on the use case.
*/
void schedule();
/**
* 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; }
};
/**
* Scheduler
*/
class Bsd::Scheduler
{
private:
Bsd::List<Bsd::Task> _present_list;
Genode::Lock _present_list_mutex;
Task *_current = nullptr; /* currently scheduled task */
bool _run_task(Task *);
public:
Scheduler();
~Scheduler();
/**
* Return currently scheduled task
*/
Task *current();
/**
* Add new task to the present list
*/
void add(Task *);
/**
* Schedule all present tasks
*
* Returns if no task is runnable.
*/
void schedule();
/**
* Log current state of tasks in present list (debug)
*
* Log lines are prefixed with 'prefix'
*/
void log_state(char const *prefix);
};
#endif /* _SCHEDULER_H_ */

View File

@ -0,0 +1,43 @@
/**
* \brief Platform specific code
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2012-06-10
*/
/*
* Copyright (C) 2012-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 _X86_32__PLATFORM_H_
#define _X86_32__PLATFORM_H_
#ifdef __cplusplus
extern "C" {
#endif
#define _JBLEN 11
typedef struct _jmp_buf { long _jb[_JBLEN + 1]; } jmp_buf[1];
void _longjmp(jmp_buf, int);
int _setjmp(jmp_buf);
#ifdef __cplusplus
}
#endif
static inline
void platform_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 /* _X86_32__PLATFORM_H_ */

View File

@ -0,0 +1,44 @@
/**
* \brief Platform specific code
* \author Sebastian Sumpf
* \author Alexander Boettcher
* \author Josef Soentgen
* \date 2012-06-10
*/
/*
* Copyright (C) 2012-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 _X86_64__PLATFORM_H_
#define _X86_64__PLATFORM_H_
#ifdef __cplusplus
extern "C" {
#endif
#define _JBLEN 12
typedef struct _jmp_buf { long _jb[_JBLEN]; } jmp_buf[1];
void _longjmp(jmp_buf, int);
int _setjmp(jmp_buf);
#ifdef __cplusplus
}
#endif
static inline
void platform_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 /* _X86_64__PLATFORM_H_ */

View File

@ -0,0 +1,172 @@
/*
* \brief Signal context for IRQ's
* \author Josef Soentgen
* \date 2014-10-14
*/
/*
* Copyright (C) 2014-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/thread.h>
#include <base/tslab.h>
#include <timer_session/connection.h>
#include <irq_session/connection.h>
/* local includes */
#include <audio/audio.h>
#include <bsd.h>
#include <extern_c_begin.h>
# include <bsd_emul.h>
#include <extern_c_end.h>
namespace Bsd {
class Irq;
}
static void run_irq(void *args);
static Genode::Signal_context_capability _dma_notifier_cap;
void Audio::dma_notifier(Genode::Signal_context_capability cap) {
_dma_notifier_cap = cap; }
class Bsd::Irq
{
public:
typedef int (*intrh_t)(void*);
/**
* Context encapsulates the handling of an IRQ
*/
class Context
{
private:
enum { STACK_SIZE = 1024 * sizeof(long) };
Bsd::Task _task;
Genode::Irq_session_client _irq;
Genode::Signal_rpc_member<Context> _dispatcher;
intrh_t _intrh;
void *_intarg;
/**
* Signal handler
*/
void _handle(unsigned)
{
_task.unblock();
Bsd::scheduler().schedule();
}
public:
/**
* Constructor
*/
Context(Server::Entrypoint &ep,
Genode::Irq_session_capability cap,
intrh_t intrh, void *intarg)
:
_task(run_irq, this, "irq", Bsd::Task::PRIORITY_3,
Bsd::scheduler(), STACK_SIZE),
_irq(cap),
_dispatcher(ep, *this, &Context::_handle),
_intrh(intrh), _intarg(intarg)
{
_irq.sigh(_dispatcher);
_irq.ack_irq();
}
/**
* Handle IRQ
*/
void handle_irq()
{
_intrh(_intarg);
_irq.ack_irq();
/*
* Notify the frontend when a block from the DMA
* was played.
*/
if (_dma_notifier_cap.valid())
Genode::Signal_transmitter(_dma_notifier_cap).submit();
}
};
private:
Genode::Allocator &_alloc;
Server::Entrypoint &_ep;
Context *_ctx;
public:
/**
* Constructor
*/
Irq(Genode::Allocator &alloc, Server::Entrypoint &ep)
: _alloc(alloc), _ep(ep), _ctx(nullptr) { }
/**
* Request an IRQ
*/
void establish_intr(Genode::Irq_session_capability cap, intrh_t intrh, void *intarg)
{
if (_ctx) {
PERR("interrupt already established");
Genode::sleep_forever();
}
_ctx = new (&_alloc) Context(_ep, cap, intrh, intarg);
}
};
static Bsd::Irq *_bsd_irq;
void Bsd::irq_init(Server::Entrypoint &ep)
{
static Bsd::Irq irq_context(*Genode::env()->heap(), ep);
_bsd_irq = &irq_context;
}
static void run_irq(void *args)
{
Bsd::Irq::Context *ctx = static_cast<Bsd::Irq::Context*>(args);
while (true) {
Bsd::scheduler().current()->block_and_schedule();
ctx->handle_irq();
}
}
/**********************
** dev/pci/pcivar.h **
**********************/
extern "C" int pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ih) {
return 0; }
extern "C" void *pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih,
int ipl, int (*intrh)(void *), void *intarg,
const char *intrstr)
{
Bsd::Bus_driver *drv = (Bsd::Bus_driver*)pc;
_bsd_irq->establish_intr(drv->irq_session(), intrh, intarg);
return _bsd_irq;
}

View File

@ -0,0 +1,386 @@
/**
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-16
*/
/*
* Copyright (C) 2014-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/env.h>
#include <base/allocator_avl.h>
#include <base/printf.h>
#include <dataspace/client.h>
#include <rm_session/connection.h>
#include <util/string.h>
/* local includes */
#include "bsd.h"
#include <extern_c_begin.h>
# include <bsd_emul.h>
#include <extern_c_end.h>
static bool const verbose = false;
namespace Bsd {
typedef Genode::addr_t addr_t;
class Slab_backend_alloc;
class Slab_alloc;
class Malloc;
}
/**
* Back-end allocator for Genode's slab allocator
*/
class Bsd::Slab_backend_alloc : public Genode::Allocator,
public Genode::Rm_connection
{
private:
enum {
VM_SIZE = 8 * 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::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 */
Genode::Ram_session &_ram; /* ram session to allocate ds from */
bool _alloc_block()
{
if (_index == ELEMENTS) {
PERR("Slab-backend exhausted!");
return false;
}
try {
_ds_cap[_index] = _ram.alloc(BLOCK_SIZE);
Rm_connection::attach_at(_ds_cap[_index], _index * BLOCK_SIZE, BLOCK_SIZE, 0);
} 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::Ram_session &ram)
:
Rm_connection(0, VM_SIZE),
_index(0), _range(Genode::env()->heap()), _ram(ram)
{
/* reserver attach us, anywere */
_base = Genode::env()->rm_session()->attach(dataspace());
}
addr_t start() const { return _base; }
addr_t end() const { return _base + VM_SIZE - 1; }
/*************************
** Allocator interface **
*************************/
bool alloc(Genode::size_t size, void **out_addr)
{
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, Genode::size_t size) { }
Genode::size_t overhead(Genode::size_t size) const { return 0; }
bool need_size_for_free() const override { return false; }
};
/**
* Slab allocator using our back-end allocator
*/
class Bsd::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
*/
addr_t alloc()
{
addr_t result;
return (Slab::alloc(slab_size(), (void **)&result) ? result : 0);
}
};
/**
* Memory interface
*/
class Bsd::Malloc
{
private:
enum {
SLAB_START_LOG2 = 5, /* 32 B */
SLAB_STOP_LOG2 = 17, /* 64 KiB */
NUM_SLABS = (SLAB_STOP_LOG2 - SLAB_START_LOG2) + 1,
};
typedef Genode::addr_t addr_t;
typedef Bsd::Slab_alloc Slab_alloc;
typedef Bsd::Slab_backend_alloc Slab_backend_alloc;
Slab_backend_alloc &_back_allocator;
Slab_alloc *_allocator[NUM_SLABS];
addr_t _start;
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
*/
Genode::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)
:
_back_allocator(alloc), _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, _back_allocator);
}
/**
* Alloc in slabs
*/
void *alloc(Genode::size_t size, int align = 0)
{
using namespace Genode;
/* save requested size */
Genode::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", 1U << msb, size);
return 0;
}
addr_t addr = _allocator[msb - SLAB_START_LOG2]->alloc();
if (!addr) {
PERR("Failed to get slab for %u", 1U << 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);
}
return (addr_t *)addr;
}
void free(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
unsigned nr = _slab_index(&addr);
/* we need to decrease addr by 2, orig_size and index come first */
_allocator[nr]->free((void *)(addr - 2));
}
Genode::size_t size(void const *a)
{
using namespace Genode;
addr_t *addr = (addr_t *)a;
return _get_orig_size(&addr);
}
bool inside(addr_t const addr) const { return (addr > _start) && (addr <= _end); }
};
static Bsd::Malloc& malloc_backend()
{
static Bsd::Slab_backend_alloc sb(*Genode::env()->ram_session());
static Bsd::Malloc m(sb);
return m;
}
/**********************
** Memory allocation *
**********************/
extern "C" void *malloc(size_t size, int type, int flags)
{
void *addr = malloc_backend().alloc(size);
if (flags & M_ZERO)
Genode::memset(addr, 0, size);
return addr;
}
extern "C" void *mallocarray(size_t nmemb, size_t size, int type, int flags)
{
if (size != 0 && nmemb > (~0UL / size))
return 0;
return malloc(nmemb * size, type, flags);
}
extern "C" void free(void *addr, int type, size_t size)
{
if (!addr) return;
if (!malloc_backend().inside((Genode::addr_t)addr)) {
PERR("cannot free unknown memory at %p, called from %p",
addr, __builtin_return_address(0));
return;
}
if (size) {
size_t ssize = malloc_backend().size(addr);
if (ssize != size)
PWRN("size: %zu for %p does not match stored size: %zu",
size, addr, ssize);
}
malloc_backend().free(addr);
}
/*****************
** sys/systm.h **
*****************/
extern "C" void bcopy(const void *src, void *dst, size_t len)
{
/* XXX may overlap */
Genode::memcpy(dst, src, len);
}
extern "C" int uiomovei(void *buf, int n, struct uio *uio)
{
void *dst = buf;
void *src = ((char*)uio->buf) + uio->uio_offset;
size_t len = uio->uio_resid < (size_t)n ? uio->uio_resid : (size_t)n;
Genode::memcpy(dst, src, len);
uio->uio_resid -= len;
uio->uio_offset += len;
return 0;
}

View File

@ -0,0 +1,127 @@
/*
* \brief Audio driver BSD API emulation
* \author Josef Soentgen
* \date 2014-11-09
*/
/*
* Copyright (C) 2014-15 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 <base/sleep.h>
#include <base/snprintf.h>
#include <util/string.h>
/* local includes */
#include <extern_c_begin.h>
#include <bsd_emul.h>
#include <extern_c_end.h>
/* compiler includes */
#include <stdarg.h>
/*******************
** machine/mutex **
*******************/
void mtx_enter(struct mutex *mtx) {
mtx->mtx_owner = curcpu(); }
void mtx_leave(struct mutex *mtx) {
mtx->mtx_owner = nullptr; }
/*****************
** sys/systm.h **
*****************/
extern "C" void panic(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
Genode::sleep_forever();
}
extern "C" int printf(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
Genode::vprintf(fmt, va);
va_end(va);
return 0; /* XXX proper return value */
}
extern "C" int snprintf(char *str, size_t size, const char *format, ...)
{
va_list list;
va_start(list, format);
Genode::String_console sc(str, size);
sc.vprintf(format, list);
va_end(list);
return sc.len();
}
extern "C" int strcmp(const char *s1, const char *s2)
{
return Genode::strcmp(s1, s2);
}
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
extern "C" size_t strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}

View File

@ -0,0 +1,256 @@
/*
* \brief User-level scheduling
* \author Sebastian Sumpf
* \author Josef Soentgen
* \author Christian Helmuth
* \date 2012-04-25
*
* We use a pseudo-thread implementation based on setjmp/longjmp.
*/
/*
* Copyright (C) 2012-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/sleep.h>
/* local includes */
#include <bsd.h>
#include <scheduler.h>
static bool const debugging = false;
static bool const verbose = false;
#define PDBGV(...) do { if (verbose) PDBG(__VA_ARGS__); } while (0)
/**********
** Task **
**********/
bool Bsd::Task::_runnable() const
{
switch (_state) {
case STATE_INIT: return true;
case STATE_RUNNING: return true;
case STATE_BLOCKED: return false;
}
PERR("state %d not handled by switch", _state);
Genode::sleep_forever();
}
bool Bsd::Task::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();
_stack = th->alloc_secondary_stack(_name, _stack_size);
/* switch stack and call '_func(_arg)' */
platform_execute(_stack, (void *)_func, _arg);
} else {
/* restore execution environment */
_longjmp(_env, 1);
}
/* never reached */
PERR("Unexpected return of Task");
Genode::sleep_forever();
}
void Bsd::Task::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);
}
Bsd::Task::Task(void (*func)(void*), void *arg, char const *name,
Priority priority, Scheduler &scheduler, int stack_size)
:
_priority(priority), _scheduler(scheduler),
_func(func), _arg(arg), _name(name), _stack_size(stack_size)
{
scheduler.add(this);
PDBGV("name: '%s' func: %p arg: %p prio: %u t: %p", name, func, arg, priority, this);
}
Bsd::Task::~Task()
{
if (_stack)
Genode::Thread_base::myself()->free_secondary_stack(_stack);
}
/***************
** Scheduler **
***************/
Bsd::Scheduler & Bsd::scheduler()
{
static Bsd::Scheduler inst;
return inst;
}
Bsd::Task *Bsd::Scheduler::current()
{
if (!_current) {
PERR("BUG: _current is zero!");
Genode::sleep_forever();
}
return _current;
}
void Bsd::Scheduler::add(Task *task)
{
Bsd::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);
}
void Bsd::Scheduler::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 current time before running task */
Bsd::update_time();
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;
}
#include <timer_session/connection.h>
namespace {
struct Logger : Genode::Thread<0x4000>
{
Timer::Connection _timer;
Bsd::Scheduler &_scheduler;
unsigned const _interval;
Logger(Bsd::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);
}
}
};
}
#define ANSI_ESC_RESET "\033[00m"
#define ANSI_ESC_BLACK "\033[30m"
#define ANSI_ESC_RED "\033[31m"
#define ANSI_ESC_YELLOW "\033[33m"
static char const *state_color(Bsd::Task::State state)
{
switch (state) {
case Bsd::Task::STATE_INIT: return ANSI_ESC_RESET;
case Bsd::Task::STATE_RUNNING: return ANSI_ESC_RED;
case Bsd::Task::STATE_BLOCKED: return ANSI_ESC_YELLOW;
}
return ANSI_ESC_BLACK;
}
void Bsd::Scheduler::log_state(char const *prefix)
{
unsigned i;
Bsd::Task *t;
for (i = 0, t = _present_list.first(); t; t = t->next(), ++i) {
Genode::printf("%s [%u] prio: %u state: %s%u" ANSI_ESC_RESET " %s\n",
prefix, i, t->priority(), state_color(t->state()),
t->state(), t->name());
}
}
Bsd::Scheduler::Scheduler()
{
if (debugging)
new (Genode::env()->heap()) Logger(*this, 10);
}
Bsd::Scheduler::~Scheduler() { }

View File

@ -0,0 +1,139 @@
/*
* \brief Signal context for timer events
* \author Josef Soentgen
* \date 2014-10-10
*/
/*
* Copyright (C) 2014-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/env.h>
#include <base/heap.h>
#include <base/printf.h>
#include <base/sleep.h>
#include <base/tslab.h>
#include <timer_session/connection.h>
/* local includes */
#include <list.h>
#include <bsd.h>
#include <extern_c_begin.h>
# include <bsd_emul.h>
#include <extern_c_end.h>
static unsigned long millisecs;
namespace Bsd {
class Timer;
}
/**
* Bsd::Timer
*/
class Bsd::Timer
{
private:
::Timer::Connection _timer_conn;
Genode::Signal_rpc_member<Bsd::Timer> _dispatcher;
/**
* Handle trigger_once signal
*/
void _handle(unsigned)
{
Bsd::scheduler().schedule();
}
public:
/**
* Constructor
*/
Timer(Server::Entrypoint &ep)
:
_dispatcher(ep, *this, &Bsd::Timer::_handle)
{
_timer_conn.sigh(_dispatcher);
}
/**
* Update time counter
*/
void update_millisecs()
{
millisecs = _timer_conn.elapsed_ms();
}
};
static Bsd::Timer *_bsd_timer;
void Bsd::timer_init(Server::Entrypoint &ep)
{
/* XXX safer way preventing possible nullptr access? */
static Bsd::Timer bsd_timer(ep);
_bsd_timer = &bsd_timer;
/* initialize value explicitly */
millisecs = 0UL;
}
void Bsd::update_time() {
_bsd_timer->update_millisecs(); }
static Timer::Connection _timer;
static Bsd::Task *_sleep_task;
/*****************
** sys/systm.h **
*****************/
extern "C" int msleep(const volatile void *ident, struct mutex *mtx,
int priority, const char *wmesg, int timo)
{
// PDBG("ident: %p mtx: %p priority: %d wmesg: '%s' timo: %d",
// ident, mtx, priority, wmesg, timo);
if (_sleep_task) {
PERR("_sleep_task is not null, current task: '%s'", Bsd::scheduler().current()->name());
Genode::sleep_forever();
}
_sleep_task = Bsd::scheduler().current();
// PERR("msleep: '%s' %p", _sleep_task->name(), ident);
_sleep_task->block_and_schedule();
return 0;
}
extern "C" void wakeup(const volatile void *ident)
{
// PERR("wakeup: '%s' %p", _sleep_task->name(), ident);
_sleep_task->unblock();
_sleep_task = nullptr;
}
/*********************
** machine/param.h **
*********************/
extern "C" void delay(int delay)
{
_timer.msleep(delay);
}

View File

@ -0,0 +1,79 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
.asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
#endif /* LIBC_SCCS and not lint */
//#include <machine/asm.h>
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the environment 'a'.
* The previous signal state is NOT restored.
*/
.text; .p2align 2,0x90
.globl _setjmp; .type _setjmp,@function; _setjmp:
movl 4(%esp),%eax
movl 0(%esp),%edx
movl %edx, 0(%eax) /* rta */
movl %ebx, 4(%eax)
movl %esp, 8(%eax)
movl %ebp,12(%eax)
movl %esi,16(%eax)
movl %edi,20(%eax)
fnstcw 24(%eax)
xorl %eax,%eax
ret
.size _setjmp, . - _setjmp
.text; .p2align 2,0x90
.globl _longjmp; .type _longjmp,@function; _longjmp:
movl 4(%esp),%edx
movl 8(%esp),%eax
movl 0(%edx),%ecx
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
fldcw 24(%edx)
testl %eax,%eax
jnz 1f
incl %eax
1: movl %ecx,0(%esp)
ret
.size _longjmp, . - _longjmp

View File

@ -0,0 +1,93 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
.asciz "@(#)_setjmp.s 5.1 (Berkeley) 4/23/90"
#endif /* LIBC_SCCS and not lint */
//#include <machine/asm.h>
/*
* C library -- _setjmp, _longjmp
*
* _longjmp(a,v)
* will generate a "return(v)" from the last call to
* _setjmp(a)
* by restoring registers from the environment 'a'.
* The previous signal state is NOT restored.
*/
.text; .p2align 4,0x90
.globl _setjmp; .type _setjmp,@function; _setjmp:
movq %rdi,%rax
movq 0(%rsp),%rdx /* retval */
movq %rdx, 0(%rax) /* 0; retval */
movq %rbx, 8(%rax) /* 1; rbx */
movq %rsp,16(%rax) /* 2; rsp */
movq %rbp,24(%rax) /* 3; rbp */
movq %r12,32(%rax) /* 4; r12 */
movq %r13,40(%rax) /* 5; r13 */
movq %r14,48(%rax) /* 6; r14 */
movq %r15,56(%rax) /* 7; r15 */
fnstcw 64(%rax) /* 8; fpu cw */
stmxcsr 68(%rax) /* and mxcsr */
xorq %rax,%rax
ret
.size _setjmp, . - _setjmp
.text; .p2align 4,0x90
.globl _longjmp; .type _longjmp,@function; _longjmp:
movq %rdi,%rdx
/* Restore the mxcsr, but leave exception flags intact. */
stmxcsr -4(%rsp)
movl 68(%rdx),%eax
andl $0xffffffc0,%eax
movl -4(%rsp),%edi
andl $0x3f,%edi
xorl %eax,%edi
movl %edi,-4(%rsp)
ldmxcsr -4(%rsp)
movq %rsi,%rax /* retval */
movq 0(%rdx),%rcx
movq 8(%rdx),%rbx
movq 16(%rdx),%rsp
movq 24(%rdx),%rbp
movq 32(%rdx),%r12
movq 40(%rdx),%r13
movq 48(%rdx),%r14
movq 56(%rdx),%r15
fldcw 64(%rdx)
testq %rax,%rax
jnz 1f
incq %rax
1: movq %rcx,0(%rsp)
ret
.size _longjmp, . - _longjmp

View File

@ -4,6 +4,11 @@
#
#REPOSITORIES += $(GENODE_DIR)/repos/dde_oss
#
# Drivers ported from the OpenBSD
#
#REPOSITORIES += $(GENODE_DIR)/repos/dde_bsd
#
# Drivers ported from iPXE
#