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

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