注意:这不是我遇到的问题,但这是我想要的
喜欢理解(只是因为我
想要成为一个更好的人,并且
进一步拓展人类的视野
理解)。
在 Raymond Chen 的 图书,
Raymond 给出了声卡驱动程序中的错误示例:
原始函数,调用于
硬件中断时间,看起来像
DDK 中的这个:
void FAR PASCAL midiCallback(NPPORTALLOC pPortAlloc, WORD msg,
双字 dwParam1、双字 dwParm2) {
if (pPostAlloc->dwCallback)
DriverCallBack(pPortalloc->dwCallback, HIWORD(pPortalloc->dwFlags),
pPortalloc->hMidi,msg,dwParam1,dwParam2);
}
他们的函数版本看起来
像这样:
void FAR PASCAL midiCallback(NPPORTALLOC pPortAlloc, WORD msg,
双字 dwParam1、双字 dwParm2) {
字符 szBuf[80];
if (pPostAlloc->dwCallback) {
wsprintf(szBuf, " Dc(hMidi=%X,wMsg=%X)", pPortalloc->hMidi, msg);
#ifdef 调试
输出调试字符串(szBuf);
#endif
DriverCallBack(pPortalloc->dwCallback, HIWORD(pPortalloc->dwFlags),
pPortalloc->hMidi,msg,dwParam1,dwParam2);
}
}
零售代码中不仅存在剩余的调试内容,而且
调用非中断安全函数
在硬件中断时间。如果
wsprintf
函数曾经获得过
丢弃后,系统将采取
段内不存在故障
硬件中断,这会导致
死得很快。
现在,如果我查看该代码,我不会猜到对库函数 wsprintf 会是一个问题。如果我的驱动程序代码需要使用 Win32 API,会发生什么情况?
什么是段错误?我理解页面错误的概念:我需要的代码位于已换出到硬盘驱动器的页面上,并且需要在代码执行之前从硬盘驱动器返回可以继续。当我们处于设备驱动程序的中断内部时,什么是段错误?
页面错误保护模式是否等同于段错误?如何避免段错误? Windows 是否会交换设备驱动程序代码?我如何阻止“wsprintf被丢弃”?什么会导致 wsprintf 被“丢弃”?什么是“废弃”?舍弃有何功德?当它un被丢弃时
为什么从驱动程序内部调用 API 调用是不好的,以及如何解决它?
Note: This is not a problem i'm experiencing, but it is something i'd
like to understand (just because i
want to be a better person, and to
further the horizon of human
understanding).
In the bonus chapter of Raymond Chen's book,
Raymond gives the example of a bug in a sound card driver:
The original function, called at
hardware interrupt time, looks like
this in the DDK:
void FAR PASCAL midiCallback(NPPORTALLOC pPortAlloc, WORD msg,
DWORD dwParam1, DWORD dwParm2) {
if (pPostAlloc->dwCallback)
DriverCallBack(pPortalloc->dwCallback, HIWORD(pPortalloc->dwFlags),
pPortalloc->hMidi, msg, dwParam1, dwParam2);
}
Their version of the function looked
like this:
void FAR PASCAL midiCallback(NPPORTALLOC pPortAlloc, WORD msg,
DWORD dwParam1, DWORD dwParm2) {
char szBuf[80];
if (pPostAlloc->dwCallback) {
wsprintf(szBuf, " Dc(hMidi=%X,wMsg=%X)", pPortalloc->hMidi, msg);
#ifdef DEBUG
OutputDebugString(szBuf);
#endif
DriverCallBack(pPortalloc->dwCallback, HIWORD(pPortalloc->dwFlags),
pPortalloc->hMidi, msg, dwParam1, dwParam2);
}
}
Not only is there leftover debug stuff in retail code, but it is
calling a noninterrupt- safe function
at hardware interrupt time. If the
wsprintf
function ever gets
discarded, the system will take a
segment-not-present fault inside a
hardware interrupt, which leads to a
pretty quick death.
Now if i'm looking at that code i wouldn't have guessed that a call to the library function wsprintf would be a problem. What happens if my driver code needs to make use of the Win32 API?
What is a segment fault? i understand the concept of a page-fault: the code i need is sitting on a page that has been swapped out to the hard-drive, and will need to get back from the hard drive before code execution can continue. What is a segment fault when we're inside a device-driver's interrupt?
Is page-faults the protected mode equivalent of a segment-fault? How does one avoid segment faults? Does Windows ever swap out device driver code? How would i stop "wsprintf from being discarded"? What would cause wsprintf to be "discarded"? What is "discarded"? What is the virtue of discarding? When it something undiscarded
Why is calling an API call from inside a driver bad, and how would one work around it?
发布评论
评论(1)
分段错误通常是指无效的内存访问。在大多数现代操作系统中,生成段错误的机制也用于提供请求分页机制。他们倾向于做的是将内存页面“交换”到磁盘并将其标记为无效,下次指令访问该内存位时,内核会识别出它实际上并不是一个错误,并且将在内存中分页。
Windows 无法处理某些上下文中的页面错误,其中之一就是中断。这就是它的设计方式。例如,假设您在从磁盘驱动器读取内存页面数据的代码中遇到页面错误,如何处理这种情况?因此,他们对允许寻呼和不允许寻呼的操作模式定义了某些限制。如果在中断中导致页面错误,内核将强制出现 BSOD。
如果您需要执行可能需要分页的操作,那么您应该在中断上下文中执行的操作是对所谓的延迟过程调用进行排队(DPC) 在中断处理程序中。然后,DPC 在 DPC 级别执行(如果您阅读 DDK 函数的一些描述,您会看到提到的内容)。 DPC级别可以分页,因此您可以使用您需要的任何功能。
至于驱动程序的内容,您可以将某些代码标记为不可分页,并且可以分配非分页池,这是您可以访问而不会导致页面错误的内存。 wsprintf 可能会被调出,因为没有人使用它并且内核回收内存。
A segmentation fault normally refers to an invalid memory access. In most modern operating systems the mechanism which generates seg-faults is also used to provide the demand paging mechanism. What they tend to do is "swap" pages of memory out to disc and mark them as invalid, the next time an instruction accesses that bit of memory the kernel recognises that it isn't really an error and will page in memory.
Windows cannot handle page-faults in certain contexts, one of them being in an interrupt. That is just the way it is designed. For example imagine you get a page fault in the code which reads memory pages data from the disk drive, how could it possible handle such an occurrance? So they define certain limitations on what modes of operation are allowed to page and what are not. If you cause a page fault in an interrupt the kernel will force a BSOD.
What you are supposed to do in an interrupt context if you need to do something which might need paging is to queue what is called a Deferred Procedure Call (DPC) in the interrupt handler. The DPC is then executed at DPC level (something you will see mentioned if you read some of the descriptions of DDK functions). DPC level can page and so you can use any function you need.
As for driver stuff, you can mark some of your code as non-pageable and you can allocate non-paged-pool which is memory you can access without causing page-faults. wsprintf could be paged out because no-one has used it and the kernel reclaims the memory.