mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 15:02:25 +00:00
parent
57aab46fc3
commit
2760b67902
33
repos/dde_linux/src/include/lx_emul/io_port.h
Normal file
33
repos/dde_linux/src/include/lx_emul/io_port.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* \brief Lx_emul support for I/O port access
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-02-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _LX_EMUL__IO_PORT_H_
|
||||
#define _LX_EMUL__IO_PORT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
unsigned char lx_emul_io_port_inb(unsigned short addr);
|
||||
unsigned short lx_emul_io_port_inw(unsigned short addr);
|
||||
unsigned int lx_emul_io_port_inl(unsigned short addr);
|
||||
|
||||
void lx_emul_io_port_outb(unsigned char value, unsigned short addr);
|
||||
void lx_emul_io_port_outw(unsigned short value, unsigned short addr);
|
||||
void lx_emul_io_port_outl(unsigned int value, unsigned short addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LX_EMUL__IO_PORT_H_ */
|
@ -74,6 +74,22 @@ class Lx_kit::Device : List<Device>::Element
|
||||
void handle();
|
||||
};
|
||||
|
||||
struct Io_port : List<Io_port>::Element
|
||||
{
|
||||
using Index = Platform::Device::Io_port_range::Index;
|
||||
|
||||
Index idx;
|
||||
uint16_t addr;
|
||||
uint16_t size;
|
||||
|
||||
Constructible<Platform::Device::Io_port_range> io_port {};
|
||||
|
||||
bool match(uint16_t addr);
|
||||
|
||||
Io_port(unsigned idx, uint16_t addr, uint16_t size)
|
||||
: idx{idx}, addr(addr), size(size) {}
|
||||
};
|
||||
|
||||
struct Clock : List<Clock>::Element
|
||||
{
|
||||
unsigned idx;
|
||||
@ -93,6 +109,7 @@ class Lx_kit::Device : List<Device>::Element
|
||||
Name const _name;
|
||||
Type const _type;
|
||||
List<Io_mem> _io_mems {};
|
||||
List<Io_port> _io_ports {};
|
||||
List<Irq> _irqs {};
|
||||
List<Clock> _clocks {};
|
||||
Constructible<Platform::Device> _pdev {};
|
||||
@ -101,6 +118,10 @@ class Lx_kit::Device : List<Device>::Element
|
||||
void _for_each_io_mem(FN const & fn) {
|
||||
for (Io_mem * i = _io_mems.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_io_port(FN const & fn) {
|
||||
for (Io_port * i = _io_ports.first(); i; i = i->next()) fn(*i); }
|
||||
|
||||
template <typename FN>
|
||||
void _for_each_irq(FN const & fn) {
|
||||
for (Irq * i = _irqs.first(); i; i = i->next()) fn(*i); }
|
||||
@ -125,6 +146,14 @@ class Lx_kit::Device : List<Device>::Element
|
||||
|
||||
bool read_config(unsigned reg, unsigned len, unsigned *val);
|
||||
bool write_config(unsigned reg, unsigned len, unsigned val);
|
||||
|
||||
bool io_port(uint16_t addr);
|
||||
uint8_t io_port_inb(uint16_t addr);
|
||||
uint16_t io_port_inw(uint16_t addr);
|
||||
uint32_t io_port_inl(uint16_t addr);
|
||||
void io_port_outb(uint16_t addr, uint8_t val);
|
||||
void io_port_outw(uint16_t addr, uint16_t val);
|
||||
void io_port_outl(uint16_t addr, uint32_t val);
|
||||
};
|
||||
|
||||
|
||||
|
30
repos/dde_linux/src/include/spec/x86/lx_emul/shadow/asm/io.h
Normal file
30
repos/dde_linux/src/include/spec/x86/lx_emul/shadow/asm/io.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* \brief Shadow copy of asm/io.h
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-02-21
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_IO_H
|
||||
#define _ASM_X86_IO_H
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable_types.h>
|
||||
|
||||
#include <lx_emul/io_port.h>
|
||||
|
||||
void __iomem *ioremap(resource_size_t offset, unsigned long size);
|
||||
void iounmap(volatile void __iomem *addr);
|
||||
|
||||
#define inb lx_emul_io_port_inb
|
||||
#define inw lx_emul_io_port_inw
|
||||
#define inl lx_emul_io_port_inl
|
||||
|
||||
#define outb lx_emul_io_port_outb
|
||||
#define outw lx_emul_io_port_outw
|
||||
#define outl lx_emul_io_port_outl
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
||||
#endif /* _ASM_X86_IO_H */
|
@ -18,6 +18,7 @@
|
||||
#include <base/attached_dataspace.h>
|
||||
#include <base/exception.h>
|
||||
#include <io_mem_session/client.h>
|
||||
#include <io_port_session/client.h>
|
||||
#include <irq_session/client.h>
|
||||
#include <platform_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
@ -39,6 +40,7 @@ class Platform::Device : Interface, Noncopyable
|
||||
struct Range { addr_t start; size_t size; };
|
||||
|
||||
struct Mmio;
|
||||
struct Io_port_range;
|
||||
struct Irq;
|
||||
struct Config_space;
|
||||
|
||||
@ -104,6 +106,36 @@ class Platform::Device::Mmio : Range
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Io_port_range : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Index { unsigned value; };
|
||||
|
||||
private:
|
||||
|
||||
Device &_device;
|
||||
Index _index;
|
||||
|
||||
Constructible<Io_port_session_client> _io_port { };
|
||||
|
||||
public:
|
||||
|
||||
Io_port_range(Device &device, Index index);
|
||||
|
||||
explicit Io_port_range(Device &device)
|
||||
: _device { device }, _index { ~0u } { }
|
||||
|
||||
uint8_t inb(uint16_t addr);
|
||||
uint16_t inw(uint16_t addr);
|
||||
uint32_t inl(uint16_t addr);
|
||||
|
||||
void outb(uint16_t addr, uint8_t val);
|
||||
void outw(uint16_t addr, uint16_t val);
|
||||
void outl(uint16_t addr, uint32_t val);
|
||||
};
|
||||
|
||||
|
||||
class Platform::Device::Irq : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
101
repos/dde_linux/src/lib/lx_emul/io_port.cc
Normal file
101
repos/dde_linux/src/lib/lx_emul/io_port.cc
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* \brief Lx_emul backend for I/O port access
|
||||
* \author Josef Soentgen
|
||||
* \date 2022-02-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2022 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#include <lx_kit/env.h>
|
||||
#include <lx_emul/io_port.h>
|
||||
|
||||
|
||||
template<typename T>
|
||||
T _io_port_in(unsigned short addr)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
|
||||
unsigned ret = 0;
|
||||
bool valid_ret = false;
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
if (d.io_port(addr)) {
|
||||
valid_ret = true;
|
||||
switch (sizeof (T)) {
|
||||
case sizeof (unsigned char): ret = d.io_port_inb(addr); break;
|
||||
case sizeof (unsigned short): ret = d.io_port_inw(addr); break;
|
||||
case sizeof (unsigned int): ret = d.io_port_inl(addr); break;
|
||||
default: valid_ret = false; break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!valid_ret)
|
||||
error("could not read I/O port resource ", Hex(addr));
|
||||
|
||||
return static_cast<T>(ret);
|
||||
}
|
||||
|
||||
|
||||
unsigned char lx_emul_io_port_inb(unsigned short addr)
|
||||
{
|
||||
return _io_port_in<unsigned char>(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned short lx_emul_io_port_inw(unsigned short addr)
|
||||
{
|
||||
return _io_port_in<unsigned short>(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned int lx_emul_io_port_inl(unsigned short addr)
|
||||
{
|
||||
return _io_port_in<unsigned int>(addr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void _io_port_out(unsigned short addr, T value)
|
||||
{
|
||||
using namespace Lx_kit;
|
||||
using namespace Genode;
|
||||
|
||||
bool valid_ret = false;
|
||||
env().devices.for_each([&] (Device & d) {
|
||||
if (d.io_port(addr)) {
|
||||
valid_ret = true;
|
||||
switch (sizeof (T)) {
|
||||
case sizeof (unsigned char): d.io_port_outb(addr, (unsigned char)value); break;
|
||||
case sizeof (unsigned short): d.io_port_outw(addr, (unsigned short)value); break;
|
||||
case sizeof (unsigned int): d.io_port_outl(addr, (unsigned int)value); break;
|
||||
default: valid_ret = false; break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!valid_ret)
|
||||
error("could not write I/O port resource ", Hex(addr));
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_io_port_outb(unsigned char value, unsigned short addr)
|
||||
{
|
||||
_io_port_out<unsigned char>(addr, value);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_io_port_outw(unsigned short value, unsigned short addr)
|
||||
{
|
||||
_io_port_out<unsigned short>(addr, value);
|
||||
}
|
||||
|
||||
|
||||
void lx_emul_io_port_outl(unsigned int value, unsigned short addr)
|
||||
{
|
||||
_io_port_out<unsigned int>(addr, value);
|
||||
}
|
@ -27,6 +27,17 @@ bool Device::Io_mem::match(addr_t addr, size_t size)
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
** Device::Io_port **
|
||||
**********************/
|
||||
|
||||
bool Device::Io_port::match(uint16_t addr)
|
||||
{
|
||||
return (this->addr <= addr) &&
|
||||
((this->addr + this->size) >= addr);
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
** Device::Irq**
|
||||
****************/
|
||||
@ -168,6 +179,110 @@ void Device::irq_ack(unsigned number)
|
||||
}
|
||||
|
||||
|
||||
bool Device::io_port(uint16_t addr)
|
||||
{
|
||||
bool ret = false;
|
||||
_for_each_io_port([&] (Io_port & io) {
|
||||
if (io.match(addr))
|
||||
ret = true;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint8_t Device::io_port_inb(uint16_t addr)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
ret = io.io_port->inb(addr);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint16_t Device::io_port_inw(uint16_t addr)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
ret = io.io_port->inw(addr);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Device::io_port_inl(uint16_t addr)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
ret = io.io_port->inl(addr);
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Device::io_port_outb(uint16_t addr, uint8_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
io.io_port->outb(addr, val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Device::io_port_outw(uint16_t addr, uint16_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
io.io_port->outw(addr, val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Device::io_port_outl(uint16_t addr, uint32_t val)
|
||||
{
|
||||
_for_each_io_port([&] (Device::Io_port & io) {
|
||||
if (!io.match(addr))
|
||||
return;
|
||||
|
||||
if (!io.io_port.constructed())
|
||||
io.io_port.construct(*_pdev, io.idx);
|
||||
|
||||
io.io_port->outl(addr, val);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Device::enable()
|
||||
{
|
||||
if (_pdev.constructed())
|
||||
@ -208,6 +323,13 @@ Device::Device(Entrypoint & ep,
|
||||
_io_mems.insert(new (heap) Io_mem(i++, addr, size));
|
||||
});
|
||||
|
||||
i = 0;
|
||||
xml.for_each_sub_node("io_port", [&] (Xml_node node) {
|
||||
uint16_t addr = node.attribute_value<uint16_t>("phys_addr", 0U);
|
||||
uint16_t size = node.attribute_value<uint16_t>("size", 0U);
|
||||
_io_ports.insert(new (heap) Io_port(i++, addr, size));
|
||||
});
|
||||
|
||||
i = 0;
|
||||
xml.for_each_sub_node("irq", [&] (Xml_node node) {
|
||||
_irqs.insert(new (heap) Irq(ep, i++, node.attribute_value("number", 0U)));
|
||||
|
@ -229,6 +229,13 @@ static unsigned bar_size(Platform::Device const &dev,
|
||||
|
||||
val = node.attribute_value("size", 0u);
|
||||
});
|
||||
|
||||
device.for_each_sub_node("io_port", [&] (Xml_node node) {
|
||||
if (node.attribute_value("bar", 6u) != bar)
|
||||
return;
|
||||
|
||||
val = node.attribute_value("size", 0u);
|
||||
});
|
||||
});
|
||||
|
||||
return val;
|
||||
@ -271,7 +278,7 @@ Platform::Device::Device(Connection &platform, Name name)
|
||||
unsigned Platform::Device::Config_space::read(unsigned char address,
|
||||
Access_size size)
|
||||
{
|
||||
// 32bit BARs only for now
|
||||
/* 32bit BARs only for now */
|
||||
if (address >= 0x10 && address <= 0x24) {
|
||||
unsigned const bar = (address - 0x10) / 4;
|
||||
if (_device._bar_checked_for_size[bar]) {
|
||||
@ -286,9 +293,6 @@ unsigned Platform::Device::Config_space::read(unsigned char address,
|
||||
if (address == 0x34)
|
||||
return 0u;
|
||||
|
||||
if (address > 0x3f)
|
||||
return 0u;
|
||||
|
||||
Legacy_platform::Device::Access_size const as = convert(size);
|
||||
Legacy_platform::Device_client device { _device._device_cap };
|
||||
return device.config_read(address, as);
|
||||
@ -299,7 +303,7 @@ void Platform::Device::Config_space::write(unsigned char address,
|
||||
unsigned value,
|
||||
Access_size size)
|
||||
{
|
||||
// 32bit BARs only for now
|
||||
/* 32bit BARs only for now */
|
||||
if (address >= 0x10 && address <= 0x24) {
|
||||
unsigned const bar = (address - 0x10) / 4;
|
||||
if (value == 0xffffffffu)
|
||||
@ -307,8 +311,30 @@ void Platform::Device::Config_space::write(unsigned char address,
|
||||
return;
|
||||
}
|
||||
|
||||
if (address != 0x04)
|
||||
/* reject writes to unknown addresses */
|
||||
switch (address) {
|
||||
case 0x04:
|
||||
/*
|
||||
* Doing this multiple times induces multiple "assignment of PCI
|
||||
* device" diasgnostics currently.
|
||||
*/
|
||||
/* command register (value for enable io, memory, bus master) */
|
||||
value = 7;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Write in [0x40,0xff] should be okay if there are is no capability
|
||||
* list (status register bit 4 + capability list pointer). Otherwise,
|
||||
* writes into capability-list entries should be rejected.
|
||||
*/
|
||||
|
||||
case 0xc0: /* UHCI BIOS handoff (UHCI_USBLEGSUP) */ break;
|
||||
case 0xc4: /* UHCI INTEL resume-enable (USBRES_INTEL) */ break;
|
||||
case 0x60 ... 0x6f: /* EHCI BIOS handoff (just empiric, address not fixed) */ break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
Legacy_platform::Device::Access_size const as = convert(size);
|
||||
Legacy_platform::Device_client device { _device._device_cap };
|
||||
@ -343,6 +369,53 @@ void *Platform::Device::Mmio::_local_addr()
|
||||
}
|
||||
|
||||
|
||||
Platform::Device::Io_port_range::Io_port_range(Device &device, Index index)
|
||||
:
|
||||
_device { device },
|
||||
_index { index }
|
||||
{
|
||||
Legacy_platform::Device_client client { _device._device_cap };
|
||||
|
||||
_io_port.construct(client.io_port((uint8_t)index.value));
|
||||
}
|
||||
|
||||
|
||||
unsigned char Platform::Device::Io_port_range::inb(uint16_t addr)
|
||||
{
|
||||
return _io_port->inb(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned short Platform::Device::Io_port_range::inw(uint16_t addr)
|
||||
{
|
||||
return _io_port->inw(addr);
|
||||
}
|
||||
|
||||
|
||||
unsigned int Platform::Device::Io_port_range::inl(uint16_t addr)
|
||||
{
|
||||
return _io_port->inl(addr);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outb(uint16_t addr, uint8_t val)
|
||||
{
|
||||
return _io_port->outb(addr, val);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outw(uint16_t addr, uint16_t val)
|
||||
{
|
||||
return _io_port->outw(addr, val);
|
||||
}
|
||||
|
||||
|
||||
void Platform::Device::Io_port_range::outl(uint16_t addr, uint32_t val)
|
||||
{
|
||||
return _io_port->outl(addr, val);
|
||||
}
|
||||
|
||||
|
||||
Platform::Device::Irq::Irq(Platform::Device &device, Index index)
|
||||
:
|
||||
_device { device },
|
||||
|
Loading…
Reference in New Issue
Block a user