Open20

ゼロからのOS自作入門メモ: 実機で動かすためのメモ

maeharinmaeharin

--image-baseの変更

教科書で指定されてる0x100000は使用領域だったので、メモリマップファイルから空いている領域を調べた。0x110000がよさそう

kernel/Makefile
-LDFLAGS  += --entry KernelMain -z norelro --image-base 0x100000 --static
+LDFLAGS  += --entry KernelMain -z norelro --image-base 0x110000 --static

画面が真っ白になってしまう

Main.cでframe_bufferに255を入れて真っ白に塗りつぶしている。この後の処理でframe_bufferにさらに違う値を入れるので上書きされるはずだが、なぜか実機だとこの真っ白に塗りつぶしたものが前面に来てします。そもそも真っ白に塗りつぶす処理はいらないので消す

MikanLoaderPkg/Main.c
-  UINT8* frame_buffer = (UINT8*)gop->Mode->FrameBufferBase;
-  for (UINTN i = 0; i < gop->Mode->FrameBufferSize; ++i) {
-    frame_buffer[i] = 255;
-  }

maeharinmaeharin

実機(ThinkPad T450s)だとマウスが認識されない。。

kInvalidPhaseとなってしまう
USBマウス挿してても挿してなくても同じ

maeharinmaeharin

xHCは検出されてる(USBマウスありなしに関係ない。ここでいうxHCは差し込みポートのことではなく、あくまでもPC内部にあるxHCコントローラのことだから当然)。試しにPCIデバイス列挙のところでis_xhcという表示を出してみると、is_xhcが1になってるのは一個だけ。これは想定どおり

maeharinmaeharin

まず、手元の実機のチップセットが何なのか確認する。幸い、開発用のPCも動作確認用PCと同じ機種(ThinkPad T450s、ubuntu入れてる)だったので、lspciでxHCの情報を調べてみる

$ sudo lspci -nn
00:00.0 Host bridge [0600]: Intel Corporation Broadwell-U Host Bridge -OPI [8086:1604] (rev 09)
00:02.0 VGA compatible controller [0300]: Intel Corporation HD Graphics 5500 [8086:1616] (rev 09)
00:03.0 Audio device [0403]: Intel Corporation Broadwell-U Audio Controller [8086:160c] (rev 09)
00:14.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB xHCI Controller [8086:9cb1] (rev 03)
00:16.0 Communication controller [0780]: Intel Corporation Wildcat Point-LP MEI Controller #1 [8086:9cba] (rev 03)
00:19.0 Ethernet controller [0200]: Intel Corporation Ethernet Connection (3) I218-V [8086:15a3] (rev 03)
00:1b.0 Audio device [0403]: Intel Corporation Wildcat Point-LP High Definition Audio Controller [8086:9ca0] (rev 03)
00:1c.0 PCI bridge [0604]: Intel Corporation Wildcat Point-LP PCI Express Root Port #6 [8086:9c9a] (rev e3)
00:1c.1 PCI bridge [0604]: Intel Corporation Wildcat Point-LP PCI Express Root Port #3 [8086:9c94] (rev e3)
00:1d.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB EHCI Controller [8086:9ca6] (rev 03)
00:1f.0 ISA bridge [0601]: Intel Corporation Wildcat Point-LP LPC Controller [8086:9cc3] (rev 03)
00:1f.2 SATA controller [0106]: Intel Corporation Wildcat Point-LP SATA Controller [AHCI Mode] [8086:9c83] (rev 03)
00:1f.3 SMBus [0c05]: Intel Corporation Wildcat Point-LP SMBus Controller [8086:9ca2] (rev 03)
00:1f.6 Signal processing controller [1180]: Intel Corporation Wildcat Point-LP Thermal Management Controller [8086:9ca4] (rev 03)
02:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS5227 PCI Express Card Reader [10ec:5227] (rev 01)
03:00.0 Network controller [0280]: Intel Corporation Wireless 7265 [8086:095b] (rev 59)

USBコントローラは2つある

  • 00:14.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB xHCI Controller [8086:9cb1] (rev 03)
  • 00:1d.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB EHCI Controller [8086:9ca6] (rev 03)

xHCIコントローラとEHCIコントローラがある。mikanosのイシューにあるUSBマウスが認識されない機種(Acer Aspire E1-572-A54D)と同じだ

xHCIコントローラの方のdevice idは9cb1

$ sudo lspci -nn -s 00:14.0 -v
00:14.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB xHCI Controller [8086:9cb1] (rev 03) (prog-if 30 [XHCI])
	Subsystem: Lenovo Wildcat Point-LP USB xHCI Controller [17aa:5034]
	Flags: bus master, medium devsel, latency 0, IRQ 44
	Memory at f1220000 (64-bit, non-prefetchable) [size=64K]
	Capabilities: [70] Power Management version 2
	Capabilities: [80] MSI: Enable+ Count=1/8 Maskable- 64bit+
	Kernel driver in use: xhci_hcd
	Kernel modules: xhci_pci

EHCIコントローラの方のdevice idは9ca6

$ sudo lspci -nn -s 00:1d.0 -v
00:1d.0 USB controller [0c03]: Intel Corporation Wildcat Point-LP USB EHCI Controller [8086:9ca6] (rev 03) (prog-if 20 [EHCI])
	Subsystem: Lenovo Wildcat Point-LP USB EHCI Controller [17aa:5034]
	Flags: bus master, medium devsel, latency 0, IRQ 23
	Memory at f123d000 (32-bit, non-prefetchable) [size=1K]
	Capabilities: [50] Power Management version 3
	Capabilities: [58] Debug port: BAR=1 offset=00a0
	Capabilities: [98] PCI Advanced Features
	Kernel driver in use: ehci-pci
maeharinmaeharin

xHCIコントローラの方のdevice idは9cb1

0x9cb1でlinuxのソースコードで検索かけると「PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI」という名前がつけられていることが分かる
https://github.com/torvalds/linux/blob/9bad743e8d221c1be8fa80f0e76102234e472ac3/drivers/usb/host/xhci-pci.c#L41

Wildcat Pointというチップセットで、mikanosのイシューにあるLynx Pointチップセットと似てるぽい
https://en.wikipedia.org/wiki/List_of_Intel_chipsets

maeharinmaeharin

PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCIでlinuxソースコード検索かける

が、1箇所でしか使われていない

https://github.com/torvalds/linux/blob/9bad743e8d221c1be8fa80f0e76102234e472ac3/drivers/usb/host/xhci-pci.c#L226

XHCI_SPURIOUS_REBOOTとXHCI_SPURIOUS_WAKEUPフラグを立てているだけだ。(そしてPCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCIも同じフラグの立て方をしてる)

mikanosのissueだとこれはシャットダウン処理に関するものっぽいというこで一旦深入りしないでいる

うーん、となると関係ないのか。一旦無視する

maeharinmaeharin

逆に、mikanosでデバッグしてる「PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI」と今回の「PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI」の違いはなんだろうか?

PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCIの方はasus_wmi_set_xusb2pr()で使われているけど、PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCIは使われてない

https://github.com/torvalds/linux/blob/038101e6b2cd5c55f888f85db42ea2ad3aecb4b6/drivers/platform/x86/asus-wmi.c#L1618

ということは、今回のPCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCIでは、このissueへの対策であるSwitchEhci2Xhci が不要なのか?

maeharinmaeharin

SwitchEhci2Xhci を呼び出さないようにして実機で動かしてみた。

しかし、全ポートのisConnectedがfalseになってしまった

どうやら今回のWildcat Pointでも SwitchEhci2Xhci は必要なようだ

maeharinmaeharin

となると、mikanosのissueでは深い入りしていなかったXHCI_SPURIOUS_REBOOTとXHCI_SPURIOUS_WAKEUPが関係しているのだろうか

XHCI_SPURIOUS_REBOOTは再起動に関するののだけど、 XHCI_SPURIOUS_WAKEUPの方は起動に関するもの?だとするとこの対策が重要なのでは?

maeharinmaeharin

上記検証する前に、起きている現象についてもう少し調査する

mikanosのissueで調べてる以下の値を出力してみる

デバッグ用の関数はこんな感じ

  void Port::Debug(char* const name) const {
    auto pls = port_reg_set_.PORTSC.Read().bits.port_link_state;
    auto pp = port_reg_set_.PORTSC.Read().bits.port_power;
    auto ccs = port_reg_set_.PORTSC.Read().bits.current_connect_status;
    auto ped = port_reg_set_.PORTSC.Read().bits.port_enabled_disabled;
    auto pr = port_reg_set_.PORTSC.Read().bits.port_reset;

    Log(kInfo, "[p%d] [%s] connected=%d,enabled=%d,PLS=%d,(%d,%d,%d,%d)\n",
        Number(),
        name,
        IsConnected(),
        IsEnabled(),
        pls,
        pp,
        ccs,
        ped,
        pr);
  }
maeharinmaeharin

PLSの意味は仕様書のTable 5-27: Port Status and Control Register Bit Definitions (PORTSC)

(PP,CCS,PED,PR)の意味は仕様書のFigure 4-27: USB3 Root Hub Port State Machine

maeharinmaeharin
  • port2, 6, 7, 8
    • connected=1, enabled=0, PLS=7, (1,1,0,0)から開始
    • PLS=7: Link is in the Polling State
    • (1,1,0,0): 状態遷移図に存在しない?
  • port13
    • connected=1, enabled=1, PLS=0, (1,1,1,0)から開始
    • PLS=0: Link is in the U0 State
    • (1,1,1,0): Enabled
  • その他のポート
    • connected=0, enabled=0, PLS=5, (1,0,0,0)から開始
    • PLS=5: Link is in the RxDetect State
    • (1,0,0,0): Disconnected, Disabled, Loopback, Polling, Compliance, Error

初期化後、port2,6,7,8,13(初期化時にconnectedだったポートたち)に関してのみ、OnEvent PortStatusChangeEventのハンドラが実行されてる
その際はいずれもconnected=0, enabled=0, PLS=5, (1,0,0,0)

そしてport2はEnableSlotの処理に入るが、それ以外のポートはkInvalidPhaseエラーになってる

port2はport6,7,8,13がkInvalidPhaseエラーになった後に再度OnEvent PortStatusChangeEventのハンドラが実行されているが、enabled=0のため処理がスキップされるため、何も起こらない

なぜ connected=0, enabled=0, PLS=5, (1,0,0,0) の状態でハンドラが呼ばれるのか全く分からない。。

なお、Debug Capability Registerの状況は以下と同じ状況なので問題なさそう

00hを見ると,Capability ID = 0x05 = 10となっており,"Table 7-2: xHCI Extended Capability Codes"よりDebug Capability Registerであることが分かる。
20hは0であるからDCE=0である。Debug Capabilityが無効化されていることが分かった。
https://github.com/uchan-nos/mikanos/issues/3#issuecomment-708919226

maeharinmaeharin

USBマウスあり時は、USBマウスなし時とほぼ同じで、違いはport3がport6,7,8と同じ挙動になっただけ。

maeharinmaeharin

いずれの場合もport2の動きが怪しいので、port2に絞って動きを整理する

  • main.cppのforループ
    • connected=1, enabled=0, PLS=7, (1,1,0,0)
    • PLS=7: Link is in the Polling State
    • (1,1,0,0): 状態遷移図に存在しない?
  • ConfigurePort
  • ResetPort
    • port_config_phaseにkResettingPortフラグをセット

ここで一旦処理終了

イベントハンドラが呼び出される

  • OnEvent PortStatusChangeEvent
    • EnableSlot
      • connected=0, enabled=0, PLS=5, (1,0,0,0)
      • enabled=0なので何もせず終了

再度イベントハンドラが呼び出される

  • OnEvent PortStatusChangeEvent
    • EnableSlot
      • connected=0, enabled=0, PLS=5, (1,0,0,0)
      • enabled=0なので何もせず終了

それ以降何も起こらない

うーん、、謎なのは

  • 最初はconnected=1なのに、イベントハンドラが呼び出されたときはconnected=0になってる
  • イベントハンドラ呼び出された時もenabled=0(なので処理スキップされて何も起こらない)
maeharinmaeharin

XHCI_SPURIOUS_WAKEUPについて調査

LynxPointにこのフラグが追加されたときの説明

Wildcat Pointにこのフラグが追加されたときの説明

シャットダウンするときに呼び出されるもの?
https://github.com/torvalds/linux/blob/81ff0be4b9e3bcfee022d71cf89d72f7e2ed41ba/drivers/usb/host/xhci.c#L776