読者です 読者をやめる 読者になる 読者になる

はわわーっ

はわわわわっ

qemuのデバイスの追加とか

qemuSATAとかUSB接続のディスクをつけてみたりしたメモ。

SATAコントローラーとかUSBコントローラーを追加。

-device ich9-ahci,id=ahci
-device nec-usb-xhci,id=xhci

ドライブを作って上で作ったコントローラーにつなぐ。

-device ide-drive,drive=sata,bus=ahci.0
-drive if=none,id=sata,file=temp.qcow2

-device usb-storage,bus=xhci.0,drive=usb0
-drive if=none,id=usb0,file=temp0.qcow2

-device usb-storage,bus=xhci.0,drive=usb1
-drive if=none,id=usb1,media=cdrom,file=temp.iso

ゲストからデバイス確認。

$ lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371SB PIIX3 IDE [Natoma/Triton II]
00:01.3 Bridge: Intel Corporation 82371AB/EB/MB PIIX4 ACPI (rev 03)
00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:03.0 Ethernet controller: Intel Corporation 82540EM Gigabit Ethernet Controller (rev 03)
00:04.0 SATA controller: Intel Corporation 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode] (rev 02)
00:05.0 USB controller: NEC Corporation uPD720200 USB 3.0 Host Controller (rev 03)

00:04.0にSATAコントローラー、00:05.0にUSBコントローラーができた。

$ lsscsi -v 
[0:0:0:0]    disk    ATA      QEMU HARDDISK    2     /dev/sda 
  dir: /sys/bus/scsi/devices/0:0:0:0  [/sys/devices/pci0000:00/0000:00:01.1/ata1/host0/target0:0:0/0:0:0:0]
[1:0:0:0]    cd/dvd  QEMU     QEMU DVD-ROM     2.1.  /dev/sr0 
  dir: /sys/bus/scsi/devices/1:0:0:0  [/sys/devices/pci0000:00/0000:00:01.1/ata2/host1/target1:0:0/1:0:0:0]
[2:0:0:0]    disk    ATA      QEMU HARDDISK    2     /dev/sdb 
  dir: /sys/bus/scsi/devices/2:0:0:0  [/sys/devices/pci0000:00/0000:00:04.0/ata3/host2/target2:0:0/2:0:0:0]
[8:0:0:0]    disk    QEMU     QEMU HARDDISK    2.1.  /dev/sdc 
  dir: /sys/bus/scsi/devices/8:0:0:0  [/sys/devices/pci0000:00/0000:00:05.0/usb2/2-1/2-1:1.0/host8/target8:0:0/8:0:0:0]
[9:0:0:0]    cd/dvd  QEMU     QEMU CD-ROM      2.1.  /dev/sr1 
  dir: /sys/bus/scsi/devices/9:0:0:0  [/sys/devices/pci0000:00/0000:00:05.0/usb2/2-2/2-2:1.0/host9/target9:0:0/9:0:0:0]

/dev/sdbがSATAのハードディスク、/dev/sdcがUSBのハードディスク、/dev/sr1がUSBの光学ディスクになっている。

bashのエラー処理とか

bashのエラー処理まわりわからないので適当にメモ。

#!/bin/bash -eu

exec 3> >(tee e.log) >&3 2>&3

may_fail() {
  test $(( $1 % 3 )) -ne 1
}

commands_may_fail() {
  may_fail $1
  echo "may_fail err $?"
}

main() {
  local i=
  for i in `seq 0 9`; do
    echo "i=$i"
    commands_may_fail $i
  done
}

main

最初に作ったのがこんな感じ。
ログを残しつつループする処理があって、その中でエラーになるかもしれないコマンドがある。
基本的にどっかでエラーになったらその場で終了してほしいので -e つけてる。

とりあえず、このまま実行する。

$ ./e.bash 
i=0
may_fail err 0
i=1

i が 1 のときに may_fail が失敗するのでその場で実行が終わる。

で、ループの commands_may_fail の中でエラーが発生してもスクリプト実行は終了しないで次のループに行くようにしたかった。
ただし、エラーが発生したら commands_may_fail 自体はその場で抜けるようにしたい。

ググってみると、if の条件とか && でコマンドをつなげた場合は bash -e で終了することはないらしいのでそうしてみる。
$? で返り値もとれるらしい。

#!/bin/bash -eu

exec 3> >(tee e.log) >&3 2>&3

may_fail() {
  test $(( $1 % 3 )) -ne 1
}

commands_may_fail() {
  may_fail $1
  echo "may_fail err $?"
}

main() {
  local i=
  for i in `seq 0 9`; do
    echo "i=$i"
    commands_may_fail $i && :
    test $? -eq 0 && echo "success" || echo "error"
  done
}

main

これを実行すると

$ ./e.bash 
i=0
may_fail err 0
success
i=1
may_fail err 1
success
i=2
may_fail err 0
success
i=3
may_fail err 0
success
i=4
may_fail err 1
success
i=5
may_fail err 0
success
i=6
may_fail err 0
success
i=7
may_fail err 1
success
i=8
may_fail err 0
success
i=9
may_fail err 0
success

こんな感じになる。
may_fail がエラーになってもそこで戻ってこないで次の echo が実行されてしまった。
ついでに、echo の戻り値が 0 なので全部 success になってしまっている。
こうなってほしかったんじゃないんだよなぁ。

パイプ使ってコマンドをつなげると最後のコマンドの戻り値で bash -e の終了の判定するようなのでパイプにしてみる。
PIPESTATUS でそれぞれのコマンドの戻り値も取れるらしい。

#!/bin/bash -eu

exec 3> >(tee e.log) >&3 2>&3

may_fail() {
  test $(( $1 % 3 )) -ne 1
}

commands_may_fail() {
  may_fail $1
  echo "may_fail err $?"
}

main() {
  local i=
  for i in `seq 0 9`; do
    echo "i=$i"
    commands_may_fail $i | :
    test ${PIPESTATUS[0]} -eq 0 && echo "success" || echo "error"
  done
}

main

これで実行してみると

$ ./e.bash 
i=0
success
i=1
error
i=2
success
i=3
success
i=4
error
i=5
error
i=6
error
i=7
error
i=8
success
i=9
error

なんか意味不明なことになった。
success/error の出力もおかしいし、echo "may_fail err $?" の部分が出力されてない。
パイプでコマンドつなげたからそっちに向けられてしまったっぽい。

ということで、最終的にこうなった。

#!/bin/bash -eu

exec 3> >(tee e.log) >&3 2>&3

may_fail() {
  test $(( $1 % 3 )) -ne 1
}

commands_may_fail() {
  may_fail $1
  echo "may_fail err $?"
}

main() {
  local i=
  for i in `seq 0 9`; do
    echo "i=$i"
    commands_may_fail $i >&3 2>&3 | :
    test ${PIPESTATUS[0]} -eq 0 && echo "success" || echo "error"
  done
}

main

実行してみると

$ ./e.bash 
i=0
may_fail err 0
success
i=1
error
i=2
may_fail err 0
success
i=3
may_fail err 0
success
i=4
error
i=5
may_fail err 0
success
i=6
may_fail err 0
success
i=7
error
i=8
may_fail err 0
success
i=9
may_fail err 0
success

success/error の判定もちゃんとできているっぽいし、may_fail がエラーになるときは echo "may_fail err $?" が実行されていないのでその場で終了して次のループに進んでいることもわかる。
思ったように動いてるっぽい。

ただし、これだとパイプを使っている以上、set -o pipefail するとたぶん動かなくなりそう。
今のところ pipefail 使ってないからいいんだけど使う必要がでてくるとどう直せばいいんだろう…

qemuのネットワーク設定

qemuのネットワークの設定メモ。とりあえずホストと通信できるだけのやつ
Networking - KVM を見ながら適当に

yomi@xenial:~$ cat /etc/qemu-ifup
#!/bin/sh -e

[ -n "$1" ] || exit 1

sw=br0
tap=$1

#ip tuntap add $tap mode tap
ip link set $tap up
ip link set $tap master $sw
yomi@xenial:~$ sudo ip link add br0 type bridge
yomi@xenial:~$ sudo ip link set br0 up
yomi@xenial:~$ sudo ip addr add 192.168.31.1/24 dev br0

qemuqemu-ifupのスクリプト実行する前にtapデバイス作るらしいのでスクリプト中でデバイス作るようにしてたらエラーになった
tunctl complains that device or resource is busy if used in /etc/qemu-ifup script - Unix & Linux Stack Exchange

qemu起動

yomi@xenial:~$ sudo qemu-system-x86_64 -bios ~/ovmf/OVMF.fd -nographic -device e1000,netdev=net0 -netdev tap,id=net0

UEFI Interactive Shell v2.0
EDK II
UEFI v2.40 (EDK II, 0x00010000)
Mapping table
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x0)
     BLK1: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x1)
Press ESC in 5 seconds to skip startup.nsh or any other key to continue.
Shell> 
Shell> ifconfig -l
eth0
  MAC        : 52-54-00-12-34-56
  Media State: Media present
  Not configured.
Shell> ifconfig -s eth0 static 192.168.31.100 255.255.255.0 192.168.31.1
Create an IP and start to get the default address
Please wait, your console may stop responding for a while ...
      Default: 192.168.31.100
Shell> ifconfig -l
eth0
  MAC        : 52-54-00-12-34-56
  Media State: Media present
  Source     : STATIC
  Permanent  : FALSE
   IP address: 192.168.31.100
         Mask: 255.255.255.0
      Gateway: 192.168.31.1
  Routes (2 entries):
    Entry[0]
       Subnet: 192.168.31.0
      Netmask: 255.255.255.0
      Gateway: 0.0.0.0
    Entry[1]
       Subnet: 0.0.0.0
      Netmask: 0.0.0.0
      Gateway: 192.168.31.1
Shell> ping 192.168.31.1
Ping 192.168.31.1 16 data bytes
16 bytes from 192.168.31.1 : icmp_seq=1 ttl=0 time=42534ms
16 bytes from 192.168.31.1 : icmp_seq=2 ttl=0 time=2483ms
16 bytes from 192.168.31.1 : icmp_seq=3 ttl=0 time=2331ms
16 bytes from 192.168.31.1 : icmp_seq=4 ttl=0 time=1375ms
16 bytes from 192.168.31.1 : icmp_seq=5 ttl=0 time=2924ms
16 bytes from 192.168.31.1 : icmp_seq=6 ttl=0 time=3026ms
16 bytes from 192.168.31.1 : icmp_seq=7 ttl=0 time=2115ms
16 bytes from 192.168.31.1 : icmp_seq=8 ttl=0 time=1586ms
16 bytes from 192.168.31.1 : icmp_seq=9 ttl=0 time=1778ms
16 bytes from 192.168.31.1 : icmp_seq=10 ttl=0 time=1855ms

10 packets transmitted, 10 received, 0% packet loss, time 62007ms

Rtt(round trip time) min=1375ms max=42534ms avg=6200ms

PEヘッダのサブシステム

詳しくは
IMAGE_OPTIONAL_HEADER structure (Windows)

  • 10 IMAGE_SUBSYSTEM_EFI_APPLICATION
  • 11 IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
  • 12 IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER

使いそうなのはこのあたりかしら。

WSLメモ

あとで読みたい(読みたい

https://blogs.msdn.microsoft.com/wsl/
https://blogs.msdn.microsoft.com/wsl/2016/04/22/windows-subsystem-for-linux-overview/

powershellからNVRAMよむやつ

Add-Type -Language CSharp -TypeDefinition @'
    using System;
    using System.Diagnostics;
    using System.Runtime.InteropServices;

    public class UefiNvram {
        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool
        OpenProcessToken(
            IntPtr ProcessHandle,
            uint DesiredAccess,
            out IntPtr TokenHandle
            );

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool
        LookupPrivilegeValue(
            string lpSystemName,
            string lpName,
            out long lpLuid
            );

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool
        AdjustTokenPrivileges(
            IntPtr TokenHandle,
            [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
            ref TokenPrivileges NewState,
            uint BufferLength,
            IntPtr Null1,
            IntPtr Null2
            );

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern uint
        GetFirmwareEnvironmentVariableA(
            string lpName,
            string Guid,
            IntPtr pBuffer,
            uint nSize,
            IntPtr pdwAttributes
            );

        private const uint TokenQuery = 0x08;
        private const uint TokenAdjustPrivileges = 0x20;
        private const uint SePrivilegeEnabled = 0x02;
        private const string SeSystemEnvironmentName = "SeSystemEnvironmentPrivilege";
        private const string UefiGlobalGuid = "{8BE4DF61-93CA-11D2-AA0D-00E098032B8C}";

        [StructLayout(LayoutKind.Sequential)]
        public struct LuidAndAttribute
        {
            public long Luid;
            public uint Attributes;
        };

        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        public struct TokenPrivileges
        {
            public uint PrivilegeCount;
            public LuidAndAttribute Privileges;
        };

        public static bool AdjustPrivileges()
        {
            IntPtr htok;

            if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TokenQuery | TokenAdjustPrivileges, out htok) ||
                Marshal.GetLastWin32Error() != 0) {
                Console.WriteLine("OpenProcessToken failed");
                return false;
            }

            TokenPrivileges tp = new TokenPrivileges { PrivilegeCount = 1, Privileges = new LuidAndAttribute { Attributes = SePrivilegeEnabled } };

            if (!LookupPrivilegeValue(null, SeSystemEnvironmentName, out tp.Privileges.Luid) ||
                Marshal.GetLastWin32Error() != 0) {
                Console.WriteLine("LookupPrivilegeValue failed");
                return false;
            }

            if (!AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero) ||
                Marshal.GetLastWin32Error() != 0) {
                Console.WriteLine("AdjustTokenPrivileges failed");
                Console.WriteLine(Marshal.GetLastWin32Error());
                return false;
            }

            return true;
        }

        public static void BootOrder()
        {
            const int bufsize = 0x100;
            IntPtr buf = Marshal.AllocCoTaskMem(bufsize);
            uint retlen = GetFirmwareEnvironmentVariableA("BootOrder", UefiGlobalGuid, buf, bufsize, IntPtr.Zero);

            if (retlen == 0) {
                Console.WriteLine("GetFirmwareEnvironmentVariableA failed");
                Console.WriteLine(retlen);
                Console.WriteLine(Marshal.GetLastWin32Error());
                return;
            }

            int datalen = (int)retlen;
            byte[] data = new byte[datalen];
            Marshal.Copy(buf, data, 0, datalen);
            for (int i = 0; i < datalen; i++)
                Console.Write("{0:x02} ", data[i]);
            Console.WriteLine();

            Marshal.FreeCoTaskMem(buf);
        }
    }
'@

if ([UefiNvram]::AdjustPrivileges()) {
    [UefiNvram]::BootOrder()
}

あけましておめでとうございました

() ^o^) ちくわ!