FreeBSD-10 install image for Baytrail-M NUC(DN2820FYKH)
Intel Baytrail-M NUC(DN2820FYKH) causes kernel panic due to its broken ACPI table:
http://www.freebsd.org/cgi/query-pr.cgi?pr=187966
This install image includes patched kernel for the machine, you are able to install FreeBSD-10 on the machine without any kernel rebuilding work.
Baytrail-M NUC(DN2820FYKH)でFreeBSDが起動しなかった話・解決編
これの続き。
Linuxでは僕の書いたpatchと同じ感じでreservedが来たらtriggerならlevel、polarityならlowを返すようにしています。
http://lxr.linux.no/linux+v3.13.5/arch/x86/kernel/acpi/boot.c#L1094
ですので、このパッチをマージして貰うという事で良いのではないかという気がしてきたので、PRを送ってみました:
amd64/187966: Intel Baytrail-M NUC panics because of buggy ACPI table
その後、それをみたtakawataさんが同等のコードをCURRENTにコミットしてくれました:
Revision 263795
というわけで一件落着。
Baytrail-M NUC(DN2820FYKH)でFreeBSDが起動しなかった話
bhyve用にこれ買ってみたんですよ、これ。まぁ新しいハードだし地雷だろうなと思ってたんだけど、面白そうにおもっちゃってつい人柱っちゃったんですよ。はい。
したらもういきなりドハマリして。
- FreeBSDが入っている2.5インチHDDを繋いでもレガシーブートモードでブートセクタが認識されている様子が無い
- USBメモリやUSB CD-ROMを認識する気配も無い
- ふと何となくHDDを抜いてUSBメモリを刺したらUbuntuがあっさり起動
- …それ、電源容量足りてないのでは?
- HDDをSSDに差し替えてみたらUSBメモリとSSD両方認識
- でもUEFIの設定画面でブートデバイスのリスト空になったりするし、ブートセレクタでUSBメモリでてこないし
- UEFIの設定画面のメモリ容量0GBだし
- UEFIの設定画面からネット経由のファームアップを選んだらエラーメッセージ
- UEFIの設定画面からUSBメモリ経由のファームアップを実行したらフリーズ
- もうなんか全然うまくいかないので別のマシンでSSDにFreeBSDをインストールしてきてから、NUCに刺してみる
- かーねるぱにっく!
- インストールするFreeBSDのバージョンを変えたり試行錯誤してみたら、動く組み合わせを発見
- 無事起動!
- でもよくみると、USBコントローラがdmesgにエラーを吐きまくって発狂してて動いてない。CPUコアは2つのはずだが1つしか見えてない。
- これ、ACPIのテーブルがちゃんと読めてないか壊れてたりするのでは?
- dmesgみると「ACPI BIOS Warning (bug): Incorrect checksum in table [DSDT] - 0x8E, should be 0x51 (20130823/tbprint-233」とか出てる
- ACPIのテーブル、ちゃんと読めてないか壊れてるとしか思えない
- USBメモリでブートしてACPIテーブルのダンプを取る→再コンパイル→エラー無し。FreeBSDでだけおかしいのだろうか?
- BIOSリカバリモードでなら無事ファームアップできるらしいと教えて貰ったので試してみる
- FreeBSDがまたカーネルパニックするようになった!←イマココ
で、どんなpanicを起こしているかを見てみるわけですね。
こちらはverbose modeで起動時のpanic画面で、「Bogus Interrupt Trigger Mode」で止まってます。
static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source) { switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) { case ACPI_MADT_TRIGGER_CONFORMS: if (Source == AcpiGbl_FADT.SciInterrupt) return (INTR_TRIGGER_LEVEL); else return (INTR_TRIGGER_EDGE); case ACPI_MADT_TRIGGER_EDGE: return (INTR_TRIGGER_EDGE); case ACPI_MADT_TRIGGER_LEVEL: return (INTR_TRIGGER_LEVEL); default: panic("Bogus Interrupt Trigger Mode"); } }
何らかのデバイスの割り込み設定をパースしている所に見えます。
で、取り敢えず先に進みたいと思ったので、panicをコメントアウトして、PCIデバイスの割り込みで通常使われているINTR_TRIGGER_LEVELをreturnするようにコードを適当に書き換えてみます。
すると、今度は「Bogus Interrupt Polarity」でpanicしました。
コードではこの辺ですね。
static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source) { switch (IntiFlags & ACPI_MADT_POLARITY_MASK) { case ACPI_MADT_POLARITY_CONFORMS: if (Source == AcpiGbl_FADT.SciInterrupt) return (INTR_POLARITY_LOW); else return (INTR_POLARITY_HIGH); case ACPI_MADT_POLARITY_ACTIVE_HIGH: return (INTR_POLARITY_HIGH); case ACPI_MADT_POLARITY_ACTIVE_LOW: return (INTR_POLARITY_LOW); default: panic("Bogus Interrupt Polarity"); } }
で、今度もpanicをコメントアウトして、取り敢えず適当にINTR_POLARITY_LOWを返すように書き換えてみます。
…すると、問題なく動作するようになりました。
でも、このエラーは何だったのでしょう。dmesgやソースコードを眺めた感じでは、MADTというテーブルのパース中に、あるデバイスの割り込み設定を取りに行ったら範囲外の値を受け取ってカーネルの実行を止めたというように読み取れます。
ではどんな値が来てるのかdmesgに表示してみましょう。
こんなprintfを入れてみました:
diff --git a/sys/x86/acpica/madt.c b/sys/x86/acpica/madt.c index 9dfb77f..fdc86c0 100644 --- a/sys/x86/acpica/madt.c +++ b/sys/x86/acpica/madt.c @@ -308,14 +308,15 @@ interrupt_polarity(UINT16 IntiFlags, UINT8 Source) case ACPI_MADT_POLARITY_ACTIVE_LOW: return (INTR_POLARITY_LOW); default: - panic("Bogus Interrupt Polarity"); + printf("Bogus Interrupt Polarity %x, set to low\n", + IntiFlags & ACPI_MADT_POLARITY_MASK); + return (INTR_POLARITY_LOW); } } static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source) { - switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) { case ACPI_MADT_TRIGGER_CONFORMS: if (Source == AcpiGbl_FADT.SciInterrupt) @@ -327,7 +328,9 @@ interrupt_trigger(UINT16 IntiFlags, UINT8 Source) case ACPI_MADT_TRIGGER_LEVEL: return (INTR_TRIGGER_LEVEL); default: - panic("Bogus Interrupt Trigger Mode"); + printf("Bogus Interrupt Trigger Mode %x, set to level\n", + IntiFlags & ACPI_MADT_TRIGGER_MASK); + return (INTR_TRIGGER_LEVEL); } }
すると、以下のような出力が得られます(一部抜粋)
MADT: Found IO APIC ID 1, Interrupt 0 at 0xfec00000 ioapic0: Routing external 8259A's -> intpin 0 lapic0: Routing NMI -> LINT1 Bogus Interrupt Trigger Mode 8, set to level lapic0: LINT1 trigger: level lapic0: LINT1 polarity: high lapic2: Routing NMI -> LINT1 lapic2: LINT1 trigger: level Bogus Interrupt Polarity 2, set to low lapic2: LINT1 polarity: low MADT: Interrupt override: source 0, irq 2 ioapic0: Routing IRQ 0 -> intpin 2 MADT: Interrupt override: source 9, irq 9 ioapic0: intpin 9 trigger: level ioapic0 <Version 2.0> irqs 0-86 on motherboard lapic0: Forcing LINT1 to edge trigger
つまり、Interrupt Trigger Modeに0x8が、Interrupt Polarityに0x2が届いているらしい、という事がわかります。
この値はなんだろう、ここには実装されていないけど新しいモードでもあるのかな?と思ってACPI Specificationを眺めてみます。
…すると、どちらもreservedな値らしいという事がわかりました。なんか変ですね…。
dmesgを見る限りでは2つのコアの割り込みコントローラ(lapic0, lapic2)からそれぞれ接続されている、レガシ割り込み1番(LINT1と書いてある)の設定でしょうか…。
これ以上はMADTを眺めない限り分からなそうです。
というわけでMADTをダンプしてみます:
$ sudo acpidump -t MADT /* RSD PTR: OEM=INTEL, ACPI_Rev=2.0x (2) XSDT=0xb9549078, length=36, cksum=199 */ /* XSDT: Length=116, Revision=1, Checksum=141, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=AMI, Creator Revision=0x10013 Entries={ 0xb9550848, 0xb9550958, 0xb95509c0, 0xb9550a08, 0xb9550a48, 0xb9550b50, 0xb9550b88, 0xb95512f0, 0xb9551580, 0xb9551700 } */ /* FACP: Length=268, Revision=5, Checksum=89, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=AMI, Creator Revision=0x10013 FACS=0xb96eef80, DSDT=0xb9549180 INT_MODEL=APIC Preferred_PM_Profile=Desktop (1) SCI_INT=9 SMI_CMD=0xb2, ACPI_ENABLE=0xa0, ACPI_DISABLE=0xa1, S4BIOS_REQ=0x0 PSTATE_CNT=0x80 PM1a_EVT_BLK=0x400-0x403 PM1a_CNT_BLK=0x404-0x405 PM2_CNT_BLK=0x450-0x450 PM_TMR_BLK=0x408-0x40b GPE0_BLK=0x420-0x42f CST_CNT=0x85 P_LVL2_LAT=101 us, P_LVL3_LAT=1001 us FLUSH_SIZE=1024, FLUSH_STRIDE=16 DUTY_OFFSET=1, DUTY_WIDTH=3 DAY_ALRM=13, MON_ALRM=0, CENTURY=50 IAPC_BOOT_ARCH={NO_VGA} Flags={WBINVD,SLEEP_BUTTON,S4_RTC_WAKE,RESET_REGISTER,PLATFORM_CLOCK,S4_RTC_VALID,REMOTE_POWER_ON} RESET_REG=0xcf9:0[8] (IO), RESET_VALUE=0x6 */ /* FACS: Length=64, HwSig=0x0000004f, Firm_Wake_Vec=0x00000000 Global_Lock= Flags= Version=2 */ /* DSDT: Length=30405, Revision=2, Checksum=79, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=INTL, Creator Revision=0x20120913 */ /* APIC: Length=104, Revision=3, Checksum=174, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=AMI, Creator Revision=0x10013 Local APIC ADDR=0xfee00000 Flags={PC-AT} Type=Local APIC ACPI CPU=1 Flags={ENABLED} APIC ID=0 Type=Local APIC NMI ACPI CPU=1 LINT Pin=60 Flags={Polarity=active-hi, Trigger=0x2} Type=Local APIC ACPI CPU=2 Flags={ENABLED} APIC ID=2 Type=Local APIC NMI ACPI CPU=2 LINT Pin=61 Flags={Polarity=0x2, Trigger=level} Type=IO APIC APIC ID=1 INT BASE=0 ADDR=0x00000000fec00000 Type=INT Override BUS=0 IRQ=0 INTR=2 Flags={Polarity=conforming, Trigger=conforming} Type=INT Override BUS=0 IRQ=9 INTR=9 Flags={Polarity=active-hi, Trigger=level} */ /* FPDT: Length=68, Revision=1, Checksum=181, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=AMI, Creator Revision=0x10013 */ /* MCFG: Length=60, Revision=1, Checksum=76, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=MSFT, Creator Revision=0x97 Base Address=0x00000000e0000000 Segment Group=0x0000 Start Bus=0 End Bus=255 */ /* LPIT: Length=260, Revision=1, Checksum=63, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x3, Creator ID=VLV2, Creator Revision=0x100000d */ /* HPET: Length=56, Revision=1, Checksum=171, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x1072009, Creator ID=AMI., Creator Revision=0x5 HPET Number=0 ADDR=0xfed00000:0[64] (Memory) HW Rev=0x1 Comparators=2 Counter Size=1 Legacy IRQ routing capable={TRUE} PCI Vendor ID=0x8086 Minimal Tick=128 Flags=0x00 */ /* SSDT: Length=1891, Revision=1, Checksum=193, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x3000, Creator ID=INTL, Creator Revision=0x20061109 */ /* SSDT: Length=656, Revision=1, Checksum=10, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x3000, Creator ID=INTL, Creator Revision=0x20061109 */ /* SSDT: Length=378, Revision=1, Checksum=186, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x3000, Creator ID=INTL, Creator Revision=0x20061109 */ /* UEFI: Length=66, Revision=1, Checksum=147, OEMID=INTEL, OEM Table ID=DN2820FY, OEM Revision=0x0, Creator ID=, Creator Revision=0x0 */
よくわかりませんが、多分
Type=Local APIC NMI ACPI CPU=1 LINT Pin=60 Flags={Polarity=active-hi, Trigger=0x2}
と
Type=Local APIC NMI ACPI CPU=2 LINT Pin=61 Flags={Polarity=0x2, Trigger=level}
でしょうか。
Trigger=0x2はおそらくビットシフト後の0x8だと思われます。
間違ってるっぽいのは分かったけど、それでどうしたらいいんだろうか…。
まぁ、取り敢えず上述のパッチでpanicを起こさないようにすると動くには動くんですが。
ちなみに、新しいファームウェアではこのパッチを当てないと起動出来ないですが、CPU数はちゃんと2に増えました。
USBは相変わらずおかしいようです。
RubyでTAPを使ったトンネリングプログラムを実装してみる
こちらのサイトでシンプルなPythonの実装が配布されていたので、Rubyでも実装してみました。
require "socket" TUNSETIFF = 0x400454ca IFF_TAP = 0x0002 PEER = "192.168.0.100" PORT = 9876 tap = open("/dev/net/tun", "r+") tap.ioctl(TUNSETIFF, ["tap%d", IFF_TAP].pack("a16S")) sock = UDPSocket.open sock.bind("0.0.0.0", 9876) peer = Socket.pack_sockaddr_in(PORT, PEER) while true ret = IO::select([sock, tap]) ret[0].each do |d| if d == tap sock.send(tap.read(1500), 0, peer) else tap.write(sock.recv(65535)) end end end
RubyでもTAPの読み書きが出来るしselectも使えるしioctlも発行できるよー、っと。
OSvにマージされたmrubyを試す
$ sudo apt-get install openjdk-7-jdk autotools-dev libltdl-dev libtool autoconf autopoint libboost-all-dev \ genromfs zfs-fuse autoconf ant libffi-dev ruby bison gyp git build-essential qemu-utils qemu-system-x86 \ bridge-utils libvirt0 libvirt-bin $ git clone git@github.com/cloudius-systems/osv $ cd osv $ git submodule update --init $ cd apps/mruby $ make module $ cd - $ sudo make external all image=mruby $ sudo ./scripts/run.py OSv v0.05-72-g4eb7d9c mruby-eshell $ ls [".", "..", "libuutil.so", "libzfs.so", "dev", "tools", "proc", "zfs.so", "tmp", "etc", "zpool.so", "usr"] $ exit
ただ、これだけだとスクリプトが何も無いので何も実行できない。
スクリプトを足して再ビルドしてみる。
$ cd apps/mruby $ cat << EOF > tcpsocket.rb s = TCPSocket.open("www.kame.net", 80) s.write("GET / HTTP/1.0\r\n\r\n") puts s.read s.close EOF $ echo "/tcpsocket.rb: \${MODULE_DIR}/tcpsocket.rb" >> usr.manifest $ cd - $ sudo make all image=mruby $ sudo ./scripts/run.py OSv v0.05-72-g4eb7d9c mruby-eshell $ run ./tcpsocket.rb HTTP/1.1 200 OK Date: Sat, 25 Jan 2014 00:13:58 GMT Server: Apache/2.2.26 (FreeBSD) mod_ssl/2.2.26 OpenSSL/0.9.8y DAV/2 Accept-Ranges: bytes Connection: close Content-Type: text/html (後略) $ exit
ソケット通信のテストが実行出来た。
FreeBSD 10.0-RELEASEのBHyVeでLinuxゲストが「WRMSR・RDMSR」などの単語を含むエラーメッセージと共に異常終了する場合
一部のLinuxカーネルと一部のIntel CPUの組み合わせでは「Unknown WRMSR code 391, val 2000000f, cpu 0」「vm exit rdmsr 0xe8, cpu 0」などのエラーがでる。
これは、該当するMSRへのアクセスをBHyVeがハンドルせずに異常終了して済ませてしまっているためで、以下の手順で-CURRENTのパッチをバックポートすることで解決出来る。
# svn co svn://svn.freebsd.org/base/head # cd head # svn diff -r259634:r259635 > ~/msr.diff # cd /usr/src # patch -p0 < ~/msr.diff # cd usr.sbin/bhyve # make # make install # cd ~/bhyve-script # vi centos1 BHYVECMD="/usr/sbin/bhyve \ -c "$VCPUS" \ のところを以下のように書き換える: BHYVECMD="/usr/sbin/bhyve \ -w \ -c "$VCPUS" \
FreeBSD 10.0-RELEASEのBHyVeでOpenBSD 5.4をインストールしてみよう
OpenBSDサポートはまだ実験段階で、カーネルを改変したバージョンの5.4しか動かない。
この問題を回避するために、改変版カーネルがインストールされたディスクイメージをダウンロードする。
# cd bhyve-script # cp vm0 openbsd3 これから作るVMの名前にvm0をコピー(末尾は数値で、他のVMと重複しない値でなければならない) # vi openbsd3 NIC=“em0” をお使いのNIC名に VCPUS=“1”を任意のvCPU数に VMOS=“freebsd”を”openbsd”に VMRAM=1024”を任意のメモリサイズに それぞれ変更。 # mkdir -p ./vm/openbsd3 # fetch http://people.freebsd.org/~grehan/flashimg.amd64-20131014.bz2 # bunzip2 flashimg.amd64-20131014.bz2 # cp flashimg.amd64-20131014 ./vm/openbsd3/openbsd3.img # sh openbsd3 start rootのパスワードは'test123'でログイン可能。
TODO:これだとネットワークが繋がらない気がする。