Note: Use an xHCI debug port for Kernel debugging on Windows/Linux

xHCI 在Intel 平台已經是標準內建的功能,Intel 早期在EHCI 就有加入一個Debug Port 功能,但是基於 EHCI 的Host<->Client半雙工模式設計,它必須透過外部一個USB Device 去做Host/Target的資料交換,又EHCI Controller 上只有 Port 0 可以提供這個功能,變成硬體設計與使用設定上都相對複雜,所以只有相對少數的工程師會去使用這個功能,通常是開發Windows Kernel Driver 的才會需要。

而Intel 在發展XHCI 時,因為USB3 已經是TX/RX分離,所以這次規格變成可以直接兩個Host Port 對接, 一條USB 3 的Debug Cable 實際上就是把 USB 2.0 的 D+/D- 跟Power(VBUS) 斷掉, 然後把USB 3的SS TX/SS RX 交換而已
enter image description here

所以現在開發UEFI/Windows/Linux Kernel mode driver 都支援透過xHCI 的這個內建功能去做,不過有些外接的xHCI Host Controller 並沒有實作這個 DbC (Debug Capability Class)

Microsoft 關於Kernel Debug 的設定
Intel 關於Linux 的Kernel mode 設定 — 這已經併入Vanilla Kernel stream 的文件目錄了,可以看到Linux 下就是把它當tty用

廣告

Note: Vendor ACPI Driver on Windows

之前寫了一些 ACPI Driver 相關的紀錄, 最近看到USB Type C connector for Windows 10 如果不做PD State Machine,下面也需要ACPI Driver 去協調 MCU/EC 所以整理一下手上有的資料 順便重新整理一下網路上很多消失的檔案

ACPIDriver Vista — 這個是Microsoft 最早提供的文件,不過根據實際經驗應該Windows XP 就支援這些功能
ACPI in Vista — 這是早期 WinHEC 2006 的 Presatations
BIOS implement of UCSI — Intel 這是Intel 講如何實作USB Type C Connector System Interface

older WDM/DDK Sample from Windows 2000

這邊提供實際原始碼的實作內容

Older WDM driver implement – 實作了Customer GPIO Button/Indicator LED, 應該是 Intel 用來Demo MID (Mobile Internal Device)做的
Current WDF Driver implement for UCSI - 這就是Microsoft 實作UCSI 的參考Driver了 可以搭配Intel 文件跟 Microsoft 網站資料一起看

下面是想更了解UCSI可以參考的資料
https://www.usb.org/developers/presentations/  — 2017 USB Developer Days  in Taipei

Update:
Linux 下的實作也有 Intel 提交的標準
https://github.com/torvalds/linux/tree/master/drivers/usb/typec/ucsi
所以盡可能透過在使用ACPI/ASL implement 去做這個功能,這樣Windows/Linux 下都有inbox driver 不用另外提供特殊的 customization driver
不過要透過標準UCSI 有一個地方考慮的是成本, 標準UCSI 界面是由 ACPI + EC + PD Controller 構成的,需要付出比較多的成本,目前已經有一個新的方式透過提供軟體的TCPM 取代PD Controller 如下圖 這個架構仍然需要一個MCU 去控制Type C 的界面行為, 系統透過I2C之類的下PD Policy 的行為給MCU

TCPCx

ref. https://www.mail-archive.com/linux-usb@vger.kernel.org/msg92179.html

Note: Previous releases of the WDK/DDK

Update: currently MS has been close the program, so the link is invalid.

https://connect.microsoft.com/site148/Downloads/DownloadDetails.aspx?DownloadID=21028, need join Microsoft Connect project!

current provide the below DDK/WDK

GRMWDK_EN_7600 – WDK for Windows 7

6001.18002 – WDK for Windows Server 2008, Vista Sp1

6000 – WDK for Vista

1830 – DDK for Windows Server 2003 SP1

winddk.rtm.iso – DDK for Windows 2000

Note: 剖析 ACPIEC Part II – AddDevice & Create Device Object

還是把 AcpiEcAddDevice 拿出來, 基本做的就一般 Function/Filter driver要做的事!
AddDevice會由PNP Manager 傳進兩個Parameters, 一個是 本身的Driver Object 另一個是Physical Device Object
一開始會按照標準的Function Driver 一般去建立 FDO (Function Device Object), 這是透過AcpiEcCreateFdo() 來實現的

在AcpiEcCreateFdo()內就是簡單的呼叫 IoCreateDevice() 去Create該FDO, 取得FDO 之後, 將其參數初始化與建立同步物件

取得FDO後, 透過 IoAttachDeviceToDeviceStack() 把FDO掛上

NTSTATUS
AcpiEcAddDevice(
IN PDRIVER_OBJECT   DriverObject,
IN PDEVICE_OBJECT   Pdo
)

/*++

Routine Description:

This routine creates functional device objects for each AcpiEc controller in the
system and attaches them to the physical device objects for the controllers

Arguments:

DriverObject       – a pointer to the object for this driver
PDO                  – a pointer to where the FDO is placed

Return Value:

Status from device creation and initialization

–*/

{
PDEVICE_OBJECT  fdo = NULL;
PDEVICE_OBJECT  ownerDevice = NULL;
PDEVICE_OBJECT  lowerDevice = NULL;
PECDATA         EcData;
NTSTATUS        status;

PAGED_CODE();

EcPrint(EC_LOW, (“AcpiEcAddDevice: Entered with pdo %xn", Pdo));

if (Pdo == NULL) {

//
// Have we been asked to do detection on our own?
// if so just return no more devices
//

EcPrint(EC_LOW, (“AcpiEcAddDevice – asked to do detectionn"));
return STATUS_NO_MORE_ENTRIES;
}

//
// Create and initialize the new functional device object
//

status = AcpiEcCreateFdo(DriverObject, &fdo);

if (!NT_SUCCESS(status)) {

EcPrint(EC_LOW, (“AcpiEcAddDevice – error creating Fdon"));
return status;
}

//
// Layer our FDO on top of the PDO
//

lowerDevice = IoAttachDeviceToDeviceStack(fdo,Pdo);

//
// No status. Do the best we can.
//
ASSERT(lowerDevice);

EcData = fdo->DeviceExtension;
EcData->LowerDeviceObject = lowerDevice;
EcData->Pdo = Pdo;

//
// Allocate and hold an IRP for Query notifications, and miscellaneous
//
EcData->IrpSize         = IoSizeOfIrp (EcData->LowerDeviceObject->StackSize);
EcData->QueryRequest    = IoAllocateIrp (EcData->LowerDeviceObject->StackSize, FALSE);
EcData->MiscRequest     = IoAllocateIrp (EcData->LowerDeviceObject->StackSize, FALSE);

if ((!EcData->QueryRequest) || (!EcData->MiscRequest)) {
//
// NOTE: This failure case and other failure cases below should do
// cleanup of all previous allocations, etc performed in this function.
//

EcPrint(EC_ERROR, (“AcpiEcAddDevice: Couldn’t allocate Irpn"));
return STATUS_INSUFFICIENT_RESOURCES;
}

//
// Link this fdo to the list of fdo’s managed by the driver
// (Probably overkill since there will be only one FDO)
//
//
EcPrint(EC_LOW, (“AcpiEcAddDevice: linking fdo to listn"));
EcData->NextFdo = FdoList;
InterlockedExchangePointer((PVOID *) &FdoList, fdo);

//
// Get the GPE vector assigned to this device
//

status = AcpiEcGetGpeVector (EcData);
if (!NT_SUCCESS(status)) {

EcPrint(EC_LOW, (“AcpiEcAddDevice: Could not get GPE vector, status = %Lxn", status));
return status;
}

//
// Get the direct-call ACPI interfaces.
//

status = AcpiEcGetAcpiInterfaces (EcData);
if (!NT_SUCCESS(status)) {

EcPrint(EC_LOW, (“AcpiEcAddDevice: Could not get ACPI driver interfaces, status = %Lxn", status));
return status;
}

//
// Final flags
//

fdo->Flags &= ~DO_DEVICE_INITIALIZING;
fdo->Flags |= DO_POWER_PAGABLE;             // Don’t want power Irps at irql 2

return STATUS_SUCCESS;
}

 

NTSTATUS
AcpiEcCreateFdo(
IN PDRIVER_OBJECT   DriverObject,
OUT PDEVICE_OBJECT  *NewDeviceObject
)

/*++

Routine Description:

This routine will create and initialize a functional device object to
be attached to a Embedded controller PDO.

Arguments:

DriverObject – a pointer to the driver object this is created under
DeviceObject – a location to store the pointer to the new device object

Return Value:

STATUS_SUCCESS if everything was successful
reason for failure otherwise

–*/

{
UNICODE_STRING  unicodeString;
PDEVICE_OBJECT  deviceObject;
NTSTATUS        Status;
PECDATA         EcData;

PAGED_CODE();

EcPrint(EC_LOW, (“AcpiEcCreateFdo: Entryn") );

RtlInitUnicodeString(&unicodeString, L"\Device\ACPIEC");

Status = IoCreateDevice(
DriverObject,
sizeof (ECDATA),
&unicodeString,
FILE_DEVICE_UNKNOWN,    // DeviceType
0,
FALSE,
&deviceObject
);

if (Status != STATUS_SUCCESS) {
EcPrint(EC_LOW, (“AcpiEcCreateFdo: unable to create device object: %Xn", Status));
return(Status);
}

deviceObject->Flags |= DO_BUFFERED_IO;
deviceObject->StackSize = 1;

//
// Initialize EC device extension data
//

EcData = (PECDATA) deviceObject->DeviceExtension;
EcData->DeviceObject        = deviceObject;
EcData->DeviceState         = EC_DEVICE_WORKING;
EcData->QueryState          = EC_QUERY_IDLE;
EcData->IoState             = EC_IO_NONE;
EcData->IsStarted           = FALSE;
EcData->MaxBurstStall       = 50;
EcData->MaxNonBurstStall    = 10;
EcData->InterruptEnabled    = TRUE;

//
// Initialize EC global synchronization objects
//

InitializeListHead (&EcData->WorkQueue);
KeInitializeEvent (&EcData->Unload, NotificationEvent, FALSE);
KeInitializeSpinLock (&EcData->Lock);

*NewDeviceObject = deviceObject;
return STATUS_SUCCESS;

}

 

Note: 剖析ACPIEC Part I

在 Windows 平台上, 從 Win98 就開始引入 ACPI and ACPIEC driver stack, 好玩的是就Microsoft 有提供的source code(早期的DDK有附, Win2000) 看來, 實際上 ACPIEC.Sys 的Source code 應該是Intel 的 Bob Moore 所撰寫, 而我現在實測編譯出來的binary size 為 12.1KB(12,416Byte) 比XP Sp3還大一點, 底下是Build log, 研判應該是編譯參數問題, 有 9成的把握該Driver 在 XP 還是依據這個原始的Source, 要注意的是這個source 並不在 6001.18001內, 這是從舊的DDK內取出的!(Update: http://www.osronline.com/showthread.cfm?link=150332 跟據這個討論串中由 Jake Oshins/MSFT 指出從Vista開始已經將 ACPIEC一些功能直接整進 ACPI.SYS了)

BUILD: Computing Include file dependencies:
BUILD: Examining c:winddk6001.18001srcwdmacpiecec directory for files to compile.
skipping post pass 0 command
Compiling and Linking c:winddk6001.18001srcwdmacpiecec *************
‘nmake.exe /nologo BUILDMSG=Stop. -i BUILD_PASS=PASS2 LINKONLY=1 NOPASS0=1 MAKEDIR_RELATIVE_TO_BASEDIR=srcwdmacpiecec’
c:winddk6001.18001srcwdmacpiecec: TARGETPATH is obj
BUILDMSG: _NT_TARGET_VERSION SET TO WINXP
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386echo.msg not found
Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0
Copyright (C) Microsoft Corporation.  All rights reserved.
cl.exe @c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386cl.rsp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.278 for 80×86
Copyright (C) Microsoft Corporation.  All rights reserved.
cl /Fo"c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386/"
/FC
/Ii386
/I.
/I..inc
/Ic:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386
/IC:WinDDK6001.18001incapi
/IC:WinDDK6001.18001incapi
/IC:WinDDK6001.18001incddk
/IC:WinDDK6001.18001incddk
/IC:WinDDK6001.18001inccrt
/D_X86_=1
/Di386=1
/DSTD_CALL
/DCONDITION_HANDLING=1
/DNT_INST=0
/DWIN32=100
/D_NT1X_=100
/DWINNT=1
/D_WIN32_WINNT=0x0501
/DWINVER=0x0501
/D_WIN32_IE=0x0603
/DWIN32_LEAN_AND_MEAN=1
/DDEVL=1
/D__BUILDMACHINE__=WinDDK
/DFPO=0
/DNDEBUG
/D_DLL=1
/DNDEBUG
/DNTDDI_VERSION=0x05010200
/c
/Zc:wchar_t-
/Zl
/Zp8
/Gy
/Gm-
-cbstring
-W3
-WX
/WX
/Gz
/hotpatch
/EHs-c-
/GR-
/GF
/GS
/Zi
/Oxs
/Oy-
/Zi
/Fdc:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386
/DKMDF_MAJOR_VERSION=01
/DKMDF_MINOR_VERSION=007
/FIC:WinDDK6001.18001incapiwarning.h
.acpiec.c .eclowio.c .ecpnp.c .handlers.c .service.c .query.c
acpiec.c
eclowio.c
ecpnp.c
handlers.c
service.c
query.c
Generating Code…
link.exe /out:c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386acpiec.sys /machine:ix86 @c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386lnk.rsp
Microsoft (R) Incremental Linker Version 8.00.50727.278
Copyright (C) Microsoft Corporation.  All rights reserved.
/MERGE:_PAGE=PAGE
/MERGE:_TEXT=.text
/SECTION:INIT,d
/OPT:REF
/OPT:ICF
/IGNORE:4198,4010,4037,4039,4065,4070,4078,4087,4089,4221
/INCREMENTAL:NO
/release
/NODEFAULTLIB
/WX
/debug
/debugtype:cv,fixup,pdata
/version:6.0
/osversion:6.0
/functionpadmin:5
/safeseh
/pdbcompress
/STACK:0x40000,0x1000
/driver
/base:0x10000
/align:0x80 /stub:c:winddk6001.18001libwxpstub512.com
/subsystem:native,5.01
/entry:GsDriverEntry@8
/out:c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386acpiec.sys
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386acpiec.res
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386acpiec.obj
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386eclowio.obj
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386ecpnp.obj
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386handlers.obj
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386service.obj
c:winddk6001.18001srcwdmacpiececobjfre_wxp_x86i386query.obj
c:winddk6001.18001libwxpi386BufferOverflowK.lib
c:winddk6001.18001libwxpi386ntoskrnl.lib
c:winddk6001.18001libwxpi386hal.lib
c:winddk6001.18001libwxpi386wmilib.lib
c:winddk6001.18001libwxpi386sehupd.lib

所有的 ACPI Customer Driver 應該由 GUID_ACPI_INTERFACE_STANDARD 取得 ACPI Driver 本身的界面, 如 ACPIEC driver 的 source 中有一個檔案為 eclowio.c 裡面有一個 AcpiEcGetAcpiInterfaces. 它是在OS的 PNP Manager 去執行 ECAddDevice (in ecpnp.c) 時所被呼叫.

NTSTATUS
AcpiEcGetAcpiInterfaces (
IN PECDATA          EcData
)
/*++

Routine Description:

Call ACPI driver to get the direct-call interfaces.

Arguments:

EcData          – Pointer to the EC driver device extension

Return Value:

Status is returned.

–*/
{
KEVENT              event;
IO_STATUS_BLOCK     ioStatus;
NTSTATUS            status;
PIRP                irp;
PIO_STACK_LOCATION  irpSp;

PAGED_CODE();

//
// Initialize an event to block on
//
KeInitializeEvent( &event, SynchronizationEvent, FALSE );

//
// Build an irp
//
irp = IoBuildSynchronousFsdRequest(
IRP_MJ_PNP,
EcData->LowerDeviceObject,
NULL,
0,
NULL,
&event,
&ioStatus
);

if (!irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}

irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
irp->IoStatus.Information = 0;

//
// Get the the current irp location
//
irpSp = IoGetNextIrpStackLocation( irp );

//
// Use QUERY_INTERFACE to get the address of the direct-call
// ACPI interfaces.
//
irpSp->MajorFunction = IRP_MJ_PNP;
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpSp->Parameters.QueryInterface.InterfaceType          = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
irpSp->Parameters.QueryInterface.Version                = 1;
irpSp->Parameters.QueryInterface.Size                   = sizeof (AcpiInterfaces);
irpSp->Parameters.QueryInterface.Interface              = (PINTERFACE) &AcpiInterfaces;
irpSp->Parameters.QueryInterface.InterfaceSpecificData  = NULL;

//
// send the request down
//
status = IoCallDriver( EcData->LowerDeviceObject, irp );
if (status == STATUS_PENDING) {

KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
status = ioStatus.Status;

}

//
// Done
//
return status;
}

但是在可以看到當 ECAddDevice 還沒取得 ACPI interface 時, 就在將自己本身掛上 Driver list 後就已經去讀取 EC的 _GPE, 此時就已經可以發IRP 給底層的 ACPI.sys, 去取得ASL中的值!

更有趣的是, 如果用Google 查找 Bob Moore 的話可以找到 Bob Moore robert.moore@intel.com 針對ACPICA/Linux 的commit 所以基本上不管 Windows and Linux 上的 ACPI Driver Stack 應該都是Intel 的一群人寫出來的!

 

關於 ACPI Driver For Windows OS

先來聲明下小弟也是只是一個BIOS/EC/WDM的初學者, 現在這裡(Spaces)只記錄學習過程的一些偶得,

有某位仁兄問我 Get ACPI Interface (Get ACPI Interface 我一開始還是反組譯某A公司的Driver Code 得來的, 後來發現 MSFT 的ACPI Interface in Vista 有寫, 舊的DDK也有 wdmec 有相同的 sample code)後, 為啥用 RegisterForDeviceNotifications 會BlueScreen, 說真的小弟 WDM 才剛起步沒幾週, 目前還在找書看, 跟看 WinDDK Sample code的階段, 雖然這幾天有一點Fu 了 (真的花在看東西上差不多一周吧, 大概只到會寫一個 Port/Memory I/O, Functions Driver 是啥, 怎樣 Call Lower Driver to Process Irp 等等), 但是很多問題還是不懂, 尤其是為啥會BlueScreen 那有可能的有問題很多, MSDN 上也是建議依據BugCheck Number 給一些可能的方向而已

不過因為有很好很強大的 Google Code Search 小弟找到了一個 Driver Code (竟然是 Intel’s UrbanMax ACPI to HID Button mapping driver), 有開發 ACPI Driver for Windows OS 需求的可以參考一下

https://code.google.com/p/screenswitcher/source/browse/trunk/goruntu-aktarimi/HidCom64bit/HidMapperCOM/acpihid-x64/src/DispatchPnP.c

Update:

have backup to my github:   https://github.com/KunYi/screenswitcher/tree/master/goruntu-aktarimi/HidCom64bit/HidMapperCOM


今天用 VMWare + WinDBG + WinXP SP2 Free Build 透過置換 ACPI.SYS checked build 抓下來當 XP Boot 時, 會執行的 ACPI Log

Ref. http://msdn.microsoft.com/en-us/library/cc267789.aspx

http://www.osronline.com/article.cfm?id=318

http://www.osronline.com/article.cfm?id=259

然後發現一本中國大陸出版的好書 軟件調試/Software Debugging(台灣習慣用語應該是軟體除錯)  http://advdbg.org/books/swdbg/ , 網站內有一個試閱章節有100頁左右

下面是看來的
關於在Vista中,應該在具有Administrator 等級的Console window 執行下列指令在置換 ACPI.sys:
takeown /f acpi.sys
cacls acpi.sys /G <username>:F

Technorati 的標籤:,,,

ACPI Debugging on Windows Platforms

MSFT的 TW04015_WINHEC2004.ppt (內容是Implementing, Testing And Debugging ACPI On Windows Platforms)

Update: MSFT上的 link 好像已經失效了, 這擺一份 TW04015_WINHEC2004.ppt 有需要者自取

其中amli 是存在checked build 的acpi.sys 這可以從Microsoft下載, 參考這http://www.microsoft.com/whdc/DevTools/tools/chkblds.mspx,
https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/using-the-checked-build

XP SP2的check build版本

http://download.microsoft.com/download/e/c/6/ec6e00ab-ec05-4673-b8db-0658cf65f043/WindowsXP-KB835935-SP2-DEBUG-ENU.exe

XP SP3的 check build 版本

http://download.microsoft.com/download/4/e/a/4eab3e63-9a62-4473-8af3-87e503603fe2/windowsxp-kb936929-sp3-x86-debug-enu.exe

透過WinDBG 進行 Kernel Debugging時, 可以調用amli 進行ACPI的debug.

安裝了MSFT的 ASL Compiler (個人安裝 3.0.1 version)會有一篇文章講Load Table via Registry(Using the Microsoft ASL Compiler’s ACPI Table Load Utility), 就是透過checked build 的ACPI.SYS 作Developement & Debugging.

Ref.

http://blog.sina.com.cn/s/blog_542734b401000agt.html

http://blog.csdn.net/EFIBIOS/archive/2007/03/12/1526763.aspx

http://blog.chinaunix.net/u/548/showart.php?id=377952

ACPI Debugging, http://msdn.microsoft.com/en-us/library/cc267796.aspx or

http://msdn.microsoft.com/en-us/library/ff537808.aspx