mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-23 10:40:27 +00:00
parent
ee7f965061
commit
38c5abbaad
27
repos/libports/lib/mk/acpica.mk
Normal file
27
repos/libports/lib/mk/acpica.mk
Normal file
@ -0,0 +1,27 @@
|
||||
REQUIRES := x86
|
||||
|
||||
ACPICA_DIR := $(call select_from_ports,acpica)/src/lib/acpica
|
||||
ACPICA_COMP := $(ACPICA_DIR)/source/components
|
||||
|
||||
INC_DIR += $(ACPICA_DIR)/source/include
|
||||
|
||||
SRC_C += debugger/dbdisply.c debugger/dbobject.c debugger/dbxface.c
|
||||
SRC_C += $(addprefix disassembler/, $(notdir $(wildcard $(ACPICA_COMP)/disassembler/*.c)))
|
||||
SRC_C += $(addprefix dispatcher/, $(notdir $(wildcard $(ACPICA_COMP)/dispatcher/*.c)))
|
||||
SRC_C += $(addprefix events/, $(notdir $(wildcard $(ACPICA_COMP)/events/*.c)))
|
||||
SRC_C += $(addprefix executer/, $(notdir $(wildcard $(ACPICA_COMP)/executer/*.c)))
|
||||
SRC_C += $(addprefix hardware/, $(notdir $(wildcard $(ACPICA_COMP)/hardware/*.c)))
|
||||
SRC_C += $(addprefix namespace/, $(notdir $(wildcard $(ACPICA_COMP)/namespace/*.c)))
|
||||
SRC_C += $(addprefix parser/, $(notdir $(wildcard $(ACPICA_COMP)/parser/*.c)))
|
||||
SRC_C += $(addprefix resources/, $(notdir $(wildcard $(ACPICA_COMP)/resources/*.c)))
|
||||
SRC_C += $(addprefix tables/, $(notdir $(wildcard $(ACPICA_COMP)/tables/*.c)))
|
||||
SRC_C += $(addprefix utilities/, $(notdir $(wildcard $(ACPICA_COMP)/utilities/*.c)))
|
||||
|
||||
SRC_CC += osl.cc iomem.cc pci.cc
|
||||
SRC_CC += scan_root.cc
|
||||
|
||||
CC_OPT += -Wno-unused-function -Wno-unused-variable
|
||||
CC_C_OPT += -DACPI_LIBRARY
|
||||
|
||||
vpath %.c $(ACPICA_COMP)
|
||||
vpath %.cc $(REP_DIR)/src/lib/acpica
|
1
repos/libports/ports/acpica.hash
Normal file
1
repos/libports/ports/acpica.hash
Normal file
@ -0,0 +1 @@
|
||||
a3d820f28b860fdd9fd8c855f0fa2ec0b4beb859
|
9
repos/libports/ports/acpica.port
Normal file
9
repos/libports/ports/acpica.port
Normal file
@ -0,0 +1,9 @@
|
||||
LICENSE := BSD
|
||||
VERSION := 20160212
|
||||
DOWNLOADS := acpica.archive
|
||||
|
||||
URL(acpica) := http://acpica.org/sites/acpica/files/acpica-unix2-$(VERSION).tar.gz
|
||||
SHA(acpica) := 9b4ceb8562952c16bfb70c567429509504f388b8
|
||||
DIR(acpica) := src/lib/acpica
|
||||
|
||||
PATCHES := src/lib/acpica/acpica.patch
|
161
repos/libports/run/acpica.run
Normal file
161
repos/libports/run/acpica.run
Normal file
@ -0,0 +1,161 @@
|
||||
assert_spec acpi
|
||||
|
||||
if {
|
||||
![have_spec hw] &&
|
||||
![have_spec nova]
|
||||
} {
|
||||
puts "Platform is unsupported."
|
||||
exit 0
|
||||
}
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
drivers/input
|
||||
drivers/timer
|
||||
server/dynamic_rom
|
||||
server/report_rom
|
||||
app/acpica
|
||||
test/input
|
||||
}
|
||||
|
||||
source ${genode_dir}/repos/base/run/platform_drv.inc
|
||||
|
||||
# override default platform driver policy
|
||||
proc platform_drv_policy {} {
|
||||
return {
|
||||
<policy label="ps2_drv"> <device name="PS2"/> </policy>
|
||||
<policy label="acpica"> <pci class="ALL"/> </policy>}
|
||||
}
|
||||
|
||||
append_platform_drv_build_components
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
set config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="IRQ"/>
|
||||
<service name="RAM"/>
|
||||
<service name="ROM"/>
|
||||
<service name="LOG"/>
|
||||
<service name="RM"/>
|
||||
<service name="IO_MEM" />
|
||||
<service name="IO_PORT" />
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="acpica">
|
||||
<!-- <binary name="debug-acpica"/> -->
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config ld_verbose="yes" reset="no" poweroff="no" report="yes">
|
||||
<!-- required for "debug-acpica":
|
||||
<libc stdout="/dev/log">
|
||||
<vfs> <dir name="dev"> <log/> </dir> </vfs>
|
||||
</libc>
|
||||
-->
|
||||
</config>
|
||||
<route>
|
||||
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>
|
||||
<service name="Report"> <child name="acpi_state"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="acpi_state">
|
||||
<binary name="report_rom"/>
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides>
|
||||
<service name="ROM" />
|
||||
<service name="Report" />
|
||||
</provides>
|
||||
<config verbose="yes">
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="SIGNAL"> <parent/> </service>
|
||||
<service name="CAP"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="system">
|
||||
<inline description="set system state to 'normal'">
|
||||
<system state="normal"/>
|
||||
</inline>
|
||||
<sleep milliseconds="5000" />
|
||||
<inline description="set system state to 'reset'">
|
||||
<system state="reset"/>
|
||||
</inline>
|
||||
<!--
|
||||
<inline description="set system state to 'poweroff'">
|
||||
<system state="poweroff"/>
|
||||
</inline>
|
||||
-->
|
||||
<sleep milliseconds="500" />
|
||||
</rom>
|
||||
</config>
|
||||
</start>}
|
||||
|
||||
append config {
|
||||
<start name="ps2_drv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="Input"/></provides>
|
||||
<config verbose_keyboard="no" verbose_mouse="no" verbose_scancodes="no"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
<service name="Platform"> <child name="platform_drv"/> </service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="test-input">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<service name="LOG"> <parent/> </service>
|
||||
<service name="RM"> <parent/> </service>
|
||||
|
||||
<service name="Input"> <child name="ps2_drv"/> </service>
|
||||
<service name="Timer"> <child name="timer"/> </service>
|
||||
</route>
|
||||
</start>}
|
||||
|
||||
append_platform_drv_config
|
||||
|
||||
append config {
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
set boot_modules {
|
||||
core init
|
||||
ld.lib.so libc.lib.so
|
||||
timer
|
||||
ps2_drv
|
||||
report_rom
|
||||
dynamic_rom
|
||||
acpica
|
||||
debug-acpica
|
||||
test-input
|
||||
}
|
||||
|
||||
append_platform_drv_boot_modules
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args "-nographic -m 128"
|
||||
|
||||
run_genode_until {\[init -\> acpica\].*SCI IRQ:.*\n} 30
|
141
repos/libports/src/app/acpica/README
Normal file
141
repos/libports/src/app/acpica/README
Normal file
@ -0,0 +1,141 @@
|
||||
This directory contains a application using the ported ACPI-CA
|
||||
library (https://www.acpica.org) and reports ACPI state changes in form of
|
||||
Genode reports. Additionally the application is capable to perform ACPI poweroff
|
||||
and reset.
|
||||
|
||||
Behavior
|
||||
--------
|
||||
|
||||
General support for ACPI events compromises state changes from the following
|
||||
sources:
|
||||
|
||||
- ACPI Lid - open/closed
|
||||
- ACPI Smart battery (SB) - charging/discharging and static information (capacity)
|
||||
- ACPI fixed events - e.g. power button
|
||||
- ACPI AC adapters - power cable plugged/un-plugged
|
||||
- ACPI Embedded controller - some Fn-* keys and on some machines also Lid, AC, SB changes
|
||||
|
||||
Whenever a state change is detected, a Genode report is generated, if a
|
||||
config attribute "report" is set to "yes". The reports are named
|
||||
'acpi_lid', 'acpi_battery', 'acpi_fixed', 'acpi_ac' and 'acpi_ec'. See below
|
||||
for the xml syntax used so far. Please also look into the ACPI specification
|
||||
for detailed description of some of the fields and their possible values.
|
||||
|
||||
If the config attributes 'reset' or 'poweroff' are set to yes, the application
|
||||
additionally looks for a ROM in XML format named 'system' and monitors
|
||||
changes of the 'state' attribute:
|
||||
|
||||
!<system state="something"/>
|
||||
|
||||
If the ROM changes to 'state="reset"' the application tries to reset the
|
||||
machine immediately.
|
||||
If the ROM changes to 'state="poweroff"' the application tries to poweroff
|
||||
the machine immediately.
|
||||
|
||||
The attempt to reset or to poweroff may fail. One reason, we have seen so far,
|
||||
is that the required resources are already owned by other components in the
|
||||
system. E.g. for 'reset' on some machines the platform driver posses the
|
||||
required I/O ports and the acpica application don't get access to. On such
|
||||
systems the platform driver can be configured to react on the 'state="reset"'
|
||||
system state change. The platform_drv can be configured to monitor
|
||||
the 'system' ROM by adding a config attribute named 'system' and set to 'yes'.
|
||||
|
||||
Furthermore the ACPICA library triggers depended on the ACPI table content
|
||||
I/O operations on various PCI devices and partly re-configure it. Because of
|
||||
this a policy rule at the platform driver is required, that permits access
|
||||
to the required devices.
|
||||
|
||||
Excerpt of important parts of the acpica configuration
|
||||
------------------------------------------------------
|
||||
|
||||
!<start name="acpica">
|
||||
! <!-- <binary name="debug-acpica"/> -->
|
||||
! ...
|
||||
! <config reset="no" poweroff="no" report="yes"/>
|
||||
! <route>
|
||||
! <service name="ROM" label="system"> <child name="..."/> </service>
|
||||
! <service name="Report"> <child name="..."/> </service>
|
||||
! ...
|
||||
! </route>
|
||||
!</start>
|
||||
!
|
||||
!<start name="platform_drv" >
|
||||
! ...
|
||||
! <config acpi="yes" system="yes">
|
||||
! <policy label="acpica"> <pci class="ALL"/> </policy>
|
||||
! ...
|
||||
! </config>
|
||||
!</start>
|
||||
|
||||
Reports generated by the Genode acpica application
|
||||
--------------------------------------------------
|
||||
|
||||
Report 'acpi_lid' - open/closed:
|
||||
|
||||
!<acpi_lid>
|
||||
! <lid value="1" count="1">open</lid>
|
||||
!</acpi_lid>
|
||||
|
||||
!<acpi_lid>
|
||||
! <lid value="0" count="3">closed</lid>
|
||||
!</acpi_lid>
|
||||
|
||||
|
||||
Report 'acpi_ac' - power cable plugged-in /unplugged
|
||||
|
||||
!<acpi_ac>
|
||||
! <ac value="1" count="1">online</ac>
|
||||
!</acpi_ac>
|
||||
|
||||
!<acpi_ac>
|
||||
! <ac value="0" count="2">offline</ac>
|
||||
!</acpi_ac>
|
||||
|
||||
|
||||
Report 'acpi_ec' - embedded controller events
|
||||
|
||||
!<acpi_ec>
|
||||
! <ec>
|
||||
! <data value="42" count="1">triggered</data>
|
||||
! <data value="43" count="1"/>
|
||||
! </ec>
|
||||
!</acpi_ec>
|
||||
|
||||
|
||||
Report 'acpi_battery' - smart battery status changes
|
||||
|
||||
!<acpi_battery>
|
||||
! <sb>
|
||||
! <name>BAT1</name>
|
||||
! <powerunit value="1">mA/mAh</powerunit>
|
||||
! <design_capacity value="4800"/>
|
||||
! <last_full_capacity value="5417"/>
|
||||
! <technology value="1">secondary</technology>
|
||||
! <voltage value="12608"/>
|
||||
! <warning_capacity value="325"/>
|
||||
! <low_capacity value="162"/>
|
||||
! <granularity1 value="0"/>
|
||||
! <granularity2 value="0"/>
|
||||
! <serial>BAT1</serial>
|
||||
! <model>RT672</model>
|
||||
! <type>LiON</type>
|
||||
! <oem>ASP</oem>
|
||||
! <status value="31"/>
|
||||
! <state value="1">discharging</state>
|
||||
! <present_rate value="0"/>
|
||||
! <remaining_capacity value="5663"/>
|
||||
! <present_voltage value="12524"/>
|
||||
! </sb>
|
||||
!</acpi_battery>
|
||||
|
||||
!<acpi_battery>
|
||||
! ...
|
||||
! <state value="2">charging</state>
|
||||
! ...
|
||||
!</acpi_battery>
|
||||
|
||||
!<acpi_battery>
|
||||
! ...
|
||||
! <status value="15">battery not present</status>
|
||||
! ...
|
||||
!</acpi_battery>
|
85
repos/libports/src/app/acpica/ac.h
Normal file
85
repos/libports/src/app/acpica/ac.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* \brief Handle ACPI AC adapter devices
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
class Ac : Acpica::Callback<Ac> {
|
||||
|
||||
private:
|
||||
|
||||
Acpica::Reportstate * _report;
|
||||
UINT64 _ac_state = 0;
|
||||
UINT64 _ac_count = 0;
|
||||
|
||||
public:
|
||||
|
||||
Ac(void * report)
|
||||
: _report(reinterpret_cast<Acpica::Reportstate *>(report))
|
||||
{
|
||||
if (_report)
|
||||
_report->add_notify(this);
|
||||
}
|
||||
|
||||
void handle(ACPI_HANDLE ac, UINT32 value)
|
||||
{
|
||||
Acpica::Buffer<ACPI_OBJECT> onoff;
|
||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(ac, ACPI_STRING("_PSR"),
|
||||
nullptr, &onoff,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PDBG("failed - res=0x%x _PSR", res);
|
||||
return;
|
||||
}
|
||||
|
||||
_ac_state = onoff.object.Integer.Value;
|
||||
_ac_count++;
|
||||
|
||||
PINF("%s - ac (%u)",
|
||||
_ac_state == 0 ? "offline " :
|
||||
_ac_state == 1 ? "online " : "unknown ",
|
||||
value);
|
||||
|
||||
if (_report)
|
||||
_report->ac_event();
|
||||
}
|
||||
|
||||
static ACPI_STATUS detect(ACPI_HANDLE ac, UINT32, void * report, void **)
|
||||
{
|
||||
Ac * obj = new (Genode::env()->heap()) Ac(report);
|
||||
|
||||
ACPI_STATUS res = AcpiInstallNotifyHandler (ac, ACPI_DEVICE_NOTIFY,
|
||||
handler, obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' res=0x%x", __func__, res);
|
||||
delete obj;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
PINF("detected - ac");
|
||||
|
||||
handler(ac, 0, obj);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml)
|
||||
{
|
||||
xml.attribute("value", _ac_state);
|
||||
xml.attribute("count", _ac_count);
|
||||
|
||||
if (_ac_state == 0)
|
||||
xml.append("offline");
|
||||
else if (_ac_state == 1)
|
||||
xml.append("online");
|
||||
else
|
||||
xml.append("unknown");
|
||||
}
|
||||
};
|
25
repos/libports/src/app/acpica/debug/printf.cc
Normal file
25
repos/libports/src/app/acpica/debug/printf.cc
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C"
|
||||
void AcpiOsPrintf (const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void AcpiOsVprintf (const char *fmt, va_list va)
|
||||
{
|
||||
vprintf(fmt, va);
|
||||
}
|
||||
|
7
repos/libports/src/app/acpica/debug/target.mk
Normal file
7
repos/libports/src/app/acpica/debug/target.mk
Normal file
@ -0,0 +1,7 @@
|
||||
TARGET = debug-acpica
|
||||
LIBS = libc
|
||||
SRC_CC = os.cc printf.cc
|
||||
|
||||
include $(PRG_DIR)/../target.inc
|
||||
|
||||
vpath os.cc $(PRG_DIR)/..
|
291
repos/libports/src/app/acpica/ec.h
Normal file
291
repos/libports/src/app/acpica/ec.h
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* \brief Handle ACPI Embedded Controller devices
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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 <util/mmio.h>
|
||||
|
||||
class Ec : Acpica::Callback<Ec> {
|
||||
|
||||
private:
|
||||
unsigned short ec_port_cmdsta;
|
||||
unsigned short ec_port_data;
|
||||
|
||||
Genode::Io_port_connection * ec_cmdsta = nullptr;
|
||||
Genode::Io_port_connection * ec_data = nullptr;;
|
||||
|
||||
ACPI_HANDLE gpe_block;
|
||||
|
||||
Acpica::Reportstate * _report;
|
||||
|
||||
/* 12.2.1 Embedded Controller Status, EC_SC (R) */
|
||||
struct State : Genode::Register<8> {
|
||||
struct Out_ful: Bitfield<0,1> { };
|
||||
struct In_ful : Bitfield<1,1> { };
|
||||
struct Sci_evt: Bitfield<5,1> { };
|
||||
};
|
||||
|
||||
/* 12.3. Embedded Controller Command Set */
|
||||
enum { RD_EC = 0x80, WR_EC = 0x81, QR_EC = 0x84 };
|
||||
|
||||
/* track data items reported by controller */
|
||||
struct Data : Genode::List<Data>::Element {
|
||||
Genode::uint64_t count;
|
||||
Genode::uint8_t data;
|
||||
bool triggered;
|
||||
|
||||
Data(Genode::uint8_t d) : count(0), data(d), triggered(false) { }
|
||||
};
|
||||
Genode::List<Data> _list_data;
|
||||
|
||||
public:
|
||||
|
||||
Ec(void * report)
|
||||
:
|
||||
_report(reinterpret_cast<Acpica::Reportstate *>(report))
|
||||
{ }
|
||||
|
||||
static UINT32 handler_gpe(ACPI_HANDLE dev, UINT32 gpe, void *context)
|
||||
{
|
||||
Ec * ec = reinterpret_cast<Ec *>(context);
|
||||
|
||||
ACPI_GPE_EVENT_INFO * ev = AcpiEvGetGpeEventInfo(ec->gpe_block, gpe);
|
||||
if (!ev || !ec->ec_cmdsta || !ec->ec_data) {
|
||||
PERR("unknown GPE 0x%x", gpe);
|
||||
return AE_OK; /* GPE is disabled and must be enabled explicitly */
|
||||
}
|
||||
|
||||
if ((ACPI_GPE_DISPATCH_TYPE (ev->Flags) != ACPI_GPE_DISPATCH_HANDLER) ||
|
||||
!ev->Dispatch.Handler) {
|
||||
PERR("unknown dispatch type, GPE 0x%x, flags=0x%x type=0x%x",
|
||||
gpe, ev->Flags, ACPI_GPE_DISPATCH_TYPE (ev->Flags));
|
||||
return AE_OK; /* GPE is disabled and must be enabled explicitly */
|
||||
}
|
||||
|
||||
State::access_t state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
|
||||
if (!State::Sci_evt::get(state)) {
|
||||
PERR("unknown status 0x%x", state);
|
||||
return ACPI_REENABLE_GPE; /* gpe is acked and re-enabled */
|
||||
}
|
||||
|
||||
ec->ec_cmdsta->outb(ec->ec_port_cmdsta, QR_EC);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (!(State::Out_ful::get(state)));
|
||||
|
||||
unsigned cnt = 0;
|
||||
unsigned char data;
|
||||
do {
|
||||
data = ec->ec_data->inb(ec->ec_port_data);
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
|
||||
if (!ec->_report)
|
||||
PINF("ec event - status 0x%x data 0x%x round=%u", state,
|
||||
data, ++cnt);
|
||||
} while (State::Out_ful::get(state));
|
||||
|
||||
if (ec->_report) {
|
||||
Data * data_obj = ec->_list_data.first();
|
||||
for (; data_obj; data_obj = data_obj->next()) {
|
||||
if (data_obj->data == data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!data_obj) {
|
||||
data_obj = new (Genode::env()->heap()) Data(data);
|
||||
ec->_list_data.insert(data_obj);
|
||||
}
|
||||
data_obj->count ++;
|
||||
data_obj->triggered = true;
|
||||
|
||||
ec->_report->ec_event();
|
||||
}
|
||||
|
||||
return ACPI_REENABLE_GPE; /* gpe is acked and re-enabled */
|
||||
}
|
||||
|
||||
static ACPI_STATUS detect_io_ports(ACPI_RESOURCE *resource,
|
||||
void *context)
|
||||
{
|
||||
Ec * ec = reinterpret_cast<Ec *>(context);
|
||||
|
||||
if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
|
||||
return AE_OK;
|
||||
|
||||
if (resource->Type != ACPI_RESOURCE_TYPE_IO) {
|
||||
PWRN("unknown resource type %u", resource->Type);
|
||||
return AE_OK;
|
||||
}
|
||||
/*
|
||||
PDBG("TYPE IO: IoDecode 0x%x, alignment 0x%x, AddressLen 0x%x "
|
||||
"min 0x%x max 0x%x",
|
||||
resource->Data.Io.IoDecode, resource->Data.Io.Alignment,
|
||||
resource->Data.Io.AddressLength, resource->Data.Io.Minimum,
|
||||
resource->Data.Io.Maximum);
|
||||
*/
|
||||
/* first port is data, second is status/cmd */
|
||||
if (resource->Data.Io.AddressLength != 1)
|
||||
PERR("unsupported address length of %u",
|
||||
resource->Data.Io.AddressLength);
|
||||
|
||||
if (!ec->ec_data) {
|
||||
ec->ec_port_data = resource->Data.Io.Minimum;
|
||||
ec->ec_data = new (Genode::env()->heap()) Genode::Io_port_connection(ec->ec_port_data, 1);
|
||||
} else
|
||||
if (!ec->ec_cmdsta) {
|
||||
ec->ec_port_cmdsta = resource->Data.Io.Minimum;
|
||||
ec->ec_cmdsta = new (Genode::env()->heap()) Genode::Io_port_connection(ec->ec_port_cmdsta, 1);
|
||||
} else
|
||||
PERR("unknown io_port");
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static ACPI_STATUS handler_ec(UINT32 function,
|
||||
ACPI_PHYSICAL_ADDRESS phys_addr,
|
||||
UINT32 bitwidth, UINT64 *value, void *,
|
||||
void *ec_void)
|
||||
{
|
||||
unsigned const bytes = bitwidth / 8;
|
||||
/* bitwidth can be larger than 64bit - use char array */
|
||||
unsigned char *result = reinterpret_cast<unsigned char *>(value);
|
||||
|
||||
if (bytes * 8 != bitwidth) {
|
||||
PERR("unsupport bit width of %u", bitwidth);
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
Ec * ec = reinterpret_cast<Ec *>(ec_void);
|
||||
|
||||
switch (function & ACPI_IO_MASK) {
|
||||
case ACPI_READ:
|
||||
for (unsigned i = 0; i < bytes; i++) {
|
||||
State::access_t state;
|
||||
|
||||
/* write command */
|
||||
ec->ec_cmdsta->outb(ec->ec_port_cmdsta, RD_EC);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (State::In_ful::get(state));
|
||||
|
||||
/* write address */
|
||||
ec->ec_data->outb(ec->ec_port_data, phys_addr + i);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (!(State::Out_ful::get(state)));
|
||||
|
||||
/* read value */
|
||||
result[i] = ec->ec_data->inb(ec->ec_port_data);
|
||||
}
|
||||
return AE_OK;
|
||||
case ACPI_WRITE:
|
||||
for (unsigned i = 0; i < bytes; i++) {
|
||||
State::access_t state;
|
||||
|
||||
/* write command */
|
||||
ec->ec_cmdsta->outb(ec->ec_port_cmdsta, WR_EC);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (State::In_ful::get(state));
|
||||
|
||||
/* write address */
|
||||
ec->ec_data->outb(ec->ec_port_data, phys_addr + i);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (State::In_ful::get(state));
|
||||
|
||||
/* write value */
|
||||
ec->ec_data->outb(ec->ec_port_data, result[i]);
|
||||
do {
|
||||
state = ec->ec_cmdsta->inb(ec->ec_port_cmdsta);
|
||||
} while (State::In_ful::get(state));
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
static ACPI_STATUS detect(ACPI_HANDLE ec, UINT32, void *report, void **)
|
||||
{
|
||||
Ec *ec_obj = new (Genode::env()->heap()) Ec(report);
|
||||
|
||||
ACPI_STATUS res = AcpiWalkResources(ec, ACPI_STRING("_CRS"),
|
||||
Ec::detect_io_ports, ec_obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' _CRS res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
res = AcpiInstallAddressSpaceHandler(ec, ACPI_ADR_SPACE_EC,
|
||||
handler_ec, nullptr,
|
||||
ec_obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' spacehandler res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
Acpica::Buffer<ACPI_OBJECT> sta;
|
||||
res = AcpiEvaluateObjectTyped(ec, ACPI_STRING("_GPE"), nullptr,
|
||||
&sta, ACPI_TYPE_INTEGER);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' _STA res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
UINT32 gpe_to_enable = sta.object.Integer.Value;
|
||||
|
||||
/* if ec_obj->gpe_block stays null - it's GPE0/GPE1 */
|
||||
res = AcpiGetGpeDevice(gpe_to_enable, &ec_obj->gpe_block);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' get_device res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
res = AcpiInstallGpeHandler(ec_obj->gpe_block, gpe_to_enable,
|
||||
ACPI_GPE_LEVEL_TRIGGERED, handler_gpe,
|
||||
ec_obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' install_device res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
res = AcpiEnableGpe (ec_obj->gpe_block, gpe_to_enable);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' enable_gpe res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
PINF("detected - ec");
|
||||
|
||||
if (ec_obj->_report)
|
||||
ec_obj->_report->add_notify(ec_obj);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml)
|
||||
{
|
||||
Data * data_obj = _list_data.first();
|
||||
for (; data_obj; data_obj = data_obj->next()) {
|
||||
xml.node("data", [&] {
|
||||
xml.attribute("value", data_obj->data);
|
||||
xml.attribute("count", data_obj->count);
|
||||
if (data_obj->triggered) {
|
||||
xml.append("triggered");
|
||||
data_obj->triggered = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
85
repos/libports/src/app/acpica/fixed.h
Normal file
85
repos/libports/src/app/acpica/fixed.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* \brief Handle fixed ACPI events, e.g. power button and sleep button
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
class Fixed : Acpica::Callback<Fixed> {
|
||||
|
||||
private:
|
||||
|
||||
Acpica::Reportstate * _report;
|
||||
|
||||
UINT64 _power_button_count = 0;
|
||||
UINT64 _sleep_button_count = 0;
|
||||
bool _power_button_pressed = false;
|
||||
bool _sleep_button_pressed = false;
|
||||
|
||||
public:
|
||||
|
||||
Fixed(void * report)
|
||||
: _report(reinterpret_cast<Acpica::Reportstate *>(report))
|
||||
{
|
||||
if (_report)
|
||||
_report->add_notify(this);
|
||||
}
|
||||
|
||||
static
|
||||
UINT32 handle_power_button(void *context)
|
||||
{
|
||||
Fixed * me = reinterpret_cast<Fixed *>(context);
|
||||
|
||||
me->_power_button_count++;
|
||||
|
||||
if (me->_report) {
|
||||
me->_power_button_pressed = true;
|
||||
me->_report->fixed_event();
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static
|
||||
UINT32 handle_sleep_button(void *context)
|
||||
{
|
||||
Fixed * me = reinterpret_cast<Fixed *>(context);
|
||||
|
||||
me->_sleep_button_count++;
|
||||
|
||||
if (me->_report) {
|
||||
me->_sleep_button_pressed = true;
|
||||
me->_report->fixed_event();
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml)
|
||||
{
|
||||
if (_power_button_count)
|
||||
xml.node("power_button", [&] {
|
||||
xml.attribute("value", _power_button_pressed);
|
||||
xml.attribute("count", _power_button_count);
|
||||
if (_power_button_pressed) {
|
||||
_power_button_pressed = false;
|
||||
xml.append("pressed");
|
||||
}
|
||||
});
|
||||
|
||||
if (_sleep_button_count)
|
||||
xml.node("sleep_button", [&] {
|
||||
xml.attribute("value", _sleep_button_pressed);
|
||||
xml.attribute("count", _sleep_button_count);
|
||||
if (_sleep_button_pressed) {
|
||||
_sleep_button_pressed = false;
|
||||
xml.append("pressed");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
83
repos/libports/src/app/acpica/lid.h
Normal file
83
repos/libports/src/app/acpica/lid.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* \brief Handle ACPI LID device
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
class Lid : Acpica::Callback<Lid> {
|
||||
|
||||
private:
|
||||
|
||||
Acpica::Reportstate * _report;
|
||||
UINT64 _lid_state = 0;
|
||||
UINT64 _lid_count = 0;
|
||||
|
||||
public:
|
||||
|
||||
Lid(void * report)
|
||||
: _report(reinterpret_cast<Acpica::Reportstate *>(report))
|
||||
{
|
||||
if (_report)
|
||||
_report->add_notify(this);
|
||||
}
|
||||
|
||||
void handle(ACPI_HANDLE lid, UINT32 value)
|
||||
{
|
||||
Acpica::Buffer<ACPI_OBJECT> onoff;
|
||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(lid, ACPI_STRING("_LID"),
|
||||
nullptr, &onoff,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' res=0x%x _PSR", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
PINF("%s - lid (%u)",
|
||||
onoff.object.Integer.Value ? "open " : "closed ",
|
||||
value);
|
||||
|
||||
_lid_state = onoff.object.Integer.Value;
|
||||
_lid_count++;
|
||||
|
||||
if (_report)
|
||||
_report->lid_event();
|
||||
}
|
||||
|
||||
static ACPI_STATUS detect(ACPI_HANDLE lid, UINT32, void * report, void **)
|
||||
{
|
||||
Lid * obj = new (Genode::env()->heap()) Lid(report);
|
||||
|
||||
ACPI_STATUS res = AcpiInstallNotifyHandler (lid, ACPI_DEVICE_NOTIFY,
|
||||
handler, obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PDBG("failed - %s res=0x%x LID adapter", __func__, res);
|
||||
delete obj;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
PINF("detected - lid");
|
||||
|
||||
handler(lid, 0, obj);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml)
|
||||
{
|
||||
xml.node("lid", [&] {
|
||||
xml.attribute("value", _lid_state);
|
||||
xml.attribute("count", _lid_count);
|
||||
if (_lid_state)
|
||||
xml.append("open");
|
||||
else
|
||||
xml.append("closed");
|
||||
});
|
||||
}
|
||||
};
|
277
repos/libports/src/app/acpica/os.cc
Normal file
277
repos/libports/src/app/acpica/os.cc
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* \brief Example app to utilize ACPICA library
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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/component.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/signal.h>
|
||||
#include <irq_session/connection.h>
|
||||
#include <io_port_session/connection.h>
|
||||
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
#include <os/config.h>
|
||||
#include <os/reporter.h>
|
||||
|
||||
#include <util/volatile_object.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
#include "accommon.h"
|
||||
#include "acevents.h"
|
||||
#include "acnamesp.h"
|
||||
}
|
||||
|
||||
namespace Acpica {
|
||||
struct Main;
|
||||
struct Statechange;
|
||||
class Reportstate;
|
||||
};
|
||||
|
||||
#include "util.h"
|
||||
#include "reporter.h"
|
||||
#include "fixed.h"
|
||||
#include "ac.h"
|
||||
#include "lid.h"
|
||||
#include "sb.h"
|
||||
#include "ec.h"
|
||||
|
||||
|
||||
static void init_acpica(Acpica::Reportstate *report) {
|
||||
|
||||
/* enable debugging: */
|
||||
/* AcpiDbgLevel |= ACPI_LV_IO | ACPI_LV_INTERRUPTS | ACPI_LV_INIT_NAMES; */
|
||||
|
||||
ACPI_STATUS status = AcpiInitializeSubsystem();
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeTables(nullptr, 0, true);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiLoadTables();
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeObjects(ACPI_NO_DEVICE_INIT);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Embedded controller */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C09"), Ec::detect, report, nullptr);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiUpdateAllGpes();
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
status = AcpiEnableAllRuntimeGpes();
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* note: ACPI_EVENT_PMTIMER claimed by nova kernel - not usable by us */
|
||||
Fixed * acpi_fixed = new (Genode::env()->heap()) Fixed(report);
|
||||
|
||||
status = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
|
||||
Fixed::handle_power_button,
|
||||
acpi_fixed);
|
||||
if (status != AE_OK)
|
||||
PINF("failed - power button registration - error=%u", status);
|
||||
|
||||
status = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
|
||||
Fixed::handle_sleep_button,
|
||||
acpi_fixed);
|
||||
if (status != AE_OK)
|
||||
PINF("failed - sleep button registration - error=%u", status);
|
||||
|
||||
|
||||
/* AC Adapters and Power Source Objects */
|
||||
status = AcpiGetDevices(ACPI_STRING("ACPI0003"), Ac::detect, report, nullptr);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Smart battery control devices */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C0A"), Battery::detect, report, nullptr);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* LID device */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C0D"), Lid::detect, report, nullptr);
|
||||
if (status != AE_OK) {
|
||||
PERR("%s:%u failed %u", __func__, __LINE__, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
struct Acpica::Statechange
|
||||
{
|
||||
Genode::Signal_handler<Acpica::Statechange> _dispatcher;
|
||||
Genode::Attached_rom_dataspace _system_state;
|
||||
bool _enable_reset;
|
||||
bool _enable_poweroff;
|
||||
|
||||
Statechange(Genode::Entrypoint &ep, bool reset, bool poweroff)
|
||||
:
|
||||
_dispatcher(ep, *this, &Statechange::state_changed),
|
||||
_system_state("system"),
|
||||
_enable_reset(reset), _enable_poweroff(poweroff)
|
||||
{
|
||||
_system_state.sigh(_dispatcher);
|
||||
|
||||
state_changed();
|
||||
}
|
||||
|
||||
void state_changed() {
|
||||
|
||||
_system_state.update();
|
||||
|
||||
if (!_system_state.is_valid()) return;
|
||||
|
||||
Genode::Xml_node system(_system_state.local_addr<char>(),
|
||||
_system_state.size());
|
||||
|
||||
Genode::String<32> state;
|
||||
system.attribute("state").value<32>(&state);
|
||||
|
||||
if (_enable_poweroff && state == "poweroff") {
|
||||
ACPI_STATUS res0 = AcpiEnterSleepStatePrep(5);
|
||||
ACPI_STATUS res1 = AcpiEnterSleepState(5);
|
||||
PERR("system poweroff failed - res=0x%x,0x%x", res0, res1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_enable_reset && state == "reset") {
|
||||
ACPI_STATUS res = AE_OK;
|
||||
try {
|
||||
res = AcpiReset();
|
||||
} catch (...) { }
|
||||
|
||||
Genode::uint64_t const space_addr = AcpiGbl_FADT.ResetRegister.Address;
|
||||
PERR("system reset failed - err=%x, reset=%u, spaceid=0x%x, "
|
||||
"addr=0x%llx", res,
|
||||
!!(AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER),
|
||||
AcpiGbl_FADT.ResetRegister.SpaceId, space_addr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct Acpica::Main {
|
||||
|
||||
Genode::Signal_handler<Acpica::Main> _sci_irq;
|
||||
Genode::Lazy_volatile_object<Genode::Irq_connection> _sci_conn;
|
||||
|
||||
Acpica::Reportstate * _report = nullptr;
|
||||
|
||||
static struct Irq_handler {
|
||||
UINT32 irq;
|
||||
ACPI_OSD_HANDLER handler;
|
||||
void *context;
|
||||
} irq_handler;
|
||||
|
||||
Main(Genode::Env &env)
|
||||
:
|
||||
_sci_irq(env.ep(), *this, &Main::acpi_irq)
|
||||
{
|
||||
bool enable_reset = Genode::config()->xml_node().attribute_value("reset", false);
|
||||
bool enable_poweroff = Genode::config()->xml_node().attribute_value("poweroff", false);
|
||||
bool enable_report = Genode::config()->xml_node().attribute_value("report", false);
|
||||
|
||||
if (enable_report)
|
||||
_report = new (Genode::env()->heap()) Acpica::Reportstate();
|
||||
|
||||
init_acpica(_report);
|
||||
|
||||
if (enable_report)
|
||||
_report->enable();
|
||||
|
||||
if (enable_reset || enable_poweroff)
|
||||
new (Genode::env()->heap()) Acpica::Statechange(env.ep(), enable_reset,
|
||||
enable_poweroff);
|
||||
|
||||
/* setup IRQ */
|
||||
if (irq_handler.handler) {
|
||||
_sci_conn.construct(irq_handler.irq);
|
||||
|
||||
PINF("SCI IRQ: %u", irq_handler.irq);
|
||||
|
||||
_sci_conn->sigh(_sci_irq);
|
||||
_sci_conn->ack_irq();
|
||||
} else
|
||||
PWRN("no IRQ handling available");
|
||||
|
||||
}
|
||||
|
||||
void acpi_irq()
|
||||
{
|
||||
if (!irq_handler.handler)
|
||||
return;
|
||||
|
||||
UINT32 res = irq_handler.handler(irq_handler.context);
|
||||
|
||||
_sci_conn->ack_irq();
|
||||
|
||||
AcpiOsWaitEventsComplete();
|
||||
|
||||
if (_report)
|
||||
_report->generate_report();
|
||||
|
||||
if (res == ACPI_INTERRUPT_HANDLED)
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
struct Acpica::Main::Irq_handler Acpica::Main::irq_handler;
|
||||
|
||||
|
||||
ACPI_STATUS AcpiOsInstallInterruptHandler(UINT32 irq, ACPI_OSD_HANDLER handler,
|
||||
void *context)
|
||||
{
|
||||
Acpica::Main::irq_handler.irq = irq;
|
||||
Acpica::Main::irq_handler.handler = handler;
|
||||
Acpica::Main::irq_handler.context = context;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 4*1024*sizeof(Genode::addr_t); }
|
||||
void Component::construct(Genode::Env &env) { static Acpica::Main main(env); }
|
17
repos/libports/src/app/acpica/printf.cc
Normal file
17
repos/libports/src/app/acpica/printf.cc
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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"
|
||||
void AcpiOsPrintf (const char *fmt, ...)
|
||||
{ }
|
||||
|
||||
extern "C"
|
||||
void AcpiOsVprintf (const char *fmt, va_list va)
|
||||
{ }
|
||||
|
109
repos/libports/src/app/acpica/reporter.h
Normal file
109
repos/libports/src/app/acpica/reporter.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* \brief Generate xml reports of various ACPI devices, e.g.
|
||||
* Lid, Embedded Controller (EC), AC Adapter,
|
||||
* Smart Battery (SB) and ACPI fixed events (power, sleep button)
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
class Ac;
|
||||
class Battery;
|
||||
class Ec;
|
||||
class Fixed;
|
||||
class Lid;
|
||||
|
||||
class Acpica::Reportstate {
|
||||
|
||||
private:
|
||||
|
||||
Genode::Reporter _reporter_lid { "acpi_lid" };
|
||||
Genode::Reporter _reporter_ac { "acpi_ac" };
|
||||
Genode::Reporter _reporter_sb { "acpi_battery" };
|
||||
Genode::Reporter _reporter_ec { "acpi_ec" };
|
||||
Genode::Reporter _reporter_fix { "acpi_fixed" };
|
||||
|
||||
bool _changed_lid = false;
|
||||
bool _changed_ac = false;
|
||||
bool _changed_sb = false;
|
||||
bool _changed_ec = false;
|
||||
bool _changed_fixed = false;
|
||||
|
||||
Genode::List<Callback<Battery> > _list_sb;
|
||||
Genode::List<Callback<Ec> > _list_ec;
|
||||
Genode::List<Callback<Ac> > _list_ac;
|
||||
Callback<Fixed> * _fixed;
|
||||
Callback<Lid> * _lid;
|
||||
|
||||
public:
|
||||
|
||||
Reportstate() { }
|
||||
|
||||
void add_notify(Acpica::Callback<Battery> * s) { _list_sb.insert(s); }
|
||||
void add_notify(Acpica::Callback<Fixed> * f) { _fixed = f; }
|
||||
void add_notify(Acpica::Callback<Lid> * l) { _lid = l; }
|
||||
void add_notify(Acpica::Callback<Ec> * e) { _list_ec.insert(e); }
|
||||
void add_notify(Acpica::Callback<Ac> * a) { _list_ac.insert(a); }
|
||||
|
||||
void enable() {
|
||||
_reporter_ac.enabled(true);
|
||||
_reporter_ec.enabled(true);
|
||||
_reporter_sb.enabled(true);
|
||||
_reporter_lid.enabled(true);
|
||||
_reporter_fix.enabled(true);
|
||||
}
|
||||
|
||||
void battery_event() { _changed_sb = true; }
|
||||
void ec_event() { _changed_ec = true; }
|
||||
void fixed_event() { _changed_fixed = true; }
|
||||
void lid_event() { _changed_lid = true; }
|
||||
void ac_event() { _changed_ac = true; battery_event(); }
|
||||
|
||||
void generate_report()
|
||||
{
|
||||
if (_changed_lid) {
|
||||
_changed_lid = false;
|
||||
if (_lid)
|
||||
Genode::Reporter::Xml_generator xml(_reporter_lid, [&] () {
|
||||
_lid->generate(xml);
|
||||
});
|
||||
}
|
||||
|
||||
if (_changed_ac) {
|
||||
_changed_ac = false;
|
||||
Genode::Reporter::Xml_generator xml(_reporter_ac, [&] () {
|
||||
for (Callback<Ac> * ac = _list_ac.first(); ac; ac = ac->next())
|
||||
xml.node("ac", [&] { ac->generate(xml); });
|
||||
});
|
||||
}
|
||||
|
||||
if (_changed_ec) {
|
||||
_changed_ec = false;
|
||||
Genode::Reporter::Xml_generator xml(_reporter_ec, [&] () {
|
||||
for (Callback<Ec> * ec = _list_ec.first(); ec; ec = ec->next())
|
||||
xml.node("ec", [&] { ec->generate(xml); });
|
||||
});
|
||||
}
|
||||
|
||||
if (_changed_sb) {
|
||||
_changed_sb = false;
|
||||
Genode::Reporter::Xml_generator xml(_reporter_sb, [&] () {
|
||||
for (Callback<Battery> * sb = _list_sb.first(); sb; sb = sb->next())
|
||||
xml.node("sb", [&] { sb->generate(xml); });
|
||||
});
|
||||
}
|
||||
|
||||
if (_changed_fixed) {
|
||||
_changed_fixed = false;
|
||||
if (_fixed)
|
||||
Genode::Reporter::Xml_generator xml(_reporter_fix, [&] () {
|
||||
_fixed->generate(xml);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
227
repos/libports/src/app/acpica/sb.h
Normal file
227
repos/libports/src/app/acpica/sb.h
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* \brief Handle ACPI Smart Battery Subsystem devices
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
class Battery : Acpica::Callback<Battery> {
|
||||
|
||||
private:
|
||||
|
||||
Acpica::Reportstate * _report;
|
||||
ACPI_HANDLE _sb;
|
||||
|
||||
public:
|
||||
|
||||
Battery(void * report, ACPI_HANDLE sb)
|
||||
: _report(reinterpret_cast<Acpica::Reportstate *>(report)), _sb(sb)
|
||||
{
|
||||
if (_report)
|
||||
_report->add_notify(this);
|
||||
}
|
||||
|
||||
void handle(ACPI_HANDLE sb, UINT32 value)
|
||||
{
|
||||
if (_report)
|
||||
_report->battery_event();
|
||||
}
|
||||
|
||||
static ACPI_STATUS detect(ACPI_HANDLE sb, UINT32, void *report, void **)
|
||||
{
|
||||
Battery * dev_obj = new (Genode::env()->heap()) Battery(report, sb);
|
||||
|
||||
ACPI_STATUS res = AcpiInstallNotifyHandler (sb, ACPI_DEVICE_NOTIFY,
|
||||
handler, dev_obj);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' res=0x%x", __func__, res);
|
||||
delete dev_obj;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
Acpica::Buffer<char [8]> battery_name;
|
||||
AcpiGetName (sb, ACPI_SINGLE_NAME, &battery_name);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' battery name res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
Acpica::Buffer<ACPI_OBJECT> sta;
|
||||
res = AcpiEvaluateObjectTyped(sb, ACPI_STRING("_STA"), nullptr, &sta,
|
||||
ACPI_TYPE_INTEGER);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
PERR("failed - '%s' _STA res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/* ACPI spec - 10.2.2.1 _BIF (Battery Information) */
|
||||
Acpica::Buffer<char [512]> battery;
|
||||
res = AcpiEvaluateObjectTyped(sb, ACPI_STRING("_BIF"),
|
||||
nullptr, &battery,
|
||||
ACPI_TYPE_PACKAGE);
|
||||
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(battery.object);
|
||||
if (ACPI_FAILURE(res) || !obj) {
|
||||
PERR("failed - '%s' _BIF res=0x%x", __func__, res);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
unsigned long long const val = sta.object.Integer.Value;
|
||||
|
||||
if (obj->Package.Count < 13 ||
|
||||
obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
|
||||
obj->Package.Elements[12].Type != ACPI_TYPE_STRING ||
|
||||
obj->Package.Elements[11].Type != ACPI_TYPE_STRING ||
|
||||
obj->Package.Elements[10].Type != ACPI_TYPE_STRING ||
|
||||
obj->Package.Elements[9].Type != ACPI_TYPE_STRING)
|
||||
{
|
||||
PINF("detected - battery '%s' - unknown state (0x%llx%s)",
|
||||
battery_name.object, val,
|
||||
val & ACPI_STA_BATTERY_PRESENT ? "" : "(not present)");
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
PINF("detected - battery '%s' type='%s' OEM='%s' state=0x%llx%s "
|
||||
"model='%s' serial='%s'",
|
||||
battery_name.object,
|
||||
obj->Package.Elements[11].String.Pointer,
|
||||
obj->Package.Elements[12].String.Pointer,
|
||||
val, val & ACPI_STA_BATTERY_PRESENT ? "" : "(not present)",
|
||||
obj->Package.Elements[10].String.Pointer,
|
||||
obj->Package.Elements[9].String.Pointer);
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml)
|
||||
{
|
||||
info(xml);
|
||||
status(xml);
|
||||
}
|
||||
|
||||
void info(Genode::Xml_generator &xml)
|
||||
{
|
||||
/* ACPI spec - 10.2.2.1 _BIF (Battery Information) */
|
||||
Acpica::Buffer<char [512]> battery;
|
||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BIF"),
|
||||
nullptr, &battery,
|
||||
ACPI_TYPE_PACKAGE);
|
||||
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(battery.object);
|
||||
if (ACPI_FAILURE(res) || !obj || obj->Package.Count != 13) {
|
||||
PERR("failed - '%s' _BIF res=0x%x", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
Acpica::Buffer<char [8]> battery_name;
|
||||
AcpiGetName (_sb, ACPI_SINGLE_NAME, &battery_name);
|
||||
if (ACPI_FAILURE(res))
|
||||
xml.node("name", [&] { xml.append("unknown"); });
|
||||
else
|
||||
xml.node("name", [&] { xml.append(battery_name.object); });
|
||||
|
||||
const char * node_name[] = {
|
||||
"powerunit", "design_capacity", "last_full_capacity",
|
||||
"technology", "voltage", "warning_capacity", "low_capacity",
|
||||
"granularity1", "granularity2", "serial", "model", "type",
|
||||
"oem"
|
||||
};
|
||||
|
||||
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < 9; i++) {
|
||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||
|
||||
xml.node(node_name[i], [&] {
|
||||
if (v->Type != ACPI_TYPE_INTEGER) {
|
||||
xml.append("unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
xml.attribute("value", v->Integer.Value);
|
||||
|
||||
if (i == 0)
|
||||
xml.append(v->Integer.Value == 0 ? "mW/mWh" :
|
||||
v->Integer.Value == 1 ? "mA/mAh" :
|
||||
"unknown");
|
||||
if (i == 3)
|
||||
xml.append(v->Integer.Value == 0 ? "primary" :
|
||||
v->Integer.Value == 1 ? "secondary" :
|
||||
"unknown");
|
||||
});
|
||||
}
|
||||
|
||||
for (unsigned i = 9; i < obj->Package.Count; i++) {
|
||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||
|
||||
xml.node(node_name[i], [&] {
|
||||
|
||||
if (v->Type != ACPI_TYPE_STRING)
|
||||
return;
|
||||
|
||||
xml.append(v->String.Pointer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void status(Genode::Xml_generator &xml)
|
||||
{
|
||||
/* 10.2.2.6 _BST (Battery Status) */
|
||||
Acpica::Buffer<char [256]> dynamic;
|
||||
ACPI_STATUS res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_BST"),
|
||||
nullptr, &dynamic,
|
||||
ACPI_TYPE_PACKAGE);
|
||||
ACPI_OBJECT * obj = reinterpret_cast<ACPI_OBJECT *>(dynamic.object);
|
||||
if (ACPI_FAILURE(res) || !obj ||
|
||||
obj->Package.Count != 4) {
|
||||
PERR("failed - '%s' _BST res=0x%x", __func__, res);
|
||||
return;
|
||||
}
|
||||
|
||||
Acpica::Buffer<ACPI_OBJECT> sta;
|
||||
res = AcpiEvaluateObjectTyped(_sb, ACPI_STRING("_STA"), nullptr,
|
||||
&sta, ACPI_TYPE_INTEGER);
|
||||
if (ACPI_FAILURE(res)) {
|
||||
xml.node("status", [&] { xml.append("unknown"); });
|
||||
} else
|
||||
xml.node("status", [&] {
|
||||
xml.attribute("value", sta.object.Integer.Value);
|
||||
/* see "6.3.7 _STA" for more human readable decoding */
|
||||
if (!(sta.object.Integer.Value & ACPI_STA_BATTERY_PRESENT))
|
||||
xml.append("battery not present");
|
||||
});
|
||||
|
||||
const char * node_name[] = {
|
||||
"state", "present_rate", "remaining_capacity",
|
||||
"present_voltage"
|
||||
};
|
||||
|
||||
if (sizeof(node_name) / sizeof(node_name[0]) != obj->Package.Count)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < obj->Package.Count; i++) {
|
||||
ACPI_OBJECT * v = &obj->Package.Elements[i];
|
||||
|
||||
xml.node(node_name[i], [&] {
|
||||
if (v->Type != ACPI_TYPE_INTEGER) {
|
||||
xml.append("unknown");
|
||||
return;
|
||||
}
|
||||
|
||||
xml.attribute("value", v->Integer.Value);
|
||||
|
||||
if (i != 0)
|
||||
return;
|
||||
|
||||
if (v->Integer.Value & 0x1) xml.append("discharging");
|
||||
if (v->Integer.Value & 0x2) xml.append("charging");
|
||||
if (v->Integer.Value & 0x4) xml.append("critical low");
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
8
repos/libports/src/app/acpica/target.inc
Normal file
8
repos/libports/src/app/acpica/target.inc
Normal file
@ -0,0 +1,8 @@
|
||||
REQUIRES := x86
|
||||
|
||||
LIBS += base acpica config
|
||||
|
||||
CC_OPT += -Wno-unused-function -Wno-unused-variable
|
||||
CC_C_OPT += -DACPI_LIBRARY
|
||||
|
||||
INC_DIR += $(call select_from_ports,acpica)/src/lib/acpica/source/include
|
4
repos/libports/src/app/acpica/target.mk
Normal file
4
repos/libports/src/app/acpica/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = acpica
|
||||
SRC_CC = os.cc printf.cc
|
||||
|
||||
include $(PRG_DIR)/target.inc
|
31
repos/libports/src/app/acpica/util.h
Normal file
31
repos/libports/src/app/acpica/util.h
Normal file
@ -0,0 +1,31 @@
|
||||
namespace Acpica {
|
||||
template<typename> class Buffer;
|
||||
template<typename> class Callback;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class Acpica::Buffer : public ACPI_BUFFER
|
||||
{
|
||||
public:
|
||||
T object;
|
||||
Buffer() {
|
||||
Pointer = &object;
|
||||
Length = sizeof(object);
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
template <typename T>
|
||||
class Acpica::Callback : public Genode::List<Acpica::Callback<T> >::Element
|
||||
{
|
||||
public:
|
||||
|
||||
static void handler(ACPI_HANDLE h, UINT32 value, void * context)
|
||||
{
|
||||
reinterpret_cast<T *>(context)->handle(h, value);
|
||||
}
|
||||
|
||||
void generate(Genode::Xml_generator &xml) {
|
||||
reinterpret_cast<T *>(this)->generate(xml);
|
||||
}
|
||||
};
|
76
repos/libports/src/lib/acpica/acpica.patch
Normal file
76
repos/libports/src/lib/acpica/acpica.patch
Normal file
@ -0,0 +1,76 @@
|
||||
+++ src/lib/acpica/source/include/platform/acenv.h
|
||||
@@ -222,7 +222,15 @@
|
||||
|
||||
/* Unknown environment */
|
||||
|
||||
-#error Unknown target environment
|
||||
+#ifdef __x86_64__
|
||||
+#define ACPI_MACHINE_WIDTH 64
|
||||
+#else
|
||||
+#define ACPI_MACHINE_WIDTH 32
|
||||
+#define ACPI_USE_NATIVE_DIVIDE
|
||||
+#endif
|
||||
+
|
||||
+/* required for va_arg - otherwise below some alternative is defined */
|
||||
+#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
/*! [End] no source code translation !*/
|
||||
+++ src/lib/acpica/source/components/events/evevent.c
|
||||
@@ -188,6 +188,9 @@
|
||||
UINT32 i;
|
||||
ACPI_STATUS Status;
|
||||
|
||||
+ /* read enabled events by kernel and don't disable them */
|
||||
+ UINT32 FixedEnable;
|
||||
+ (void) AcpiHwRegisterRead (ACPI_REGISTER_PM1_ENABLE, &FixedEnable);
|
||||
|
||||
/*
|
||||
* Initialize the structure that keeps track of fixed event handlers and
|
||||
@@ -198,6 +201,12 @@
|
||||
AcpiGbl_FixedEventHandlers[i].Handler = NULL;
|
||||
AcpiGbl_FixedEventHandlers[i].Context = NULL;
|
||||
|
||||
+ if (FixedEnable & AcpiGbl_FixedEventInfo[i].EnableBitMask)
|
||||
+ {
|
||||
+ AcpiOsPrintf (" Genode: SKIP disabling event '%u'(%x) - enabled by kernel!\n", i, AcpiGbl_FixedEventInfo[i].EnableBitMask);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
/* Disable the fixed event */
|
||||
|
||||
if (AcpiGbl_FixedEventInfo[i].EnableRegisterId != 0xFF)
|
||||
@@ -257,10 +266,13 @@
|
||||
*/
|
||||
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++)
|
||||
{
|
||||
- /* Both the status and enable bits must be on for this event */
|
||||
-
|
||||
- if ((FixedStatus & AcpiGbl_FixedEventInfo[i].StatusBitMask) &&
|
||||
- (FixedEnable & AcpiGbl_FixedEventInfo[i].EnableBitMask))
|
||||
+ /* kernel 'signals' the fixed event by disabling it in the enable
|
||||
+ * register. Check for events, that have registered handlers and that
|
||||
+ * are disabled in the enable register. If found, re-enable event.
|
||||
+ */
|
||||
+ if (AcpiGbl_FixedEventInfo[i].EnableBitMask &&
|
||||
+ AcpiGbl_FixedEventHandlers[i].Handler &&
|
||||
+ !(FixedEnable & AcpiGbl_FixedEventInfo[i].EnableBitMask))
|
||||
{
|
||||
/*
|
||||
* Found an active (signalled) event. Invoke global event
|
||||
@@ -303,12 +315,10 @@
|
||||
|
||||
ACPI_FUNCTION_ENTRY ();
|
||||
|
||||
-
|
||||
- /* Clear the status bit */
|
||||
-
|
||||
+ /* Re-enable event - kernel disabled it */
|
||||
(void) AcpiWriteBitRegister (
|
||||
- AcpiGbl_FixedEventInfo[Event].StatusRegisterId,
|
||||
- ACPI_CLEAR_STATUS);
|
||||
+ AcpiGbl_FixedEventInfo[Event].EnableRegisterId,
|
||||
+ ACPI_ENABLE_EVENT);
|
||||
|
||||
/*
|
||||
* Make sure that a handler exists. If not, report an error
|
291
repos/libports/src/lib/acpica/iomem.cc
Normal file
291
repos/libports/src/lib/acpica/iomem.cc
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* \brief I/O memory backend for ACPICA library
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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>
|
||||
#include <base/env.h>
|
||||
#include <util/misc_math.h>
|
||||
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <rm_session/connection.h>
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
#include "acpiosxf.h"
|
||||
}
|
||||
|
||||
#define FAIL(retval) \
|
||||
{ \
|
||||
PERR("%s:%u called - dead", __func__, __LINE__); \
|
||||
Genode::Lock lock; \
|
||||
while (1) lock.lock(); \
|
||||
return retval; \
|
||||
}
|
||||
|
||||
namespace Acpica {
|
||||
class Io_mem;
|
||||
};
|
||||
|
||||
class Acpica::Io_mem
|
||||
{
|
||||
private:
|
||||
|
||||
ACPI_PHYSICAL_ADDRESS _phys;
|
||||
ACPI_SIZE _size;
|
||||
Genode::uint8_t * _virt;
|
||||
Genode::Io_mem_session_capability _io_mem;
|
||||
unsigned _ref;
|
||||
|
||||
static Acpica::Io_mem _ios[16];
|
||||
|
||||
public:
|
||||
|
||||
bool valid() const { return _io_mem.valid(); }
|
||||
bool refs() const { return _ref != ~0U; }
|
||||
bool contains_virt (const Genode::uint8_t * v, const ACPI_SIZE s) const
|
||||
{
|
||||
return _virt <= v && v + s <= _virt + _size;
|
||||
}
|
||||
bool contains_phys (const ACPI_PHYSICAL_ADDRESS p, const ACPI_SIZE s) const
|
||||
{
|
||||
return _phys <= p && p + s <= _phys + _size;
|
||||
}
|
||||
|
||||
Genode::addr_t to_virt(ACPI_PHYSICAL_ADDRESS p) {
|
||||
_ref ++;
|
||||
return reinterpret_cast<Genode::addr_t>(_virt + (p - _phys));
|
||||
}
|
||||
|
||||
bool ref_dec() { return --_ref; }
|
||||
|
||||
template <typename FUNC>
|
||||
static void apply_to_all(FUNC const &func = [] () { } )
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_ios) / sizeof(_ios[0]); i++)
|
||||
func(_ios[i]);
|
||||
}
|
||||
|
||||
void invalidate(ACPI_SIZE s)
|
||||
{
|
||||
if (_io_mem.valid() && refs())
|
||||
Genode::env()->parent()->close(_io_mem);
|
||||
|
||||
ACPI_PHYSICAL_ADDRESS const p = _phys;
|
||||
|
||||
_phys = _size = 0;
|
||||
_virt = nullptr;
|
||||
_io_mem = Genode::Io_mem_session_capability();
|
||||
|
||||
if (refs())
|
||||
return;
|
||||
|
||||
_ref = 0;
|
||||
|
||||
/**
|
||||
* Continue in order to look for the larger entry that replaced
|
||||
* this one. Required to decrement ref count.
|
||||
*/
|
||||
apply_to_all([&] (Acpica::Io_mem &io_mem) {
|
||||
if (!io_mem.contains_phys(p, s) || !io_mem.refs())
|
||||
return;
|
||||
|
||||
if (io_mem.ref_dec())
|
||||
return;
|
||||
|
||||
io_mem.invalidate(s);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename FUNC>
|
||||
static Genode::addr_t apply_u(FUNC const &func = [] () { } )
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_ios) / sizeof(_ios[0]); i++)
|
||||
{
|
||||
Genode::addr_t r = func(_ios[i]);
|
||||
if (r) return r;
|
||||
}
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
template <typename FUNC>
|
||||
static Acpica::Io_mem * apply_p(FUNC const &func = [] () { } )
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(_ios) / sizeof(_ios[0]); i++)
|
||||
{
|
||||
Acpica::Io_mem * r = func(_ios[i]);
|
||||
if (r) return r;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Acpica::Io_mem * allocate(ACPI_PHYSICAL_ADDRESS p, ACPI_SIZE s,
|
||||
unsigned r)
|
||||
{
|
||||
return Acpica::Io_mem::apply_p([&] (Acpica::Io_mem &io_mem) {
|
||||
if (io_mem.valid())
|
||||
return reinterpret_cast<Acpica::Io_mem *>(0);
|
||||
|
||||
io_mem._phys = p & ~0xFFFUL;
|
||||
io_mem._size = Genode::align_addr(p + s - io_mem._phys, 12);
|
||||
io_mem._ref = r;
|
||||
io_mem._virt = 0;
|
||||
|
||||
Genode::Io_mem_connection io(io_mem._phys, io_mem._size);
|
||||
io.on_destruction(Genode::Io_mem_connection::KEEP_OPEN);
|
||||
io_mem._io_mem = io;
|
||||
|
||||
return &io_mem;
|
||||
});
|
||||
}
|
||||
|
||||
static Genode::addr_t insert(ACPI_PHYSICAL_ADDRESS p, ACPI_SIZE s)
|
||||
{
|
||||
Acpica::Io_mem * io_mem = allocate(p, s, 1);
|
||||
if (!io_mem)
|
||||
return 0UL;
|
||||
|
||||
io_mem->_virt = Genode::env()->rm_session()->attach(Genode::Io_mem_session_client(io_mem->_io_mem).dataspace(), io_mem->_size);
|
||||
|
||||
return reinterpret_cast<Genode::addr_t>(io_mem->_virt);
|
||||
}
|
||||
|
||||
Genode::addr_t pre_expand(ACPI_PHYSICAL_ADDRESS p, ACPI_SIZE s)
|
||||
{
|
||||
Genode::env()->parent()->close(_io_mem);
|
||||
|
||||
Genode::addr_t xsize = _phys - p + _size;
|
||||
if (!allocate(p, xsize, _ref))
|
||||
FAIL(0)
|
||||
|
||||
return _expand(p, s);
|
||||
}
|
||||
|
||||
Genode::addr_t post_expand(ACPI_PHYSICAL_ADDRESS p, ACPI_SIZE s)
|
||||
{
|
||||
Genode::env()->parent()->close(_io_mem);
|
||||
|
||||
ACPI_SIZE xsize = p + s - _phys;
|
||||
if (!allocate(_phys, xsize, _ref))
|
||||
FAIL(0)
|
||||
|
||||
return _expand(p, s);
|
||||
}
|
||||
|
||||
Genode::addr_t _expand(ACPI_PHYSICAL_ADDRESS const p, ACPI_SIZE const s)
|
||||
{
|
||||
/* mark this element as a stale reference */
|
||||
_ref = ~0U;
|
||||
|
||||
/* find new created entry */
|
||||
Genode::addr_t res = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
|
||||
if (!io_mem.valid() || !io_mem.refs() ||
|
||||
!io_mem.contains_phys(p, s))
|
||||
return 0UL;
|
||||
|
||||
Genode::Io_mem_dataspace_capability const io_ds = Genode::Io_mem_session_client(io_mem._io_mem).dataspace();
|
||||
|
||||
/* re-attach mem of stale entries partially using this iomem */
|
||||
unsigned stale_count = 0;
|
||||
Acpica::Io_mem::apply_to_all([&] (Acpica::Io_mem &io2) {
|
||||
if (!io2.valid() || !io_mem.contains_phys(io2._phys, 0))
|
||||
return;
|
||||
|
||||
if (io2.refs())
|
||||
return;
|
||||
|
||||
Genode::addr_t off_phys = io2._phys - io_mem._phys;
|
||||
stale_count ++;
|
||||
|
||||
io2._io_mem = io_mem._io_mem;
|
||||
Genode::addr_t virt = reinterpret_cast<Genode::addr_t>(io2._virt);
|
||||
|
||||
Genode::env()->rm_session()->attach_at(io_ds, virt,
|
||||
io2._size, off_phys);
|
||||
});
|
||||
|
||||
/**
|
||||
* In case the old *this* entry was solely a placeholder for
|
||||
* other stale entries, the new one *io_mem* becomes just
|
||||
* a placeholder too -> meaning ref must be increased by 1.
|
||||
*/
|
||||
if (io_mem._ref == stale_count)
|
||||
io_mem._ref ++;
|
||||
|
||||
if (io_mem._virt)
|
||||
FAIL(0UL);
|
||||
|
||||
/* attach whole memory */
|
||||
io_mem._virt = Genode::env()->rm_session()->attach(io_ds);
|
||||
|
||||
return io_mem.to_virt(p);
|
||||
});
|
||||
|
||||
/* should never happen */
|
||||
if (!res)
|
||||
FAIL(0)
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
Acpica::Io_mem Acpica::Io_mem::_ios[16];
|
||||
|
||||
|
||||
void * AcpiOsMapMemory (ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size)
|
||||
{
|
||||
Genode::addr_t virt = Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
|
||||
if (!io_mem.valid() || !io_mem.refs())
|
||||
return 0UL;
|
||||
|
||||
if (io_mem.contains_phys(phys, size))
|
||||
/* we have already a mapping in which the request fits */
|
||||
return io_mem.to_virt(phys);
|
||||
|
||||
if (io_mem.contains_phys(phys + 1, 0))
|
||||
/* phys is within region but end is outside region */
|
||||
return io_mem.post_expand(phys, size);
|
||||
|
||||
if (io_mem.contains_phys(phys + size - 1, 0))
|
||||
/* phys starts before region and end is within region */
|
||||
return io_mem.pre_expand(phys, size);
|
||||
|
||||
return 0UL;
|
||||
});
|
||||
|
||||
if (virt)
|
||||
return reinterpret_cast<void *>(virt);
|
||||
|
||||
virt= Acpica::Io_mem::insert(phys, size);
|
||||
if (virt)
|
||||
return reinterpret_cast<void *>(virt + (phys & 0xfffU));
|
||||
|
||||
FAIL(nullptr)
|
||||
}
|
||||
|
||||
void AcpiOsUnmapMemory (void * ptr, ACPI_SIZE size)
|
||||
{
|
||||
Genode::uint8_t const * virt = reinterpret_cast<Genode::uint8_t *>(ptr);
|
||||
|
||||
if (Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
|
||||
if (!io_mem.valid() || !io_mem.contains_virt(virt, size))
|
||||
return 0;
|
||||
|
||||
if (io_mem.refs() && io_mem.ref_dec())
|
||||
return 1;
|
||||
|
||||
io_mem.invalidate(size);
|
||||
return 1;
|
||||
}))
|
||||
return;
|
||||
|
||||
FAIL()
|
||||
}
|
289
repos/libports/src/lib/acpica/osl.cc
Normal file
289
repos/libports/src/lib/acpica/osl.cc
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* \brief OS specific backend for ACPICA library
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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>
|
||||
#include <base/env.h>
|
||||
#include <util/misc_math.h>
|
||||
|
||||
#include <io_port_session/connection.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
#include "acpiosxf.h"
|
||||
}
|
||||
|
||||
#define FAIL(retval) \
|
||||
{ \
|
||||
PERR("%s:%u called - dead", __func__, __LINE__); \
|
||||
Genode::Lock lock; \
|
||||
while (1) lock.lock(); \
|
||||
return retval; \
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsPredefinedOverride (const ACPI_PREDEFINED_NAMES *pre,
|
||||
ACPI_STRING *newobj)
|
||||
{
|
||||
*newobj = nullptr;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
|
||||
void * AcpiOsAllocate (ACPI_SIZE size) {
|
||||
return Genode::env()->heap()->alloc(size); }
|
||||
|
||||
|
||||
void AcpiOsFree (void *ptr)
|
||||
{
|
||||
if (Genode::env()->heap()->need_size_for_free())
|
||||
PWRN("%s called - warning - ptr=%p", __func__, ptr);
|
||||
|
||||
Genode::env()->heap()->free(ptr, 0);
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsCreateLock (ACPI_SPINLOCK *spin_lock)
|
||||
{
|
||||
*spin_lock = new (Genode::env()->heap()) Genode::Lock();
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_CPU_FLAGS AcpiOsAcquireLock (ACPI_SPINLOCK h)
|
||||
{
|
||||
Genode::Lock *lock = reinterpret_cast<Genode::Lock *>(h);
|
||||
lock->lock();
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
void AcpiOsReleaseLock (ACPI_SPINLOCK h, ACPI_CPU_FLAGS flags)
|
||||
{
|
||||
Genode::Lock *lock = reinterpret_cast<Genode::Lock *>(h);
|
||||
|
||||
if (flags != AE_OK)
|
||||
PWRN("warning - unknown flags in %s", __func__);
|
||||
|
||||
lock->unlock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsCreateSemaphore (UINT32 max, UINT32 initial,
|
||||
ACPI_SEMAPHORE *sem)
|
||||
{
|
||||
*sem = new (Genode::env()->heap()) Genode::Semaphore(initial);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsWaitSemaphore(ACPI_SEMAPHORE h, UINT32 units,
|
||||
UINT16 timeout_ms)
|
||||
{
|
||||
Genode::Semaphore *sem = reinterpret_cast<Genode::Semaphore *>(h);
|
||||
|
||||
if (!units)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
/**
|
||||
* Timeouts not supported yet ...
|
||||
* == 0 means - try and don't block - we're single threaded - ignore
|
||||
* == 0xfff means - wait endless - fine
|
||||
*/
|
||||
if (0 < timeout_ms && timeout_ms < 0xffff)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
/* timeout == forever case */
|
||||
while (units) {
|
||||
sem->down();
|
||||
units--;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsSignalSemaphore (ACPI_SEMAPHORE h, UINT32 units)
|
||||
{
|
||||
Genode::Semaphore *sem = reinterpret_cast<Genode::Semaphore *>(h);
|
||||
|
||||
while (units) {
|
||||
sem->up();
|
||||
units--;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsDeleteSemaphore (ACPI_SEMAPHORE)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
ACPI_THREAD_ID AcpiOsGetThreadId (void) {
|
||||
return reinterpret_cast<Genode::addr_t>(Genode::Thread::myself()); }
|
||||
|
||||
ACPI_STATUS AcpiOsTableOverride (ACPI_TABLE_HEADER *x, ACPI_TABLE_HEADER **y)
|
||||
{
|
||||
*y = nullptr;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsPhysicalTableOverride (ACPI_TABLE_HEADER *x,
|
||||
ACPI_PHYSICAL_ADDRESS *y, UINT32 *z)
|
||||
{
|
||||
*y = 0;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsReadPort (ACPI_IO_ADDRESS port, UINT32 *value, UINT32 width)
|
||||
{
|
||||
if (width % 8 != 0)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
/* the I/O port may be owned by drivers, which will cause exceptions */
|
||||
try {
|
||||
unsigned const bytes = width / 8;
|
||||
Genode::Io_port_connection io_port(port, bytes);
|
||||
|
||||
switch (bytes) {
|
||||
case 1 :
|
||||
*value = io_port.inb(port);
|
||||
break;
|
||||
case 2 :
|
||||
*value = io_port.inw(port);
|
||||
break;
|
||||
case 4 :
|
||||
*value = io_port.inl(port);
|
||||
break;
|
||||
default:
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
}
|
||||
} catch (Genode::Parent::Service_denied) {
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsWritePort (ACPI_IO_ADDRESS port, UINT32 value, UINT32 width)
|
||||
{
|
||||
if (width % 8 != 0)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
/* the I/O port may be owned by drivers, which will cause exceptions */
|
||||
try {
|
||||
unsigned const bytes = width / 8;
|
||||
Genode::Io_port_connection io_port(port, bytes);
|
||||
|
||||
switch (bytes) {
|
||||
case 1 :
|
||||
io_port.outb(port, value);
|
||||
break;
|
||||
case 2 :
|
||||
io_port.outw(port, value);
|
||||
break;
|
||||
case 4 :
|
||||
io_port.outl(port, value);
|
||||
break;
|
||||
default:
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
}
|
||||
} catch (Genode::Parent::Service_denied) {
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static struct {
|
||||
ACPI_EXECUTE_TYPE type;
|
||||
ACPI_OSD_EXEC_CALLBACK func;
|
||||
void *context;
|
||||
} deferred[8];
|
||||
|
||||
ACPI_STATUS AcpiOsExecute(ACPI_EXECUTE_TYPE type, ACPI_OSD_EXEC_CALLBACK func,
|
||||
void *context)
|
||||
{
|
||||
if (type == OSL_GPE_HANDLER) {
|
||||
func(context);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
if (type != OSL_NOTIFY_HANDLER)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
for (unsigned i = 0; i < sizeof(deferred) / sizeof (deferred[0]); i++) {
|
||||
if (deferred[i].func)
|
||||
continue;
|
||||
|
||||
deferred[i].type = type;
|
||||
deferred[i].func = func;
|
||||
deferred[i].context = context;
|
||||
return AE_OK;
|
||||
}
|
||||
PERR("Queue full for deferred handlers");
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
void AcpiOsWaitEventsComplete()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(deferred) / sizeof (deferred[0]); i++) {
|
||||
if (!deferred[i].func)
|
||||
continue;
|
||||
|
||||
ACPI_OSD_EXEC_CALLBACK func = deferred[i].func;
|
||||
deferred[i].func = nullptr;
|
||||
|
||||
func(deferred[i].context);
|
||||
}
|
||||
}
|
||||
|
||||
void AcpiOsSleep (UINT64 sleep_ms)
|
||||
{
|
||||
PDBG("%s %llu ms", __func__, sleep_ms);
|
||||
|
||||
static Timer::Connection conn;
|
||||
conn.msleep(sleep_ms);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
* unsupported/unused functions *
|
||||
********************************/
|
||||
|
||||
ACPI_STATUS AcpiOsSignal (UINT32, void *)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
UINT64 AcpiOsGetTimer (void)
|
||||
FAIL(0)
|
||||
|
||||
void AcpiOsStall (UINT32)
|
||||
FAIL()
|
||||
|
||||
ACPI_STATUS AcpiOsReadMemory (ACPI_PHYSICAL_ADDRESS, UINT64 *, UINT32)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
ACPI_STATUS AcpiOsWriteMemory (ACPI_PHYSICAL_ADDRESS, UINT64, UINT32)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
ACPI_STATUS AcpiOsRemoveInterruptHandler (UINT32, ACPI_OSD_HANDLER)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
ACPI_STATUS AcpiOsGetLine (char *, UINT32, UINT32 *)
|
||||
FAIL(AE_BAD_PARAMETER)
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void AcpiAhMatchUuid() FAIL()
|
||||
void AcpiAhMatchHardwareId() FAIL()
|
||||
void AcpiDbCommandDispatch() FAIL()
|
||||
void AcpiDbSetOutputDestination() FAIL()
|
||||
void MpSaveSerialInfo() FAIL()
|
||||
void MpSaveGpioInfo() FAIL()
|
||||
}
|
137
repos/libports/src/lib/acpica/pci.cc
Normal file
137
repos/libports/src/lib/acpica/pci.cc
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* \brief PCI specific backend for ACPICA library
|
||||
* \author Alexander Boettcher
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 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>
|
||||
#include <platform_session/connection.h>
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
#include "acpiosxf.h"
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsInitialize (void)
|
||||
{
|
||||
/* XXX - acpi_drv uses IOMEM concurrently to us - wait until it is done */
|
||||
PINF("wait for platform drv");
|
||||
try {
|
||||
Platform::Connection conn;
|
||||
} catch (...) { PERR("did not get Platform connection"); }
|
||||
PINF("wait for platform drv - done");
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
UINT64 *value, UINT32 width)
|
||||
{
|
||||
Platform::Connection conn;
|
||||
Platform::Device_capability cap = conn.first_device();
|
||||
|
||||
while (cap.valid()) {
|
||||
Platform::Device_client client(cap);
|
||||
|
||||
unsigned char bus, dev, fn;
|
||||
client.bus_address(&bus, &dev, &fn);
|
||||
|
||||
if (pcidev->Bus == bus && pcidev->Device == dev &&
|
||||
pcidev->Function == fn) {
|
||||
|
||||
Platform::Device_client::Access_size access_size;
|
||||
switch (width) {
|
||||
case 8:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_8BIT;
|
||||
break;
|
||||
case 16:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_16BIT;
|
||||
break;
|
||||
case 32:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_32BIT;
|
||||
break;
|
||||
default:
|
||||
PERR("%s : unsupported access size %u", __func__, width);
|
||||
conn.release_device(client);
|
||||
return AE_ERROR;
|
||||
};
|
||||
|
||||
*value = client.config_read(reg, access_size);
|
||||
|
||||
PINF("%s: %x:%x.%x reg=0x%x width=%u -> value=0x%llx",
|
||||
__func__, bus, dev, fn, reg, width, *value);
|
||||
|
||||
conn.release_device(client);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
cap = conn.next_device(cap);
|
||||
|
||||
conn.release_device(client);
|
||||
}
|
||||
|
||||
PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x",
|
||||
__func__, pcidev->Segment, pcidev->Bus, pcidev->Device,
|
||||
pcidev->Function, reg, width);
|
||||
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
UINT64 value, UINT32 width)
|
||||
{
|
||||
Platform::Connection conn;
|
||||
Platform::Device_capability cap = conn.first_device();
|
||||
|
||||
while (cap.valid()) {
|
||||
Platform::Device_client client(cap);
|
||||
|
||||
unsigned char bus, dev, fn;
|
||||
client.bus_address(&bus, &dev, &fn);
|
||||
|
||||
if (pcidev->Bus == bus && pcidev->Device == dev &&
|
||||
pcidev->Function == fn) {
|
||||
|
||||
Platform::Device_client::Access_size access_size;
|
||||
switch (width) {
|
||||
case 8:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_8BIT;
|
||||
break;
|
||||
case 16:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_16BIT;
|
||||
break;
|
||||
case 32:
|
||||
access_size = Platform::Device_client::Access_size::ACCESS_32BIT;
|
||||
break;
|
||||
default:
|
||||
PERR("%s : unsupported access size %u", __func__, width);
|
||||
conn.release_device(client);
|
||||
return AE_ERROR;
|
||||
};
|
||||
|
||||
client.config_write(reg, value, access_size);
|
||||
|
||||
PWRN("%s: %x:%x.%x reg=0x%x width=%u value=0x%llx",
|
||||
__func__, bus, dev, fn, reg, width, value);
|
||||
|
||||
conn.release_device(client);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
cap = conn.next_device(cap);
|
||||
|
||||
conn.release_device(client);
|
||||
}
|
||||
|
||||
PERR("%s unknown device - segment=%u bdf=%x:%x.%x reg=0x%x width=0x%x",
|
||||
__func__, pcidev->Segment, pcidev->Bus, pcidev->Device,
|
||||
pcidev->Function, reg, width);
|
||||
|
||||
return AE_ERROR;
|
||||
}
|
100
repos/libports/src/lib/acpica/scan_root.cc
Normal file
100
repos/libports/src/lib/acpica/scan_root.cc
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* \brief Lookup code for initial ACPI RSDP pointer
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
}
|
||||
|
||||
namespace Genode {
|
||||
class Acpi_table;
|
||||
}
|
||||
|
||||
class Genode::Acpi_table
|
||||
{
|
||||
private:
|
||||
|
||||
/* BIOS range to scan for RSDP */
|
||||
enum { BIOS_BASE = 0xe0000, BIOS_SIZE = 0x20000 };
|
||||
|
||||
/**
|
||||
* Search for RSDP pointer signature in area
|
||||
*/
|
||||
uint8_t *_search_rsdp(uint8_t *area)
|
||||
{
|
||||
for (addr_t addr = 0; area && addr < BIOS_SIZE; addr += 16)
|
||||
/* XXX checksum table */
|
||||
if (!memcmp(area + addr, "RSD PTR ", 8))
|
||||
return area + addr;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 'Root System Descriptor Pointer' (ACPI spec 5.2.5.1)
|
||||
*/
|
||||
uint64_t _rsdp()
|
||||
{
|
||||
uint8_t * local = 0;
|
||||
|
||||
/* try BIOS area */
|
||||
{
|
||||
Genode::Attached_io_mem_dataspace io_mem(BIOS_BASE, BIOS_SIZE);
|
||||
local = _search_rsdp(io_mem.local_addr<uint8_t>());
|
||||
if (local)
|
||||
return BIOS_BASE + (local - io_mem.local_addr<uint8_t>());
|
||||
}
|
||||
|
||||
/* search EBDA (BIOS addr + 0x40e) */
|
||||
try {
|
||||
unsigned short base = 0;
|
||||
{
|
||||
Genode::Attached_io_mem_dataspace io_mem(0, 0x1000);
|
||||
local = io_mem.local_addr<uint8_t>();
|
||||
if (local)
|
||||
base = (*reinterpret_cast<unsigned short *>(local + 0x40e)) << 4;
|
||||
}
|
||||
|
||||
if (!base)
|
||||
return 0;
|
||||
|
||||
Genode::Attached_io_mem_dataspace io_mem(base, 1024);
|
||||
local = _search_rsdp(io_mem.local_addr<uint8_t>());
|
||||
|
||||
if (local)
|
||||
return base + (local - io_mem.local_addr<uint8_t>());
|
||||
} catch (...) {
|
||||
PWRN("failed to scan EBDA for RSDP root");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Acpi_table() { }
|
||||
|
||||
Genode::addr_t phys_rsdp()
|
||||
{
|
||||
Genode::uint64_t phys_rsdp = _rsdp();
|
||||
return phys_rsdp;
|
||||
}
|
||||
};
|
||||
|
||||
ACPI_PHYSICAL_ADDRESS AcpiOsGetRootPointer (void)
|
||||
{
|
||||
Genode::Acpi_table acpi_table;
|
||||
ACPI_PHYSICAL_ADDRESS rsdp = acpi_table.phys_rsdp();
|
||||
return rsdp;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user