How to handle USBIO operation during FmpDxe update capsule flow? - uefi

According to the instructions of edk2-platforms, I can build MinnowMax.cap and CapsuleApp.efi.
Build command: build -a IA32 -a X64 -n 5 -t VS2019 -b DEBUG -p Vlv2TbltDevicePkg\PlatformPkgX64.dsc
reference:
https://github.com/tianocore/edk2-platforms/tree/master/Platform/Intel/Vlv2TbltDevicePkg
My system: MinnowMax board.
I can update capsule data to MinnowMax SPI flash with the following command:
Shell command: CapsuleApp MinnowMax.cap
But when I try to write data to an external USB device, I get an error. My modifications are as follows:
\edk2-platforms\Platform\Intel\Vlv2TbltDevicePkg\Feature\Capsule\Library\PlatformFlashAccessLib\PlatformFlashAccessLib.c
EFI_STATUS
EFIAPI
PerformFlashAccessLibConstructor (
VOID
)
{
EFI_STATUS Status;
Status = gBS->LocateProtocol(
&gEfiUsbIoProtocolGuid,
NULL,
(VOID**)&gUsbIOWDT
);
if (EFI_ERROR(Status)) return Status; //unsupport
return Status;
}
The error message is Status : EFI_NOT_FOUND.
Among them, PerformFlashAccessLibConstructor is executed in the FmpDxe(Minnow) driver, and it refers to the following method of Vlv2TbltDevicePkg:
Status = gBS->LocateProtocol (
&gEfiSpiProtocolGuid,
NULL,
(VOID **) &mSpiProtocol
);
My questions are:
How to handle USBIO operation during FmpDxe update capsule flow? Is
there any sample code?
In FmpDxe, it can pass the gEfiSpiProtocolGuid parameter in the LocateProtocol function to get
the handle. Why does passing gEfiUsbIoProtocolGuid cause an error? How should it be modified?
Any suggestion is greatly appreciated!
Thanks!

Related

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

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

Writing my first EFI application with gnu-efi [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I got an Alexa device and I’m using an esp8266 to get request from the echo dot.
I can wake on lan my Pc but it’s not enough. I have windows and Linux on my Pc so I thought “I need some code to run before boot so I can communicate with my esp8266 to know witch os should be booted”. So I started searching everywhere to find a solution and I think I’m really close to it. What I did was to put the efi-shell as main boot, let it execute the startup.nsh.
In this startup.nsh I want to start my efi application who can communicate with the esp8266.
Is this the right way to do this thing? Should I do something else?
The problem is that I can’t code this app. I can’t understand how to use protocols and which protocols are the solutions. The application should send a simple character to the esp to let it know that the computer is ready to get boot instruction. The esp should reply “1” for windows or “2” for Linux.
Can someone give me some advices for this task? Is it the right way or am I doing a lot of useless stuff? Maybe exists a better way
Here is a sample how to load and start an UEFI application with EDK2, porting it to gnu-efi should be an easy task, wrap all gBS-> calls with the uefi_call_wrapper.
Based on the response from the esp8266 you have to start the Linux or Windows loader application.
I posted an UDP sample as answer to your first question.
#include <Uefi.h>
#include <Library\UefiLib.h>
#include <Protocol\LoadedImage.h>
#include <Protocol\DevicePath.h>
#include <Library\DevicePathLib.h>
#ifndef LOG
#define LOG(fmt, ...) AsciiPrint(fmt, __VA_ARGS__)
#endif
#ifndef TRACE
#define TRACE(status) LOG("Status: '%r', Function: '%a', File: '%a', Line: '%d'\r\n", status, __FUNCTION__, __FILE__, __LINE__)
#endif
extern EFI_BOOT_SERVICES *gBS;
/*
Configuration
*/
static CHAR16 gFilePath[] = L"\\Tools\\Udp4Sample.efi";
EFI_STATUS
EFIAPI
UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE *LoadedImageProtocol = NULL;
EFI_DEVICE_PATH_PROTOCOL *AppDevicePath = NULL;
EFI_HANDLE AppHandle = NULL;
/*
Step 1: Handle the LoadedImageProtocol of the current application
*/
Status = gBS->HandleProtocol(
ImageHandle,
&gEfiLoadedImageProtocolGuid,
&LoadedImageProtocol);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 2: Create a device path that points to the application, the application must be located on the same device (partition) as this one
*/
AppDevicePath = FileDevicePath(LoadedImageProtocol->DeviceHandle, gFilePath);
if (!AppDevicePath) {
TRACE(EFI_INVALID_PARAMETER);
// Error handling
return EFI_INVALID_PARAMETER;
}
/*
Step 3: Load the application
*/
Status = gBS->LoadImage(
FALSE,
ImageHandle,
AppDevicePath,
NULL,
0,
&AppHandle);
gBS->FreePool(AppDevicePath);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
/*
Step 4: Start the application
*/
Status = gBS->StartImage(
AppHandle,
NULL,
NULL);
if (EFI_ERROR(Status)) {
TRACE(Status);
// Error handling
return Status;
}
return EFI_SUCCESS;
}

How can I extend the window reuse code paths in vscode and Azure Data Studio?

I am working in the microsoft/azuredatastudio github repo, which is largely forked from vscode. I am trying to extend our command line processing to handle the window reuse parameter such that if we pass a server connection along with -r that we will open the specified connection. Our current command line processing service is loaded by src\vs\workbench\electron-browser\workbench.ts in Workbench.initServices.
Is there any platform-provided service that is visible to both electron-main and workbench\electron-browser that I could modify or leverage to be informed of the app being reused with new command line arguments?
I've found that the LaunchService defined in src\vs\code\electron-main\launch.ts appears to be responsible for capturing the arguments and opening or reusing the window, but it's not clear how I would marshal a notification from the LaunchService over to our services that are loaded by workbench.
2/12/2019 update:
It looks like I need to add an equivalent of this function in src\vs\code\electron-main\windows.ts
private doOpenFilesInExistingWindow(configuration: IOpenConfiguration, window: ICodeWindow, filesToOpen: IPath[], filesToCreate: IPath[], filesToDiff: IPath[], filesToWait: IPathsToWaitFor): ICodeWindow {
window.focus(); // make sure window has focus
window.ready().then(readyWindow => {
const termProgram = configuration.userEnv ? configuration.userEnv['TERM_PROGRAM'] : void 0;
readyWindow.send('vscode:openFiles', { filesToOpen, filesToCreate, filesToDiff, filesToWait, termProgram });
});
return window;
}
which has a new message like 'ads:openconnection' . Now to find out how to handle the message.
I ended up using ipcRenderer service and adding an ipc call to the launch service in main.
// {{SQL CARBON EDIT}}
// give the first used window a chance to process the other command line arguments
if (args['reuse-window'] && usedWindows.length > 0 && usedWindows[0])
{
let window = usedWindows[0];
usedWindows[0].ready().then(() => window.send('ads:processCommandLine', args));
}
// {{SQL CARBON EDIT}}

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;
}

Postgres trigger notify with PHP

I have a problem or misunderstanding with Postgre trigger -> perform notify -> capture into PHP flow.
My Platform is PHP(5.6) in centos with Postgres.
I have to add trigger with notifications table and whenever a new notification is added to that notifications SMS has to send to that user.
So here added trigger like this
CREATE FUNCTION xxx_sms_trigger() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
PERFORM pg_notify('sms', NEW.id||'' );
RETURN new;
END;
and in php the inserting new notifications work fine.
Now I have a separate file where added this capturing pg_notify triggering by "pg_get_notify", here I couldn't get this flow totally like how Postgres can trigger some unknown php script without its being running as service or how I can make it work?
You do need a php script running as a service. If that is going to be the language that receives the notification you provide. As #FelipeRosa says, that script will need to connect to the database, then issue at least one command:
listen sms;
There is a good example of the listen on the main site (http://www.php.net/manual/en/function.pg-get-notify.php)
I haven't coded in php in a few years. Recently I have implemented this logic in python, but it should be about the same. I did a little research, and I can find select() in php, but it seems that the postgres socket descriptor is not available in php, so you can't use the select() in php unless you can find the postgres socket descriptor.
Anyway, that thread is here (http://postgresql.1045698.n5.nabble.com/Is-there-any-way-to-listen-to-NOTIFY-in-php-without-polling-td5749888.html). There is a polling example in there for your php script side down near the bottom. You can do the listen as previous selected (once), then put your pg_get_notify() in a loop with a sleep in there for the amount of time you are willing to queue notifications.
Just fwiw, in python I don't poll, I select.select(pg_conn,...), when data arrives on the postgres connection I check it for notifications, so there is no 'polling'. It would be nice if you could find a way to use select() in php instead of looping.
-g
Here’s a cohesive example that registers an interest in a table insertion, waits for notification (or timeout) and responds to the caller. We use a timestamp preceded by the letter ‘C’ to identify the notification channel since Postgres requires the channel name to be a proper identifier.
Postgres SQL
/* We want to know when items of interest get added to this table.
Asynchronous insertions possible from different process or server */
DROP TABLE IF EXISTS History;
CREATE TABLE History (
HistoryId INT PRIMARY KEY,
MYKEY CHAR(17),
Description TEXT,
TimeStamp BIGINT
);
/* Table of registered interest in a notification */
DROP TABLE IF EXISTS Notifications;
CREATE TABLE Notifications (
NotificationId INT PRIMARY KEY,
Channel VARCHAR(20),
MYKEY CHAR(17)
);
/* Function to process a single insertion to History table */
CREATE OR REPLACE FUNCTION notify_me()
RETURNS trigger AS
$BODY$
DECLARE ch varchar(20);
BEGIN
FOR ch IN
SELECT DISTINCT Channel FROM Notifications
WHERE MYKEY=NEW.MYKEY
LOOP
/* NOTIFY ch, 'from notify_me trigger'; */
EXECUTE 'NOTIFY C' || ch || ', ' || quote_literal('from notify_me') || ';';
DELETE FROM Notifications WHERE Channel=ch;
END LOOP;
RETURN NULL;
END;
$BODY$
LANGUAGE 'plpgsql';
/* Trigger to process all insertions to History table */
DROP TRIGGER IF EXISTS HistNotify ON History CASCADE;
CREATE TRIGGER HistNotify AFTER INSERT ON History
FOR EACH ROW EXECUTE PROCEDURE notify_me();
PHP code
// $conn is a PDO connection handle to the Postgres DB
// $MYKEY is a key field of interest
$TimeStamp = time(); // UNIX time (seconds since 1970) of the request
$timeout = 120; // Maximum seconds before responding
// Register our interest in new history log activity
$rg = $conn->prepare("INSERT INTO Notifications (MYKEY, Channel) VALUES (?,?)");
$rg->execute(array($MYKEY, $TimeStamp));
// Wait until something to report
$conn->exec('LISTEN C'.$TimeStamp.';'); // Prepend ‘C’ to get notification channel
$conn->exec('COMMIT;'); // Postgres may need this to start listening
$conn->pgsqlGetNotify (PDO::FETCH_ASSOC, $timeout*1000); // Convert from sec to ms
// Unregister our interest
$st = $conn->prepare("DELETE FROM Notifications WHERE Channel=?");
$st->execute(array($TimeStamp));
Here is an example how to migrate the "Python way" mentioned by #Greg to PHP. After starting the script below - open a new connection to the postgres db and query NOTIFY "test", 'I am the payload'
Sources:
http://initd.org/psycopg/docs/advanced.html#asynchronous-notifications
https://gist.github.com/chernomyrdin/96812377f1ac5bf567b8
<?php
$dsn = 'user=postgres dbname=postgres password=postgres port=5432 host=localhost';
$connection = \pg_connect($dsn);
if (\pg_connection_status($connection) === \PGSQL_CONNECTION_BAD) {
throw new \Exception(
sprintf('The database connect failed: %s', \pg_last_error($connection))
);
}
\pg_query('LISTEN "test"');
while (true) {
$read = [\pg_socket($connection)];
$write = null;
$except = null;
$num = \stream_select(
$read,
$write,
$except,
60
);
if ($num === false) {
throw new \Exception('Error in optaining the stream resource');
}
if (\pg_connection_status($connection) !== \PGSQL_CONNECTION_OK) {
throw new \Exception('pg_connection_status() is not PGSQL_CONNECTION_OK');
} elseif ($num) {
$notify = \pg_get_notify($connection);
if ($notify !== false) {
var_dump($notify);
}
}
}
According to this you should first make the application listen to the desired channel issuing the command "LISTEN ", via pg_query for example, before you can notify messages to the application.
Its a litte example:
The PHP script (I named it teste.php - It's the same at http://php.net/manual/pt_BR/function.pg-get-notify.php):
$conn = pg_pconnect("dbname=mydb");
if (!$conn) {
echo "An error occurred.\n";
exit;
}
while(true){
pg_query($conn, 'LISTEN SMS;');
$notify = pg_get_notify($conn);
if (!$notify) {
echo "No messages\n";
// change it as u want
} else {
print_r($notify);
//your code here
}
sleep(2);
}
Keep the script runnig (I assumed u are using linux):
php teste.php > log.txt 2>&1 &
Note that:
2>&1 redirects both standard output and standard error into the log.txt file.
& runs the whole thing in the background
You can follow the log.txt with this command:
tail -f log.txt