[gnu-efi]: How to call InitializeGlobalIoDevice funtion when I wanna call CMOS Read/Write? - uefi

Below is the code to initializing the IO device, and I wanna to call a function to do CMOS read/write, but I don't know the DevicePath and Protocol? Does anyone know this? thanks a lot;
/*
Routine Description:
Check to see if DevicePath exists for a given Protocol. Return Error if it
exists. Return GlobalIoFuncs set match the DevicePath
Arguments:
DevicePath - to operate on
Protocol - to check the DevicePath against
ErrorStr - ASCII string to display on error
GlobalIoFncs - Returned with DeviceIoProtocol for the DevicePath
Returns:
Pass or Fail based on wether GlobalIoFncs where found
*/
EFI_STATUS
InitializeGlobalIoDevice (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_GUID *Protocol,
IN CHAR8 *ErrorStr EFI_UNUSED,
OUT EFI_DEVICE_IO_INTERFACE **GlobalIoFncs
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
//
// Check to see if this device path already has Protocol on it.
// if so we are loading recursivly and should exit with an error
//
Status = uefi_call_wrapper(BS->LocateDevicePath, 3, Protocol, &DevicePath, &Handle);
if (!EFI_ERROR(Status)) {
DEBUG ((D_INIT, "Device Already Loaded for %a device\n", ErrorStr));
return EFI_LOAD_ERROR;
}
Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &DeviceIoProtocol, &DevicePath, &Handle);
if (!EFI_ERROR(Status)) {
Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &DeviceIoProtocol, (VOID*)GlobalIoFncs);
}
ASSERT (!EFI_ERROR(Status));
return Status;
}
Need your help....

In UEFI spec, there is no Protocol or Device Path defined for CMOS.
If you'd like to read/write the CMOS RTC, there are GetTime() and SetTime() APIs defined in Runtime Services. They can be directly called from RT in gnu-efi.
If you want to read/write other CMOS registers, simply access I/O port 0x70/0x71 with inb/outb instruction with inline assembly in C. That's also how EDK2 accesses CMOS.
https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/PlatformInitLib/Cmos.c
https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c

Related

How to make tap device use socket API?

I'm using tap device.
The problem is that you just can ->read() or ->write() one packet every system call.
After read the source file tun.c, I found there is struct socket in tun device and function tun_get_socket() can return it.
struct socket *tun_get_socket(struct file *file)
{
struct tun_file *tfile;
if (file->f_op != &tun_fops)
return ERR_PTR(-EINVAL);
tfile = file->private_data;
if (!tfile)
return ERR_PTR(-EBADFD);
return &tfile->socket;
}
EXPORT_SYMBOL_GPL(tun_get_socket);
The socket.ops is set with tun_socket_ops which have ->sendmsg() and ->recvmsg().
static const struct proto_ops tun_socket_ops = {
.sendmsg = tun_sendmsg,
.recvmsg = tun_recvmsg,
.release = tun_release,
};
The questions:
How to create one file descriptor to connect with this socket? That makes me to use ->sendmsg() and ->recvmsg() in userspace. My OS is CentOS7.9 with kernel version 3.10.0-1160.el7.x86_64.
Or is there other ways I can read or write multiple packets at one time from tap device?
Writing new kernel module is acceptable.

channelRead not being called in Swift-NIO Datagram's ChannelInboundHandler

I am trying to capture a UDP video stream within a (fresh) vapor application running in Xcode. The data is being streamed by ffmpeg and I can successfully view the stream on the target machine using VLC, which is also the one running the vapor application, using udp://0.0.0.0:5000. I have used various bits of Apple documentation to get to the code below. When I run it, I get these lines of output on the console log, but I wonder if they are not relevant:
2021-07-07 17:59:27.102681+0100 Run[10550:2494617] [si_destination_compare] send failed: Invalid argument
2021-07-07 17:59:27.104056+0100 Run[10550:2494617] [si_destination_compare] send failed: Undefined error: 0
In configure.swift:
try setupClient()
This is the client code:
final class FrameHandler : ChannelInboundHandler {
typealias InboundIn = AddressedEnvelope<ByteBuffer>
typealias OutboundOut = AddressedEnvelope<ByteBuffer>
func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
// minimal for question
}
func errorCaught(ctx: ChannelHandlerContext, error: Error) {
// minimal for question
}
}
func setupClient() throws {
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
let bootstrap = DatagramBootstrap(group: group)
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.channelInitializer { channel in
channel.pipeline.addHandler(FrameHandler())
}
defer {
try! group.syncShutdownGracefully()
}
let channel = try bootstrap.bind(host: "0.0.0.0", port: 5000).wait()
try channel.closeFuture.wait()
}
The problem is that although channelRegistered and channelActive are called, followed by a never-ending stream of readComplete, the important one channelRead never gets called - neither does errorCaught. If I comment out the call to setupClient then there is no network activity, however, if it runs then Xcode's network monitor shows activity consistent with the levels in ffmpeg. So, I believe the connection is being set up.
I wonder if the problem is in the way I am setting the handler up? All the examples use echo or reflecting chat examples, so the inbound handler is set up in the closure of the data-writing function using the context rather than adding it in the initialiser (although, the outbound handler is set up in this way).
I'm assuming you're using Vapor 4 which is based on SwiftNIO 2. And in NIO 2, the ChannelHandlerContext variable is called context and not ctx. So if you just rename all your ctx to context, I'd assume it'll work.

How to performs I/O to block device from block device driver under Linux

I have a task to write a block device driver (/dev/dua - for example) , this block device is must be looks like to OS as a disk device like /dev/sda. So, this driver must process data blocks and write it to other block device.
I looking for a right way to performs I/O operations on the backend device like "/dev/sdb".
I have played with the vfs_read/write routines it's works at glance for disk sector sized transfers. But, probably there is more effective way to performs I/O on backend device ?
TIA.
Follows a piece of code (original has been found here : https://github.com/asimkadav/block-filter) implements a "filtering" feature, so it can be used as a method to performs I/O on a backend block device `
void misc_request_fn(struct request_queue *q, struct bio *bio) {
printk ("we are passing bios.\n");
// here is where we trace requests...
original_request_fn (q, bio);
return;
}
void register_block_device(char *path) {
struct request_queue *blkdev_queue = NULL;
if (path == NULL) {
printk ("Block device empty.\n");
return;
}
printk ("Will open %s.\n", path);
blkdev = lookup_bdev(path);
if (IS_ERR(blkdev)) {
printk ("No such block device.\n");
return;
}
printk ("Found block device %p with bs %d.\n", blkdev, blkdev->bd_block_size);
blkdev_queue = bdev_get_queue(blkdev);
original_request_fn = blkdev_queue->request_fn;
blkdev_queue->request_fn = misc_request_fn;
}
`

ACK with packet retransmission

Again I came across a doubt. I inserted in my implementation the use of ACK.
In the function:
AMSend.sendDone (message_t * bufPtr, error_t error) {
if (call PacketAcknowledgements.wasAcked (bufPtr)) {
dbg ("test", "SEND_ACK \ n");
}
}
And it's apparently working correctly, depending on the output log.
Already in function:
AMControl.startDone (error_t err) {
radio = TRUE;
dbg ("test", "SLOT_ACTIVE \ n");
if (err == SUCCESS) {
if ((call Clock.get ()> (ultpkdados + 5000)) && (TOS_NODE_ID! = 0)) {
test_msg_t * rcm = (test_msg_t *) call Packet.getPayload (& pkt, sizeof (test_msg_t));
rcm-> type = 1;
rcm-> nodeid = TOS_NODE_ID;
rcm-> proxsalto = syncwith;
call PacketAcknowledgements.requestAck (& pkt);
if (call AMSend.send (syncwith, & pkt, sizeof (test_msg_t)) == SUCCESS) {
Dbg ("test", "SEND_PKT_DATA \ n"));
locked = TRUE;
ultpkdados call Clock.get = ();
}
}
}
}
This function startDone is sending this packet of "data" normally, and I made a call PacketAcknowledgements.requestAck to request the ACK.
My question is whether at this point, if the ACK is not confirmed, the original message is retransmitted. If this is not happening, could you suggest me the appropriate changes for this to happen?
My question is whether at this point, if the ACK is not confirmed, the
original message is retransmitted.
No, the message will not be retransmitted.
If this is not happening, could you suggest me the appropriate changes
for this to happen?
What you are doing is just requesting acknowledgments and not enabling retransmissions. Retransmissions are sent by the Packet link layer which is used as specified HERE.
In order to enable re-transmissions you need to:
1) add the PACKETLINK preprocessor variable to your makefile. This can be done by simply adding "-DPACKETLINK" to PFlags in your makefile i.e
PFLAGS = -DPACKETLINK
2) Specify the maximum number of retries that your device can transmit and the delay between each retry. This is done by appropriately calling the setRetries and setRetryDelay functions in the Packet link interface (These are found on a instantiation of a PacketLink interface so you will need a uses interface PacketLink statement in the wiring section of your module). You need to set the number of retries before calling AMSend.send. i.e you would need to have something that goes along the lines of:
#if defined(PACKET_LINK)
maxRetries = 100; //max retries
myDelay = 10; //delay between retries
call PacketLink.setRetries(&pkt, maxRetries); //set retries
call PacketLink.setRetryDelay(&pkt, myDelay); //set delay
#endif
3. In your configuration file you need to provide a Packetlink implementation instantiated and link it to your module. For instance if you are using a node with a CC2420 transceiver (such as the TelosB node) you would have the following in the implementation section of your configuration file.
components CC2420ActiveMessageC, myModuleP as App;
App.PacketLink -> CC2420ActiveMessageC.PacketLink;
What the above will do is compile the Packet Link Layer along with the rest the the Communication stack. You can look the PacketLinkP.nc file to see how the values you are passing to the PacketLink interface are being used.
If you are using the PacketLink interface and PacketAcknowledgements.wasAcked returns FALSE in your AMSend.sendDone method then it means transmission has still failed despite all the retries. You can at this point try a fresh retransmit again (which the device will again try to retransmit up to a total of maxRetries times).

windows kdmf driver virtio calling virtqueue_add_buf causes system fatal error

I have a driver for Windows VM that allows user space apps to communicate via IOCTL. I need to expose a structure to the host (using virtio) and I have tried using virtqueue_add_buf after initializing the virt device in the EvtDevicePrepareHardware using VirtIODeviceInitialize function. I am getting a fatal error when calling virtqueue_add_buf.
Below is a snippet of code
int TellHost(WDFOBJECT WdfDevice, VirtioQArg *virtioArg)
{
VIO_SG sg;
PDEVICE_CONTEXT context = GetDeviceContext(WdfDevice);
sg.physAddr = MmGetPhysicalAddress(virtioArg);
sg.length = sizeof(VirtioQCArg);
WdfSpinLockAcquire(context->VirtQueueLock);
error = virtqueue_add_buf(context->VirtQueue, &sg, 1, 0, virtioArg, NULL, 0);
// more code ....
WdfSpinLockRelease(context->VirtQueueLock);
}
The error I get is Fatal System Error: 0x000000d1 (0x0000000000000014,0x0000000000000002,0x0000000000000000,0xFFFFF80109FC0637)
Break instruction exception - code 80000003 (first chance)
and then windbg is unable to load symbols and crashes making my debugging session useless. Any ideas how I can debug this or what I might be missing?
0x000000d1 is DRIVER_IRQL_NOT_LESS_OR_EQUAL which almost always means invalid address is being referenced or addressing paged memory at DPC IRQL or higher.
0x0000000000000000 is a read access to invalid address (0x0000000000000014) from IRQL 2 (DPC).
I had not initialized the queue. Thanks to Vadim RozenFeld from Redhat for pointing out my mistake and his precise explanation.
I checked the balloon virtio driver which uses the following function for initialization of virtio queue.
PVIOQUEUE FindVirtualQueue(VIODEVICE *dev, ULONG index)
{
PVIOQUEUE pq = NULL;
PVOID p;
ULONG size, allocSize;
VirtIODeviceQueryQueueAllocation(dev, index, &size, &allocSize);
if (allocSize)
{
PHYSICAL_ADDRESS HighestAcceptable;
HighestAcceptable.QuadPart = 0xFFFFFFFFFF;
p = MmAllocateContiguousMemory(allocSize, HighestAcceptable);
if (p)
{
pq = VirtIODevicePrepareQueue(dev, index, MmGetPhysicalAddress(p), p, allocSize, p, FALSE);
}
}
return pq;
}