I have question about device removal.
When we want to notify PnP manager that device has disappeared we call IoInvalidateDeviceRelations with BusRelations. After that OS will send IRP_MN_QUERY_DEVICE_RELATIONS request with BusRelations. In this request handler we will exclude device from array and will do another necessary job to "disconnect" it from bus, also we will set RemovePending flag in its device extension.
I don't understand how to deal with incoming IO requests to the device after it becomes "remove pending" and before OS sends IRP_MN_REMOVE_DEVICE request. Should we check RemovePending flag and return STATUS_DEVICE_DOES_NOT_EXIST or should we proceed as usual?
Now imagine that IRP_MN_REMOVE_DEVICE request has finally arrived. MSDN says that we must call IoReleaseRemoveLockAndWait that releases the current acquisition of remove lock, prevents subsequent acquisitions and waits while existing acquisitions are released. So it forces us to always acquire remove lock inside PnP request handler with IoAcquireRemoveLock; and release it with IoReleaseRemoveLockAndWait for IRP_MN_REMOVE_DEVICE or with IoReleaseRemoveLock for another minor codes.
I don't understand why we need to acquire remove lock inside PnP request handler? In my understanding we need to acquire remove lock only for pending irp and release it when such irp is completed. So Windows folks could provide us with IoWaitForExistingRemoveLocks routine instead of IoReleaseRemoveLockAndWait.
Sorry if it's kinda messy, I just can't figure it out. Thanks.
After that OS will send IRP_MN_QUERY_DEVICE_RELATIONS request with
BusRelations. In this request handler we will exclude device from
array and will do another necessary job to "disconnect" it from bus,
also we will set RemovePending flag in its device extension.
here need only exclude device from array and set RemovePending flag in its device extension. but do another necessary job to "disconnect" it from bus - need do only when you process IRP_MN_REMOVE_DEVICE (after device was not included in the bus driver's most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations - or in another words - when RemovePending flag in its device extension)
how to deal with incoming IO requests to the device after it becomes
"remove pending" and before OS sends IRP_MN_REMOVE_DEVICE request.
Should we check RemovePending flag and return
STATUS_DEVICE_DOES_NOT_EXIST or should we proceed as usual?
i think possible both behavior - you can process it as usual and can return STATUS_DEVICE_DOES_NOT_EXIST too. and assume next situation - you get some IO request in concurrent with removal device process. when you check RemovePending flag - it yet not set. and you begin process request "as usual". but just after you check RemovePending flag inside IO request you can set it while handling IRP_MN_QUERY_DEVICE_RELATIONS request with BusRelations. and this situation direct related to sense using Remove Locks or Run-Down Protection.
we really can use Run-Down Protection instead Remove Locks almost in same way and exactly in same places and for same reason as Remove Locks. and i think Run-Down Protection api (more new compare remove locks) - better design and better for use (however different is minimal)
I don't understand why we need to acquire remove lock inside PnP
request handler?
first of all note that about remove lock said only in Removing a Device in a Function Driver. you how i understand have not function, but bus driver- so Removing a Device in a Bus Driver more suitable for you. and in documentation for Removing a Device in a Function Driver exist serious error - advice first call IoReleaseRemoveLockAndWait at point 4 - before point 8 - Pass the IRP_MN_REMOVE_DEVICE request down to the next driver. but correct must be
driver should call IoReleaseRemoveLockAndWait after it passes
the IRP_MN_REMOVE_DEVICE request to the next-lower driver, and
before it releases memory, calls IoDetachDevice, or calls
IoDeleteDevice.
this is correct and stated in Using Remove Locks and IoReleaseRemoveLockAndWait. funny that in old msdn versions was
call IoReleaseRemoveLockAndWait before it passes..
but now this is fixed. why after ? because next-lower driver can pending some IRPs (on which we call IoAcquireRemoveLock or ExAcquireRundownProtection) and complete it only when got IRP_MN_REMOVE_DEVICE and our driver call IoReleaseRemoveLock or ExReleaseRundownProtection only when this IRP will be completed. as result if call IoReleaseRemoveLockAndWait or ExWaitForRundownProtectionRelease before passes the remove IRP to the next-lower driver - we can wait here forever - next-lower driver can not complete some IRP (until not got remove request) and we not release remove lock or rundown protection.
so for what we need remove locks or rundown protection ? because we can got IRP_MN_REMOVE_DEVICE in concurrent with another IO requests. and this IO requests can use some resources on device. from another sized when we process IRP_MN_REMOVE_DEVICE we destroy this resources. what be if we will use some resource in IO request after he will be destroyed in IRP_MN_REMOVE_DEVICE ? think not need answer. for prevent this and exist removal locks or rundown protection. before use any resource (which will be destroyed in remove) need call IoAcquireRemoveLock or ExAcquireRundownProtection and use it only if ok status returned. after we finish use resource call IoReleaseRemoveLock or ExReleaseRundownProtection. and in IRP_MN_REMOVE_DEVICE we call IoReleaseRemoveLockAndWait or ExWaitForRundownProtectionRelease. after this call is returned - we can be sure that nobody use our resources and never will be used more (calls to IoAcquireRemoveLock or ExAcquireRundownProtection return error status (false)). at this point we can safe begin destroy resources: releases memory (etc), calls IoDetachDevice, IoDeleteDevice.
the pointer to the next-lower device - this is also resource, which we use in process IO request and destroy in IRP_MN_REMOVE_DEVICE (by call IoDetachDevice). really are correct call IofCallDriver(_nextDeviceObject, Irp); (while process some IO request) after call IoDetachDevice(_nextDeviceObject); (inside IRP_MN_REMOVE_DEVICE) ? because this removal locks (or i use yourself rundown-protection here ) always used in functions and filter drivers. for bus driver, where we usually have not pointer to the next-lower device (PDO not attached to another device, when FDO attached to PDO and filter always attached to something) - may be not need locks (or rundown protection at all). this is depend - are exist another resources - used and destroyed (on removal).
and for bus devices - usual situation when we got IRP_MN_REMOVE_DEVICE 2 time - first before device marked as RemovePending - so we go to point 4. and after device marked as RemovePending (so device was not included in the bus driver's most recent response to an IRP_MN_QUERY_DEVICE_RELATIONS request for BusRelations) we finally destroy resources and call IoDeleteDevice
Related
I have come across a scenario where two drivers (driver1 and driver2) are registering with kernel using module_init(). driver1 is configuring the chip and driver2 is accessing that chip, so driver1's module_init() has to be called before driver2's module_init() call. How we can create this order, as both driver1 and driver2 are registering at the same init call level (i.e using module_init()).
Can driver2 somehow determine that the chip has been properly configured, using either device status (preferred) or the value of a shared variable (messy)?
If so, then driver2's probe routine should return with -EPROBE_DEFER when the chip has not yet been configured (by driver1).
See https://lwn.net/Articles/485194/
drivercore: Add driver probe deferral mechanism
Allow drivers to report at probe time that they cannot get all the resources
required by the device, and should be retried at a later time.
This should completely solve the problem of getting devices
initialized in the right order. Right now this is mostly handled by
mucking about with initcall ordering which is a complete hack, and
doesn't even remotely handle the case where device drivers are in
modules. This approach completely sidesteps the issues by allowing
driver registration to occur in any order, and any driver can request
to be retried after a few more other drivers get probed.
I'd like to get event in kernel on each new process that starts (fork+execve or posix_spawn), and be able to prevent this operations.
The first option would be using Mac framework named mpo_vnode_check_exec by Hooking to this method with function that return 0 when access is granted or check deferred to next hook.. non zero returned value means access is refused right away.
Unfortunately, this framework is unsupported by apple, and I wish to use a stable alternative like kauth fileop scope with KAUTH_FILEOP_EXEC flag.
However, this framework is for detection only and lacks prevention capabilities..
Perhaps there's a way to prevent the process from running when I get relevant kauth callback on process creation, or halt the process from running until I decide whether it should run or not (and enforce the verdict in another thread).
thanks
However, this framework is for detection only and lacks prevention capabilities..
Correct, if you're only focussing on the File scope.
Register with the Vnode scope and your callback returns whether or not access is allowed.
kauth_listen_scope(KAUTH_SCOPE_VNODE, &myCallback, NULL);
Finally, note that this scope is very noisy, as every type of access to every resource is reported.
We need to handle IRQ in KMDF driver
I've registered EVT_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY callback function but system does not call it.
EVT_WDF_DEVICE_PREPARE_HARDWARE is called without any resources allocated.
Attempt to call WdfInterruptCreate() here results STATUS_INVALID_DEVICE_STATE
What is the right way to get free IRQ number from system and attach an interrupt handler?
Upd:
After we have successfully created WDFINTERRUPT object in our AddDevice handler system still does not ask us about resources (EVT_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY)
After discussion on social.msdn.microsoft.com we've found only one solution: use another OS
In KEXT, I am listening for file close via vnode or file scope listener. For certain (very few) files, I need to send file path to my system daemon which does some processing (this has to happen in daemon) and returns the result back to KEXT. The file close call needs to be blocked until I get response from daemon. Based on result I need to some operation in close call and return close call successfully. There is lot of discussion on KEXT communication related topic on the forum. But they are not conclusive and appears be very old (year 2002 around). This requirement can be handled by FtlSendMessage(...) Win32 API. I am looking for equivalent of that on Mac
Here is what I have looked at and want to summarize my understanding:
Mach message: Provides very good way of bidirectional communication using sender and reply ports with queueing mechansim. However, the mach message APIs (e.g. mach_msg, mach_port_allocate, bootstrap_look_up) don't appear to be KPIs. The mach API mach_msg_send_from_kernel can be used, but that alone will not help in bidirectional communication. Is my understanding right?
IOUserClient: This appears be more to do with communicating from User space to KEXT and then having some callbacks from KEXT. I did not find a way to initiate communication from KEXT to daemon and then wait for result from daemon. Am I missing something?
Sockets: This could be last option since I would have to implement entire bidirectional communication channel from KEXT to Daemon.
ioctl/sysctl: I don't know much about them. From what I have read, its not recommended option especially for bidirectional communication
RPC-Mig: Again I don't know much about them. Looks complicated from what I have seen. Not sure if this is recommended way.
KUNCUserNotification: This appears to be just providing notification to the user from KEXT. It does not meet my requirement.
Supported platform is (10.5 onwards). So looking at the requirement, can someone suggest and provide some pointers on this topic?
Thanks in advance.
The pattern I've used for that process is to have the user-space process initiate a socket connection to the KEXT; the KEXT creates a new thread to handle messages over that socket and sleeps the thread. When the KEXT detects an event it needs to respond to, it wakes the messaging thread and uses the existing socket to send data to the daemon. On receiving a response, control is passed back to the requesting thread to decide whether to veto the operation.
I don't know of any single resource that will describe that whole pattern completely, but the relevant KPIs are discussed in Mac OS X Internals (which seems old, but the KPIs haven't changed much since it was written) and OS X and iOS Kernel Programming (which I was a tech reviewer on).
For what it's worth, autofs uses what I assume you mean by "RPC-Mig", so it's not too complicated (MIG is used to describe the RPC calls, and the stub code it generates handles calling the appropriate Mach-message sending and receiving code; there are special options to generate kernel-mode stubs).
However, it doesn't need to do any lookups, as automountd (the user-mode daemon to which the autofs kext sends messages) has a "host special port" assigned to it. Doing the lookups to find an arbitrary service would be harder.
If you want to use the socket established with ctl_register() on the KExt side, then beware: The communication from kext to user space (via ctl_enqueuedata()) works OK. However opposite direction is buggy on 10.5.x and 10.6.x.
After about 70.000 or 80.000 send() calls with SOCK_DGRAM in the PF_SYSTEM domain complete net stack breaks with disastrous consequences for complete system (hard turning off is the only way out). This has been fixed in 10.7.0. I workaround by using setsockopt() in our project for the direction from user space to kext as we only send very small data (just to allow/disallow some operation).
I'm pulling my hair trying to figure out when a serial port finishes closing so I can reopen it. It turns out that CloseHandle() returns before the port is actually unlocked.
I am opening a serial port using CreateFile(FILE_FLAG_OVERLAPPED), associating it with a CompletionPort using CreateIoCompletionPort(), reading/writing to it using ReadFile(), WriteFile() and closing it using CloseHandle().
I've noticed that if I close and reopen a serial port quickly enough, I get an ERROR_ACCESS_DENIED back from CreateFile(). This is happening in spite of the fact that I'm waiting for CloseHandle() to return, then waiting for all outstanding read/write operations associated with that handle to come back from the completion port. Surely there is a better way :)
How do I close a serial port synchronously? Please no retry loops, sleep() or some other cheap hacks.
EDIT: Maybe this has something to do with my use of completion ports and FILE_FLAG_OVERLAPPED. I get a callback when the read/write operations complete. Is there some sort of callback for the port closing?
I believe the problem is with the driver that serves the COM port. Hence - there'll be no API to "actually close" the COM port.
BTW, after you close the file handle, there's no need to wait for all oustanding I/Os to complete with errors. At the time CloseHandle returns all outstanding I/Os are already completed/cancelled, you just receive the callbacks asynchronously (be it via completion port or APC queue, no matter).
Specifically FTDI drivers (those that emulate COM->USB) are known to be very glitchy.
I may only recommend to try flushing the data before closing the handle. You may wait for all I/Os to complete before closing the COM port (if this is applicable for your case). Alternatively you may call SetCommMask and WaitCommEvent to ensure there's no send data pending. Hopefully this may help.
EDIT:
Does CloseHandle immediately (before it returns) cancel all the pending I/Os on the file handle?
Strictly speaking - no.
There may be other references left to the file object. For example, a user-mode code may call DuplicateHandle, or a kernel-mode driver may call ObReferenceObjectByXXXX. In such a case the object the handle refers to is not necessarily released.
When the last handle is closed the driver's DispatchCleanup is called. It must cancel all the outstanding I/Os according to this.
However while one thread is within a CloseHandle - you may theoretically issue another I/O from another thread (if you're lucky - the handle will still be valid). While you're in the call to an I/O function (such as WriteFile or etc.) the OS temporarily increases the reference counter to the object. This in turn may start another I/O, which won't be cancelled directly by the CloseHandle invocation.
However in this case the handle will be closed by the O/S immediately after the new I/O is issued, because the reference count to the object reached 0 again.
So that in such a perverted scenario there may happen a situation where immediately after a call to CloseHandle you're unable to reopen the file again.
Ensure that your reader and writer fail (with invalid handle) after you have issued the CloseHandle() request (presumably on some other thread) before attempting to touch the device again. You can use this as a cue to clean up all your io handling before attempting to issue another CreateFile. I must say completion ports do seem needlessly baroque.
When you open a COM Port in a thread, the operating system opens another hidden thread to do the I/O. I am trying to resolve closing a port as well. Near as I can tell one method which may work is: 1) Suspend the thread which opened the COM Port, 2) PurgeComm() to stop all I/O and empty all read/write I/O buffers, and 3) then attempt to close the COM Port. There may be a waitforsingleobject involved to determine when the thread with the COM Port actually suspends. Unless the COM Port absolutely needs to be closed, I am considering leaving the COM Port open and letting the WinProc process the IDM_Exit command to close the COM Port, threads, and the application. Not what I wanted but an option I could live with. I am using a USB to Serial Port connection and not sure what problems this is causing me. I know if you are using an USB to Serial Port interface you need to set pin 20 high (DTR). Pin 20 helps power the interface, but is only providing around 30ma or so. If all this works I will make an update to this post and let you know how if I was able to close the COM Port. Windows has made a mess of the Serial Port driver and seem to be content to leave things in disarray!