Reading Armv8-A registers with devmem from GNU/Linux shell - cpu-registers

I want to read the values of some Cortex-A53 registers, such as
D_AA64ISAR0_EL1 (AArch64)
ID_ISAR5 (Aarch32)
ID_ISAR5_EL1 (Aarch64)
Unfortunately, I lack a little embedded/assembly experience. The documentation reveals
To access the ID_AA64ISAR0_EL1:
MRS , ID_AA64ISAR0_EL1 ; Read ID_AA64ISAR0_EL1 into Xt
ID_AA64ISAR0_EL1[31:0] can be accessed through the internal memory-mapped interface
and the external debug interface, offset 0xD30.
I decided to utilize devmem2 on my target (since busybox does not include the devmem applet). Is the following procecure correct to read the register?
devmem2 0xD30
The part which I am unsure about is using the "offset" as a direct physical address. If it is the actual address, why call if "offset" and not "address". If it's an offset, what is the base address? I am 99% certain this is not the correct procedure, but how do I know the base address to add the offset to? I have searched the Armv8 technical reference manual and A53 MPCore documents to no avail. The explain the register contents in detail but seem to assume you read them from ASM using the label ID_AA64ISAR0_EL1.
Update:
I found this:
Configuration Base Address Register, EL1
The CBAR_EL1 characteristics are:
Purpose Holds the physical base address of the memory-mapped GIC CPU
interface registers.
But it simply duplicates my problem, how to read this other register?
Update 2:
The first update seems relevant only for GIC and not for configuration registers I am trying to read (I misunderstood the information I think).
For the specific problem at hand (checking crypto extension availability) one may simply cat /proc/cpuinfo and look for aes/sha etc.
Update 3:
I am now investigating http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0176c/ar01s04s01.html, as well as the base address being SoC specific and thus may be found in the reference manual of the SoC.
Update 4:
Thanks to the great answer I seem to be able to read data via my kernel module:
[ 4943.461948] ID_AA64ISA_EL1 : 0x11120
[ 4943.465775] ID_ISAR5_EL1 : 0x11121
P.S.: This was very insightful, thank you again!
Update 5:
Source code as per request:
/******************************************************************************
*
* Copyright (C) 2011 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*****************************************************************************/
#include <linux/module.h>
#include <linux/types.h>
/*****************************************************************************/
// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).
static inline uint64_t system_read_ID_AA64ISAR0_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, ID_AA64ISAR0_EL1" : "=r" (val));
return val;
}
// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).
static inline uint64_t system_read_ID_ISAR5_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));
return val;
}
/*****************************************************************************/
int init_module(void)
{
printk("ramdump Hello World!\n");
printk("ID_AA64ISAR0_EL1 : 0x%llX\n", system_read_ID_AA64ISAR0_EL1());
printk("ID_ISAR5_EL1 : 0x%llX\n", system_read_ID_ISAR5_EL1());
return 0;
}
void cleanup_module(void)
{
printk("ramdump Goodbye Cruel World!\n");
}
MODULE_LICENSE("GPL");

Disclaimer: I am not an Aarch64 expert, but I am currently learning about the architecture and have read a bit.
You cannot read ID_AA64ISAR0_EL1, ID_ISAR5_EL1 nor ID_ISAR5 from a user-mode application running at EL0: the _EL1 suffix means than running at least at EL1 is required in order to be allowed to read those two registers.
You may find helpful to read the pseudo-code in the arm documentation here and here.
In the case of ID_ISAR5 for example, the pseudo-code is very explicit:
if PSTATE.EL == EL0 then
UNDEFINED;
elsif PSTATE.EL == EL1 then
if EL2Enabled() && !ELUsingAArch32(EL2) && HSTR_EL2.T0 == '1' then
AArch64.AArch32SystemAccessTrap(EL2, 0x03);
elsif EL2Enabled() && ELUsingAArch32(EL2) && HSTR.T0 == '1' then
AArch32.TakeHypTrapException(0x03);
elsif EL2Enabled() && !ELUsingAArch32(EL2) && HCR_EL2.TID3 == '1' then
AArch64.AArch32SystemAccessTrap(EL2, 0x03);
elsif EL2Enabled() && ELUsingAArch32(EL2) && HCR.TID3 == '1' then
AArch32.TakeHypTrapException(0x03);
else
return ID_ISAR5;
elsif PSTATE.EL == EL2 then
return ID_ISAR5;
elsif PSTATE.EL == EL3 then
return ID_ISAR5;
One easy way to read those register would be to write a tiny loadable kernel module you could call from your user-mode application: Since the Linux kernel is running at EL1, it is perfectly able to read those three registers.
See for example this article for a nice introduction to Linux loadable kernel modules.
And this is likely that an application running at EL0 cannot access memory-mapped registers accessible only from EL1, since this would obviously break the protection scheme.
The C code snippets required to read those registers in Aarch64 state would be (tested with gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu) :
#include <stdint.h>
// read system register value ID_AA64ISAR0_EL1 (s3_0_c0_c6_0).
static inline uint64_t system_read_ID_AA64ISAR0_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c6_0" : "=r" (val));
return val;
}
// read system register value ID_ISAR5_EL1 (s3_0_c0_c2_5).
static inline uint64_t system_read_ID_ISAR5_EL1(void)
{
uint64_t val;
asm volatile("mrs %0, s3_0_c0_c2_5" : "=r" (val));
return val;
}
Update #1:
The GCC toolchain does not understand all arm system register names, but can nevertheless properly encode system registers access instructions if specified which exact values of the coproc, opc1, CRn, CRm, and opc2 fields are associated to this register.
In the case of ID_AA64ISAR0_EL1, the values specified in the ArmĀ® Architecture Registers Armv8, for Armv8-A architecture profile document are:
coproc=0b11, opc1=0b000, CRn=0b0000, CRm=0b0110, opc2=0b000
The system register alias would then be s[coproc]_[opc1]_c[CRn]_c[CRm]_[opc2], that is s3_0_c0_c6_0 in the case of ID_AA64ISAR0_EL1.

I see this tool maybe meets your need:
system-register-tools
It just provides reading and writing system registers function for arm64, likes MSR-tools in x86.

Related

NIOSII Softcore UART Interrupt

I try to get an UART IP core in combination with the NIOS2 (softcore) running on the Cyclone 10 LP evaluation board.
So far everything works fine in polling mode. However, I cannot manage to get the interrupts running on the softcore.
The FPGA is configured in the following way.
From the picture it can be seen, that the interrupt line is connected to the NIOS2 softcore processor.
The following picture shows that the Altera UART driver is available.
The initalization code provided by Altera looks like the following.
/*
* Initialize the interrupt controller devices
* and then enable interrupts in the CPU.
* Called before alt_sys_init().
* The "base" parameter is ignored and only
* present for backwards-compatibility.
*/
void alt_irq_init ( const void* base )
{
ALTERA_NIOS2_GEN2_IRQ_INIT ( NIOS2E, nios2e);
alt_irq_cpu_enable_interrupts();
}
/*
* Initialize the non-interrupt controller devices.
* Called after alt_irq_init().
*/
void alt_sys_init( void )
{
ALTERA_AVALON_JTAG_UART_INIT ( JTAG_UART, jtag_uart);
ALTERA_AVALON_UART_INIT ( UART_0, uart_0);
ALTERA_REMOTE_UPDATE_INIT ( REMOTE_UPDATE_0, remote_update_0);
}
To enable interrupts you have to disable the reduced drivers in the BSP Editor of NIOS2. One might assume, that if you connect the interrupt line in Quartus Prime this will be considered in the NIOS2EDS Project. Unfortunately this is not the case.

slapi plug-in does not work after update of OpenLDAP from 2.4 to 2.6.1

We build from source and run OpenLDAP and the SLAPI plugin since ages on Linux. The SLAPI plugin, written in C, publishes LDAP changes (add, modify, delete) to an Identity Management System (IDM). The plugin is configured in slapd.conf as
plugin postoperation /opt/openldap-2.6.1/lib64/idm.so idm_init "IDM Plugin" 10.23.33.52 3001
The function idm_init() registers static C functions for add, modify and delete the supposed way (here only shown for modify):
int idm_init(Slapi_PBlock * pb)
{
int rc = LDAP_SUCCESS;
log("idm-plugin:","now in idm_init()\n");
// first call, create new list and register the functions
...
rc |=
slapi_pblock_set( /* Plug-in API version */ pb,
SLAPI_PLUGIN_VERSION,
SLAPI_PLUGIN_CURRENT_VERSION);
rc |=
slapi_pblock_set( /* Plug-in description */ pb,
SLAPI_PLUGIN_DESCRIPTION, (void *) &desc);
rc |=
slapi_pblock_set( /* Modify function */ pb,
SLAPI_PLUGIN_POST_MODIFY_FN,
(void *) modify_user);
...
// read arguments and add list entry
rc |= read_arguments(pb);
log("idm-plugin", "idm_init() return rc:%d\n", rc);
return rc;
}
The function for modify_user() which should be called from the LDAP server after modification of data, will later publish the change via network and without going into the details the start of the function looks like this:
static int modify_user(Slapi_PBlock * pb)
{
Slapi_Entry *entry;
log("idm-plugin:", "now in modify_user\n");
if (slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &entry) != LDAP_SUCCESS) {
log("IDM-Connector Plugin",
"entry modified, but couldn't get entry");
return -1;
}
...
The problem is, that after an update in LDAP this function is not called. The log
shows only the attach and initialisation of the plugin but no further actions:
03/16/22 10:52:26 idm-plugin:: now in idm_init()
03/16/22 10:52:26 IDM-Connector Plugin: idm_init: Initializing plugin
03/16/22 10:52:26 idm-plugin:: now in read_arguments()
03/16/22 10:52:26 IDM Plugin: added idm connector: ip=10.23.33.52, port=3001
03/16/22 10:52:26 idm-plugin: idm_init() returns rc:0
03/16/22 10:52:26 plugin_pblock_new: Registered plugin OCLC-IDM-Connector-Notifier 1.0 [OCLC.org] (Notify the OCLC IDM-Connector of changes)
As the subject sais, with OpenLDAP 2.4 this works fine. It does not work anymore with 2.6.1.
Is there some change in the SLAPI interface of which we are not aware of?
I already set full log level any but there is nothing logged about the function call. Any ideas?
To terminate this thread: The problem was caused by a misconfiguration in our slapd.conf.
The plugin line was at the wrong place. Details can be seen here:
https://bugs.openldap.org/show_bug.cgi?id=9812

Getting positions from gpsd in a Qt quick program

I have a computer with a GPS connected to a serial port that is running gpsd with a pretty basic configuration. Here is the contents of /etc/default/gpsd:
START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyS0"
GPSD_OPTIONS="-n -G"
GPSD_SOCKET="/var/run/gpsd.sock"
With this config, gpsd runs fine and all gpsd client utilities, e.g. cgps, gpspipe, gpsmon, can get data from the GPS.
I am trying to access GPS data from a Qt QML program using the PositionSource element with the following syntax but lat and long show as NaN so it doesn't work:
PositionSource {
id: gpsPos
updateInterval: 500
active: true
nmeaSource: "socket://localhost:2947"
onPositionChanged: {
myMap.update( gpsPos.position )
}
}
I tried piping the NMEA data from the GPS to another port using gpspipe -r | nc -l 6000 and specifying nmeaSource: "socket://localhost:6000 and everything works fine!
How do I make Qt talk to gpsd directly?
After tinkering (i.e. compiling from source, installing, configuring, testing, etc.) with gps-share, Gypsy, geoclue2, serialnmea and other ways to access data from a GPS connected to a serial port (thanks to Pa_ for all the suggestions), but all with no results while gpsd was working perfectly for other apps, I decided to make Qt support gpsd by making a very crude change to the QDeclarativePositionSource class to implement support for a gpsd scheme in the URL for the nmeaSource property. With this change, a gpsd source can now be defined as nmeaSource: "gpsd://hostname:2947" (2947 is the standard gpsd port).
The changed code is shown below. I would suggest this should be added to Qt at some point but in the meantime, I guess I need to derive this class to implement my change in a new QML component but, being new to QML, I have no idea how that is done. I suppose it would also probably be a good idea to stop and start the NMEA stream from gpsd based on the active property of the PositionSource item... I will get to it at some point but would appreciate pointers on how to do this in a more elegant way.
void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource)
{
if ((nmeaSource.scheme() == QLatin1String("socket") )
|| (nmeaSource.scheme() == QLatin1String("gpsd"))) {
if (m_nmeaSocket
&& nmeaSource.host() == m_nmeaSocket->peerName()
&& nmeaSource.port() == m_nmeaSocket->peerPort()) {
return;
}
delete m_nmeaSocket;
m_nmeaSocket = new QTcpSocket();
connect(m_nmeaSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)> (&QAbstractSocket::error),
this, &QDeclarativePositionSource::socketError);
connect(m_nmeaSocket, &QTcpSocket::connected,
this, &QDeclarativePositionSource::socketConnected);
// If scheme is gpsd, NMEA stream must be initiated by writing a command
// on the socket (gpsd WATCH_ENABLE | WATCH_NMEA flags)
// (ref.: gps_sock_stream function in gpsd source file libgps_sock.c)
if( nmeaSource.scheme() == QLatin1String("gpsd")) {
m_nmeaSocket->connectToHost(nmeaSource.host(),
nmeaSource.port(),
QTcpSocket::ReadWrite);
char const *gpsdInit = "?WATCH={\"enable\":true,\"nmea\":true}";
m_nmeaSocket->write( gpsdInit, strlen(gpsdInit);
} else {
m_nmeaSocket->connectToHost(nmeaSource.host(), nmeaSource.port(), QTcpSocket::ReadOnly);
}
} else {
...

nacl_io bind fails with EPERM

I wrote some demo app, that uses nacl_io sockets,
but bind fails with errno == EPERM
building with pepper_37,
Google Chrome 39.0.2171.95 (m)
OS Windows 7 or Server 2008 R2 SP1 64 bit
PNaCl translator version 0.1.0.13769
chrome flags:
--allow-nacl-socket-api=localhost --no-sandbox --enable-nacl
class ProxyTesterInstance : public pp::Instance
{
public:
explicit ProxyTesterInstance(PP_Instance instance, PPB_GetInterface get_interface) : pp::Instance(instance)
{
nacl_io_init_ppapi(instance, get_interface);
}
virtual ~ProxyTesterInstance() {}
virtual void HandleMessage(const pp::Var& var_message)
{
if (!var_message.is_string())
return;
std::string message = var_message.AsString();
if (message == kStartString)
{
reply(kReplyStartString);
int fd = socket( PF_INET, SOCK_STREAM, 0);
struct sockaddr_in myaddr;
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(50000);
inet_aton("0.0.0.0", &myaddr.sin_addr );
int res = bind(fd, (struct sockaddr*)&myaddr, sizeof(myaddr)); //returns -1
myaddr.sin_port = htons(80);
inet_aton("173.194.113.2", &myaddr.sin_addr );
res = connect(fd, (struct sockaddr*)&myaddr, sizeof(myaddr)); //returns 0
}
nacl_io assumes that it is being run on a worker thread, not the main thread. This is because many socket functions are blocking, but it is illegal to block the main thread in a NaCl application. Unfortunately, the error messages are not very clear explaining this constraint.
The easiest way to make this code work is to use the ppapi_simple library. It will initialize nacl_io for you and start running your code on a worker thread. At this point, you'll be able to make blocking calls (such as bind). It also gives you a main-like entry point instead of having to create a pp::Instance.
Take a look at some of the demos in the NaCl SDK (e.g. examples/demo/earth, examples/demo/pi_generator) for how to use ppapi_simple.

Qt OpenSSL problem - blocked (?) on some computers

I write an app i qt which uses OpenSSL. All was alright, since yesterday. I compiled app and sent to my friend. On his computer application can open https. I open on other computer and it doesn't work. So I gave it to other friend and he can't open https websites. I was confused and gave other guy and on his computer my app is working. I don't understand situation. Previous versions worked without bugs. But i ran previous version which worked and it doesn't work too. I turned off all my firewalls. Nothing changed.
Any suggestions?
We all have 7 x64. I tested on XP HE and it works, bou on 7 x64 doesn't work. On my friend's computer 7 x64 works, but on XP HE doesn't works. IMO Operating System hasn't got any mean.
By default Qt doesn't contain implementation of OpenSSL, but uses libraries already installed into system.
Installing Win32 OpenSSL will make it work.
Another option is to build Qt with OpenSSL. Some info here.
In case you have still no solution to the error - I just ran over the same issue. It seems to be a problem with the CA certficate chain on the Windows computer. The details can be found at https://bugreports.qt-project.org/browse/QTBUG-20012.
Here's also a little class which fixes the ca chain so the error should not occur in the application.
#ifndef OPENSSLFIX_H
#define OPENSSLFIX_H
#include <QSslConfiguration>
/* this class fixes a problem with qt/openssl and expired ca certificates.
* the idea is taken from https://bugreports.qt-project.org/browse/QTBUG-20012
* which describes the problem and the workaround further. the workaround is
* scheduled for qt5, but will not be introduced into qt4.x.
*
* to use this fix just call it in main() before doing any network related
* stuff
*
* OpenSslFix::fixCaCertificates();
*
* it will go through the certificates and remove invalid certs from the chain,
* thus avoiding the error to arise.
*/
class OpenSslFix {
public:
static void fixCaCertificates()
{
QSslConfiguration config(QSslConfiguration::defaultConfiguration());
QList<QSslCertificate> in(config.caCertificates());
QList<QSslCertificate> out;
for (int i=0, size=in.size(); i<size; ++i) {
const QSslCertificate &c(in[i]);
if (c.isValid()) {
/* not expired -> add */
out << c;
continue;
}
/* check if the cert is already present in the output */
bool found = false;
for (int j=0, size=out.size(); j<size; ++j) {
if (isCertificateSameName(c, out[j])) {
/* already present... */
found = true;
break;
}
}
if (!found)
out << c;
}
/* now set the new list as the default */
config.setCaCertificates(out);
QSslConfiguration::setDefaultConfiguration(config);
}
private:
static inline bool isCertificateSameName(const QSslCertificate &cert1,
const QSslCertificate &cert2)
{
return cert1.subjectInfo(QSslCertificate::Organization) ==
cert2.subjectInfo(QSslCertificate::Organization) &&
cert1.subjectInfo(QSslCertificate::CommonName) ==
cert2.subjectInfo(QSslCertificate::CommonName) &&
cert1.subjectInfo(QSslCertificate::LocalityName) ==
cert2.subjectInfo(QSslCertificate::LocalityName) &&
cert1.subjectInfo(QSslCertificate::OrganizationalUnitName) ==
cert2.subjectInfo(QSslCertificate::OrganizationalUnitName) &&
cert1.subjectInfo(QSslCertificate::StateOrProvinceName) ==
cert2.subjectInfo(QSslCertificate::StateOrProvinceName) &&
cert1.subjectInfo(QSslCertificate::CountryName) ==
cert2.subjectInfo(QSslCertificate::CountryName);
}
};
#endif // OPENSSLFIX_H
Try to use QSslSocket::ignoreSslErrors() method.
I also had such problems and using this function solved them for me.

Resources