Linux kernel Hardware breakpoint registration failed with EACCES - linux-kernel

I am using below code in my driver, but the register_wide_hw_breakpoint returns an EACESS error.
hw_breakpoint_init(&attr);
attr.bp_addr = kallsyms_lookup_name(ksym_name);
attr.bp_len = HW_BREAKPOINT_LEN_4;
attr.bp_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
sample_hbp = register_wide_hw_breakpoint(&attr, sample_hbp_handler, NULL);
if (IS_ERR((void __force *)sample_hbp)) {
ret = PTR_ERR((void __force *)sample_hbp);
printk(KERN_INFO "Breakpoint registration failed:%d\n",ret);
}
What could be possible reasons for this? Am I missing a CONFIG option which will grant access to hardware registers?
Additional info: My platform is X86_64, Linux
Please help.

Related

Has there been any change between kernel 5.15 and 5.4.0 concerning ioctl valid commands?

We have some custom driver working on 5.4.0. It's pretty old and the original developers are no longer supporting it, so we have to maintain it in our systems.
When upgrading to Ubuntu 22 (Kernel 5.15), the driver suddenly stopped working, and sending ioctl with the command SIOCDEVPRIVATE (which used to work in kernel 5.4.0, and in fact is used to get some necessary device information)now gives "ioctl: Operation not supported" error with no extra information anywhere on the logs.
So... has something changed between those two kernels? We did have to adapt some of the structures used to register the driver, but I can't see anything concerning registering valid operations there. Do I have to register valid operations somewhere now?
Alternatively, does somebody know what part of the kernel code is checking for the operation to be supported? I've been trying to find it from ioctl.c, but I can't seem to find where that particular error comes from.
The driver code that supposedly takes care of this (doesn't even reach first line on 5.15):
static int u50_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) {
struct u50_priv *priv = netdev_priv(dev);
if (cmd == SIOCDEVPRIVATE) {
memcpy(&ifr->ifr_data, priv->tty->name, strlen(priv->tty->name));
}
return 0;
}
And the attempt to access it that does no longer work:
struct ifreq ifr = {0};
struct ifaddrs *ifaddr, *ifa;
getifaddrs(&ifaddr);
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
memcpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ);
if (ioctl(lonsd, SIOCDEVPRIVATE, &ifr) < 0) {
perror("ioctl");
syslog(LOG_ERR, "Ioctl:%d: %s\n", __LINE__, strerror(errno));
}
...
and structure for registration
static const struct net_device_ops u50_netdev_ops = {
.ndo_init = u50_dev_init,
.ndo_uninit = u50_dev_uninit,
.ndo_open = u50_dev_open,
.ndo_stop = u50_dev_stop,
.ndo_start_xmit = u50_dev_xmit,
.ndo_do_ioctl = u50_dev_ioctl,
.ndo_set_mac_address = U50SetHWAddr,
};
If you need some code to respond to SIOCDEVPRIVATE, you used to be able to do it via ndo_do_ioctl (writing a compatible function, then linking it in a net_device_ops struct in 5.4). However, in 5.15 it was changed so now you have to implement a ndo_siocdevprivate function, rather than ndo_do_ioctl, which is no longer called, according to the kernel documentation.
source:
https://elixir.bootlin.com/linux/v5.15.57/source/include/linux/netdevice.h
Patch that did this: spinics.net/lists/netdev/msg698158.html

Why the bootloader will crash, when I use i2c read/write operation in uefi on Qualcomm qcs platform?

I'm able to control gpio in uefi right now, so there's no problem that I can control physical layer.
Meanwhile, It succeed to open I2C_instance via. qualcomm I2cApiLib. But when I use I2C_read/write in my code, the bootloader will crash when boot-up.
Crash log are as follow:
enter image description here
Sample Code:
EFI_STATUS
EFIAPI
BootLEDMain(IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
DEBUG((EFI_D_ERROR, "------BootLED APPLICATION TEST------\n"));
i2c_status istatus = I2C_SUCCESS;
VOID *i2c_handle = NULL;
UINT32 bytes_read = 0;
uint8 readbuf = 0;
//UINT32 bytes_written = 0;
//uint8 writebuf = 0x01;
i2c_config cfg;
cfg.bus_frequency_khz = 400;
cfg.slave_address = 0x77;
cfg.slave_address_type = I2C_07_BIT_SLAVE_ADDRESS;
istatus = i2c_open((i2c_instance) (I2C_INSTANCE_003), &i2c_handle);
if (I2C_SUCCESS != istatus)
{
DEBUG((EFI_D_ERROR, "Failed to initialize I2C %d\n", istatus));
goto error;
}
else
{
DEBUG((EFI_D_ERROR, "Succeed to open I2C\n"));
}
istatus = i2c_read (i2c_handle, &cfg, 0x45, 1, &readbuf, 1, &bytes_read, 2500);
if (I2C_SUCCESS != istatus)
{
DEBUG((EFI_D_ERROR, "Read Failed %d\n", (uint32) istatus));
goto error;
}
else
{
DEBUG((EFI_D_ERROR, "Succeed to Read\n"));
}
.
.
.
Could you guys who has a little bit knowledge of qualcomm uefi explain the reason why, Thanks.
Comment what details you guys need or want to know.
From your crash log, the Exception Syndrome Register (ESR) says that you are taking a 'Translation fault, level 3' from an instruction trying to write to a location.
The Fault Address Register (FAR) says that the faulting address is 0x078b700c.
I have no idea what codebase you are working on, but presumably you will have to make sure MMU mappings are created for the i2c controller.

QEMU Cannot Open Tap Device in Windows 10 Host

I am trying to bridge my QEMU VM to a local adapter in my Windows 10 host, but QEMU complains that the interface name provided by ifname option to the -netdev argument cannot be opened. I have followed the answer in https://superuser.com/questions/1317652/how-to-set-up-nat-for-qemu-with-tap-backend-windows-10, but with no luck. I have cross-compiled QEMU from source to debug this behavior, for whether or not the interface name can be detected, and apparently QEMU can find the adapter's name, but not the TAP device file. To further explain my point, here's a code snippet from net/tap-win32.c:595 from the QEMU 4.2.0 source code (latest release version as of this writing), specifically tap_win32_open function, and I will highlight where it was failing in this function (look for // THIS IS WHERE IT WILL FAIL. comments):
Testing with a correct existing network interface:
static int tap_win32_open(tap_win32_overlapped_t **phandle,
const char *preferred_name)
{
...
rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
if (rc)
return -1;
snprintf (device_path, sizeof(device_path), "%s%s%s",
USERMODEDEVICEDIR,
device_guid,
TAPSUFFIX);
handle = CreateFile (
device_path,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0 );
if (handle == INVALID_HANDLE_VALUE) {
return -1; // THIS IS WHERE IT WILL FAIL.
}
...
Testing with an incorrect (non-existent) network interface:
static int tap_win32_open(tap_win32_overlapped_t **phandle,
const char *preferred_name)
{
...
rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
if (rc)
return -1; // THIS IS WHERE IT WILL FAIL.
snprintf (device_path, sizeof(device_path), "%s%s%s",
USERMODEDEVICEDIR,
device_guid,
TAPSUFFIX);
handle = CreateFile (
device_path,
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
0 );
if (handle == INVALID_HANDLE_VALUE) {
return -1;
}
...
QEMU uses the prefix USERMODEDEVICEDIR, which is \\.\Global\ and a suffix .tap to the device's GUID to create the device's path in Windows. For example, the network adapter I am dealing with results in the following device path: \\.\Global\{990DA322-3986-4854-AE93-1D6FB0BFA137}.tap. Any idea why CreateFile always results in INVALID_HANDLE_VALUE on the device path? By the way, GetLastError() returns 2, which from learn.microsoft.com means the following:
...
ERROR_FILE_NOT_FOUND
2 (0x2)
The system cannot find the file specified.
...
I apologize. I was attaching to a non-TAP adapter, thinking it will acquire the address from it, much like VirtualBox. I did not entirely understand the bridging concept before in QEMU, but now I should attach to a TAP adapter, and bridge that adapter to another preferred adapter.

Intel VT-x: Configuring debug registers to debug from host

I am trying to configure the debug registers in the host so that I can monitor an address of a guest running on Intel VT-x. For this I have called KVM_SET_GUEST_DEBUG IOCTL.
struct kvm_guest_debug guest_debug;
guest_debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP;
guest_debug.arch.debugreg[0] = addr; // DR0
guest_debug.arch.debugreg[7] = encode_dr7(0, len, bpType);
if (ioctl(vcpu_fd, KVM_SET_GUEST_DEBUG, &guest_debug) < 0)
return false;
It successfully sets up the debug register. But upon debug register read/write, it causes VM_EXIT with EXIT_REASON_EXCEPTION_NMI. Although I am expecting to have EXIT_REASON_DR_ACCESS. What is the reason that causes an nmi exit instead of DR_ACCESS exit? Did I set the registers right?

FreeBSD newbus driver loading succesfully but cant create /dev/** file and debugging

I am installing a new newbuf driver on FreeBSD 10.0 . After compiling with make the driver.ko file has been created and than kldload can load successfully. kldload returns 0 and I can see the device at the kldstat output. When attempt to use the driver opening the /dev/** file, the file is not exist.
I think that this /dev/** file should be created by make_dev function which is located in device_attach member method. To test if the kldload reaches this attaching function; when write printf and uprintf to debug the driver, I can not see any output at console nor dmesg output.
But the problem is after writing printf at beginnings (after local variable definitions) of device_identify and device_probe functions, I can't see any output again at console nor dmesg.
My question is that even if the physical driver has problem (not located etc.), should I see the ouput of printf at the device_identify member function which is called by kldload at starting course (I think)?
Do I have a mistake when debugging newbuf driver with printf (I also tried a hello_world device driver and at this driver I can take output of printf at dmesg)?
Mainly how can I test/debug this driver's kldload processes?
Below some parts of my driver code (I think at least I should see MSG1, but I can not see):
struct mydrv_softc
{
device_t dev;
};
static devclass_t mydrv_devclass;
static struct cdevsw mydrv_cdevsw = {
.d_version = D_VERSION,
.d_name = "mydrv",
.d_flags = D_NEEDGIANT,
.d_open = mydrv_open,
.d_close = mydrv_close,
.d_ioctl = mydrv_ioctl,
.d_write = mydrv_write,
.d_read = mydrv_read
};
static void mydrv_identify (driver_t *driver, device_t parent) {
devclass_t dc;
device_t child;
printf("MSG1: The process inside the identfy function.");
dc = devclass_find("mydrv");
if (devclass_get_device(dc, 0) == NULL) {
child = BUS_ADD_CHILD(parent, 0, "mydrv", -1);
}
}
static int mydrv_probe(device_t dev) {
printf("MSG2: The process inside the probe function.");
mydrv_init();
if (device_get_unit(dev) != 0)
return (ENXIO);
device_set_desc(dev, "FreeBSD Device Driver");
return (0);
}
static int mydrv_attach(device_t dev) {
struct mydrv_softc *sc;
device_printf(dev, "MSG3: The process will make attachment.");
sc = (struct mydrv_softc *) device_get_softc(dev);
sc->dev = (device_t)make_dev(&mydrv_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, "mydrv_drv");
return 0;
}
static int mydrv_detach(device_t dev) {
struct mydrv_softc *sc;
sc = (struct mydrv_softc *) device_get_softc(dev);
destroy_dev((struct cdev*)(sc->dev));
bus_generic_detach(dev);
return 0;
}
static device_method_t mydrv_methods[] = {
DEVMETHOD(device_identify, mydrv_identify),
DEVMETHOD(device_probe, mydrv_probe),
DEVMETHOD(device_attach, mydrv_attach),
DEVMETHOD(device_detach, mydrv_detach),
{ 0, 0 }
};
static driver_t mydrv_driver = {
"mydrv",
mydrv_methods,
sizeof(struct mydrv_softc),
};
DRIVER_MODULE(mydrv, ppbus, mydrv_driver, mydrv_devclass, 0, 0);
If you don't see your printf's output on your console then your device functions will probably not be called. Can you show us your module's code?
Have you used DRIVER_MODULE() or DEV_MODULE()?
What parent bus are you using?
I guess printf works fine, but I prefer to use device_printf as it also prints the device name, and will be easier when looking through logs or dmesg output. Also leave multiple debug prints and check the log files on your system. Most logs for the device drivers are logged in /var/log/messages. But check other log files too.
Are you running your code on a virtual machine? Some device drivers don't show up their device files in /dev if the OS is running on a virtual machine. You should probably run your OS on actual hardware for the device file to show up.
As far as I know, you can't see the output in dmesg if you cannot find the corresponding device file in /dev but you may have luck with logs as I mentioned.
The easiest way to debug is of course using the printf statements. Other than this, you can debug the kernel using gdb running on another system. I am not familiar with the exact process but I know you can do this. Google it.

Resources