/home/amgsk

GPD MicroPC 2にArch Linuxを入れて環境を整備する

· amgsk
要約
  • GPD MicroPC 2を買った当日にWindowsを消し、Arch Linux単独構成にした
  • 一番手こずったのはタッチパネルをうまく動作させることだった
  • ハイバーネート復帰でUEFI設定画面に落ちる原因はBIOSのFast Bootが原因そう

TOC


買った

GPD MicroPC2
GPD MicroPC2

GPD MicroPC 2を買った。7インチの小型PCで、物理キーボードとタッチスクリーンが付いている。 持ち歩いてターミナルを叩く用途が欲しかったので、届いた日の夜にプリインストールのWindowsを丸ごと削除してArch Linuxを入れた。 デュアルブートにするか少し迷ったけど、Windowsを使う予定が無いのでNVMeのパーティションを全部消して単独構成にしている。 回復パーティションも残していないので、Windowsに戻したくなったらインストールメディアから入れ直すことになる。

購入から1週間ほどで常用できるところまで持っていけたので、やったことをまとめておく。

機体のスペックはこんな感じ。

項目
CPUIntel Core i3-N300 (8コア8スレッド)
メモリ16GB
ストレージNVMe 512GB + microSD 1TB
内蔵パネル7インチ 1080x1920 (DSI-1)
タッチILITEK ILTP7807 (I2C-HID)
加速度センサーmxc4005
BIOS2.18

購入直後から、最新のBIOSがインストールされているようだった。 最終的な構成はこうなった。

項目
OSArch Linux / linux-zen (保険でlinuxも残置)
ブートsystemd-boot、ext4、LVM・暗号化なし
ログインSDDM
デスクトップHyprland 0.56 + caelestia-shell
スケール1.25
日本語入力fcitx5 + mozc
電源BIOS TDP 8W + power-profiles-daemon power-saver固定
スリープ蓋閉じでsuspend-then-hibernate

余談: 公式サイトに繋がらない

セットアップの前に公式のファームウェア・ドライバページを見ようとしたら、https://gpd.hk/...が一切開かなかった。 調べてみると、www無しの裸ドメインは古いIISサーバーを指していてHTTPSに応答しない。 https://www.gpd.hk/の方が正しい模様。

もしGPDのサイトに繋がらない人はwwwを付けてみてほしい。

インストール

archinstallは使わず、Arch Wikiどおりの手動インストール。 特別なことはしていないけど、この機体ならではのポイントだけ書いておく。

ディスク構成

1
2
3
4
nvme0n1p1   1G      vfat   /boot   (ESP)
nvme0n1p2   475.9G  ext4   /
mmcblk1p1   921.7G  ext4   /mnt/sdcard
/swapfile   16G                    (ハイバーネート用)

素のext4 + systemd-boot。持ち歩く機体だけど暗号化はしていない。

microSDの運用

NVMeは512GB。正直ちょっと心もとなくて、最初は大容量のSSDに換装しようかと考えた。

ただ、この機体はそもそも安く小さいマシンが欲しくて選んだもので、そこに換装費用を乗せたらコストを削った意味が無くなる。 なのでメインストレージは512GBのまま頑張ることにして、足りない分をmicroSDで補う方針にした。

microSDスロットに1TBを挿して/mnt/sdcardに常時マウントしている。

ファイルシステムの選定

このカードはこの機体でしか読まないので、他OSとの互換性のためのexFATは最初から候補外。 Linux用のファイルシステムで比較した。

候補良いところ気になるところ
ext4一番枯れていてfsckもツールも安心フラッシュ最適化もチェックサムも無い
F2FSNANDフラッシュ向け設計。ログ構造で書き込みを順次化し、ランダム書き込みを減らせる。zstd透過圧縮ありfsckの成熟度がext4に劣る。メタデータのオーバーヘッドがやや大きい
btrfsデータ・メタデータ両方にチェックサムがあり、SDカードのサイレントな破損を検出できる。zstd透過圧縮ありCoWなので書き込み量はext4より増え、フラッシュ寿命では不利

書き込み耐久を重視するならF2FS、消えたら困るものを置いて破損に気づきたいならbtrfs、という棲み分けになる。

ただ、このカードの運用方針は後述のとおり「一度書いたら読むだけ」「無くなっても再取得できる」。 読み出し主体なら書き込み耐久はそもそも問題になりにくいし、再取得できるものしか置かないならビットロット検出の価値も下がる。 実効速度はどれを選んでもカード自体の速度で頭打ちになるので、体感差も出にくい。

結局、フラッシュ向けの工夫より「困ったときにツールが揃っている」方を取ってext4にした。 書き込みが増える使い方に変わったらF2FSへ移ることは考えている。

1
mkfs.ext4 -m 0 -L sdcard /dev/mmcblk1p1

-m 0はroot用の予約領域をゼロにするオプション。 既定だと5%が予約されて1TBのうち50GBが使えなくなるし、システムを置くわけでもないので予約は要らない。

fstabはUUIDではなくラベルで指定して、nofailx-systemd.device-timeout=5sを付けている。

1
LABEL=sdcard  /mnt/sdcard  ext4  defaults,noatime,nofail,x-systemd.device-timeout=5s  0  2

nofailが無いと、カードを抜いた状態で起動したときにマウント失敗でブートが止まる。 x-systemd.device-timeoutも短くしておかないと、デバイスが現れるのを既定の90秒待たされる。 持ち歩く機体でカードを抜き差しする前提なら、この2つはセットで付けておくのが安全。

microSDに置いてはいけないもの

容量が大きいからといって何でも置くと、すぐに寿命と速度で痛い目を見る。 microSDはNVMeと比べて書き込み耐久性が桁違いに低く、ランダムアクセスも遅い。 なので読み書きが激しいものは置かないと決めている。

  • swapfile。ハイバーネート用の16GBは迷わずNVMe側に置いた
  • ~/.cacheやブラウザのプロファイル。小さいファイルの書き換えが延々と続く
  • パッケージキャッシュ(/var/cache/pacman)やAURのビルドディレクトリ
  • gitリポジトリやnode_modules。ビルドのたびに大量の小ファイルが生成・削除される
  • DockerやDBのデータディレクトリ

この手のものはNVMeに置いて、NVMeが足りなくなったら消す方針にしている。

不変のデータ置き場として使う

逆に、書き込みが一度きりであとは読むだけのデータならmicroSD向き。 書き込み回数が増えないので寿命を気にしなくていいし、順次読み出しなら速度もそれほど問題にならない。

  • 動画・音楽・写真などのメディア
  • 電子書籍やPDF、ドキュメント類のアーカイブ
  • ISOイメージやインストーラー
  • 手元に置いておきたいバックアップのスナップショット

「一度置いたら書き換えない」「無くなっても再取得できる」の2つを満たすものだけ載せて、 microSDは取り外しても困らない読み出し専用の倉庫という扱いにしている。 nofailを付けたのもこの前提があるからで、カードが無ければ無いで普通に起動して使える。

pacstrap

1
2
pacstrap /mnt base linux linux-firmware intel-ucode base-devel \
              git vim sudo networkmanager openssh sof-firmware

sof-firmwareはオーディオ用。これが無いと音が出ない。 カーネルは翌日にlinux-zenを追加して以降そっちを常用している。

カーネルパラメータ

1
2
3
4
root=UUID=<root> rw
fbcon=rotate:1
video=DSI-1:panel_orientation=right_side_up
resume=UUID=<root> resume_offset=804864

fbcon=rotate:1panel_orientationが画面の向き用。詳しくは次の節で。 resume系はハイバーネート用で、後から足した。

画面の向きが一番の難所だった

この機体はパネルが物理的に90°回して実装されている。 つまりOSから見ると1080x1920の縦長ディスプレイで、そのまま表示すると画面が横に倒れる。

厄介なのは、向きを直す場所が1か所じゃないこと。最終的に4層それぞれで指定することになった。

BIOSで画面の向きを設定できることに後から気づいた。もし先にこの設定をしていれば、以下の一部はやらなくても良いかもしれない。

設定場所内容
カーネルコンソールローダーエントリfbcon=rotate:1
DRMローダーエントリvideo=DSI-1:panel_orientation=right_side_up
Xorg (SDDMのgreeter)/etc/X11/xorg.conf.d/90-gpd-rotate.confOption "Rotate" "CW"
Hyprlandmonitor設定transform = 3

Waylandコンポジタはカーネルのpanel_orientationを読んで自動補正してくれるけど、Xorgはpanel orientationを見ない。 SDDMのgreeterはX11で動いているので、ログイン画面だけ横倒しになる。 ここはxorg.conf.dで明示的に回す必要があった。タッチ座標も一緒に回さないとログイン画面で押した場所がずれる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Section "Monitor"
    Identifier "DSI-1"
    Option "Rotate" "CW"
EndSection

Section "InputClass"
    Identifier "touchscreen rotate"
    MatchIsTouchscreen "on"
    Option "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"
EndSection

Hyprland側はこう。

1
2
3
4
5
6
7
hl.monitor({
    output    = "DSI-1",
    mode      = "1080x1920@60",
    position  = "0x0",
    scale     = 1.25,   -- 実効 1536x864
    transform = 3,      -- 270°
})

タッチ座標

Hyprlandでもinput.touchdeviceをモニタに紐付けて同じtransformを当てないと、押した場所と反応する場所がずれる。 transformの値は理屈で決めず、0/1/2/3を実機で順に試して3で一致した。

自動回転

加速度センサー(mxc4005)をiio-sensor-proxy経由で読んで、monitor-sensorの向き名をHyprlandのtransformに対応させる自作スクリプトを常駐させている。 対応表は実機で校正した。

monitor-sensortransform見え方
right-up3横向き (通常の使用姿勢)
normal0縦向き
left-up1横向き (上下逆)
bottom-up2縦向き (上下逆)

キーボードで文字を打っている最中に回転されると困るので、Super+Oで画面の自動回転のオンオフをトグルできるようにした。

タブレットモードの自動判別は諦めた

画面を外向きにして閉じたらタブレットモードに切り替えたかったけど、実機で調べた結果これは無理だと分かった。

  • SW_TABLET_MODEを持つ入力デバイスが無い。Lid SwitchはSW_LIDしか出さない
  • 画面を外向きにして閉じてもLidスイッチはopenのまま
  • 外向きに閉じた状態と、画面を180°寝かせて開いた状態は加速度が原理的に同じ

センサーだけでは判別できないので、手動トグルで妥協した。

タッチのジェスチャー

Hyprland本体のジェスチャーはlibinputのswipe/pinch専用で、タッチスクリーンの多指認識は持っていない。 素の状態だと画面端からのエッジスワイプしか使えないので、hyprgrassプラグインを入れて3本指の縦スワイプでワークスペースを切り替えている。

ここで1つ落とし穴。パフォーマンス優先でアニメーションを全部切ったら、タッチのワークスペーススワイプが指に追従しなくなった。 追従中の描画位置がアニメーション変数として持たれているらしい。 結局アニメーションは有効に戻し、描画コストの主因だったblur・shadow・透過だけを切る構成にした。これでGPU使用率は93%から42%まで下がった。

デスクトップ環境

最初はML4Wのdotfilesで素のHyprlandを立ち上げて、翌朝にcaelestiaへ移行した。 デスクトップ機で使い慣れているのが理由。

途中でタブレットモードとオンスクリーンキーボード目当てにPlasma 6も入れてみたけど、上に書いたとおり自動判別ができないと分かったのでHyprlandに戻した。 PlasmaはSDDMから選べる状態で残してある。

caelestiaのHyprland設定はLuaで、自分の差分は~/.config/caelestia/hypr-user.luaにだけ書いている。 caelestia本体のhyprland.luaが最後にこれをrequireするので、更新で上書きされない。 Lua設定まわりの話は別記事に書いた。

/posts/hyprland-lua-config-migration

hyprpmのプラグインはhyprpm reloadが要る

hyprpm enableはフラグを立てるだけで、セッションに読み込むのはhyprpm reload。 これを知らずにhypr-user.luaにhyprgrassの設定を書いても、hl.plugin.hyprgrassがnilで設定ごと素通りしていた。 ログイン直後に読ませるため、Hyprlandの起動時にhyprpm reload -nを呼んでいる。

キーバインドはデスクトップ機と変えている

普段使いのデスクトップ機もHyprland + caelestiaだけど、キーバインドはMicroPC 2用に組み直した。 理由は持ち方。この機体は両手で抱えて親指で打つ姿勢になることが多く、Super+Dのような左手だけで完結するキーバインドが逆に押しづらい。 Superは左下、Dは左手の担当なので、片手に全部の仕事が集まってしまう。

そこで、Superを左手、もう1つのキーを右手で押す両手前提の組み合わせに寄せている。 自分で足した主なものはこのあたり。

キー動作
Super+O画面の自動回転トグル
Super+F / Super+/フルスクリーン (Chromeのタブストリップは残す)
Super+Spaceフローティング切替 (画面比50%に縮めて中央寄せ)
Super+↑ / Super+↓ワークスペース移動
Super+中クリックウィンドウを閉じる

Super+↑/Super+↓のワークスペース移動は、hyprgrassの3本指スワイプと同じ動きをキーボードからもできるようにしたもの。 デスクトップ機の設定をそのまま持ってくると持ち方に合わなかったので、機体ごとにhypr-user.luaを分けている。

日本語入力

fcitx5 + mozc。切り替えはCtrl+Space。 環境変数はこれだけ設定している。

1
2
3
4
XMODIFIERS=@im=fcitx
QT_IM_MODULE=fcitx
SDL_IM_MODULE=fcitx
GLFW_IM_MODULE=ibus

GTK_IM_MODULEあえて設定しない。GTK3/4はWaylandのtext-input-v3で直接fcitx5と話すので、設定するとその経路を潰してしまう。

分数スケールとXWayland

7インチに1080x1920なので、スケール1.0だと文字が小さすぎる。 最初は1.5で運用して、後に1.25へ落ち着いた。

分数スケールで困るのがXWayland。XWaylandは整数スケールしか扱えないので、XWaylandに落ちるアプリは全部ぼやける。 「このアプリだけ画質が悪い」と思ったらhyprctl clients -jxwaylandフィールドを見る。 Chromium/Electron系はOzoneでWaylandネイティブにすれば直る。

1
2
--enable-features=UseOzonePlatform,WaylandFractionalScaleV1
--ozone-platform=wayland

電源管理

TDPを8Wに絞ってファンレス運用

BIOSのMain > OEM System Configuration > Configurable TDPで、デフォルトの15Wから8Wに下げた。 効果は絶大で、変更前はアイドル42℃でも2600RPMで回り続けていたファンが完全に止まる。 6W/8Wを選んだときだけ静音ファンモードが有効になる仕様のようで、65℃くらいまで無音でいてくれる。

ターボ上限は据え置きなので短時間のバーストはPL2が吸収するし、体感はほとんど変わらなかった。 重い作業をするときはsysfsから再起動までの一時引き上げができる。

1
2
echo 15000000 | sudo tee /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw
echo 18000000 | sudo tee /sys/class/powercap/intel-rapl:0/constraint_1_power_limit_uw

電源プロファイルはpower-profiles-daemon単独で、power-saver固定。TLPは入れていない。 この機体にはplatform_profileが無いのでppdが制御できるのはEPPだけで、TDPやファンには触れない。 balancedにすればマルチで25〜60%速くなるのは計測済みだけど、遅いのは熱じゃなく意図した電力制限なので、そのままにしている。

ハイバーネート

16GBのswapfileを作って、ローダーエントリにresume=resume_offset=を追加。 mkinitcpioのHOOKSがsystemd系なのでresumeフックの追加は不要だった。

1
2
3
# /etc/systemd/sleep.conf.d/10-hibernate-shutdown.conf
[Sleep]
HibernateMode=shutdown
1
2
3
# /etc/systemd/sleep.conf.d/20-suspend-then-hibernate.conf
[Sleep]
HibernateDelaySec=30min

HibernateDelaySecを書かないと、systemdがバッテリーの放電レートから移行時刻を推定する。挙動が読めないので固定した。

復帰するとUEFI設定画面に飛ぶ

ハイバーネートから復帰するたびにUEFI設定画面に入ってしまう問題にハマった。 原因はBIOSのAMI Fast Boot

systemdはハイバーネート直前にEFI変数HibernateLocationを書く。 Fast Bootが有効だとこれでキャッシュされたブートパスが無効化され、次回起動が設定画面に落ちる、という仕組み。 BIOSでFast Bootを無効にしたら解決した。

この機体で復帰まわりが怪しいときは、まずFast Bootを疑うのが早い。

電源ボタンと蓋

電源ボタンの短押しはlogindでignoreにして、Hyprland側のXF86PowerOffバインドから自作スクリプトを呼んでいる。 ロック画面が立ち上がったのを確認してからsuspendするのが目的で、logindに直接サスペンドさせるとcaelestiaのロック描画が間に合わず、復帰時に作業画面が一瞬見えてしまう。

長押しはpoweroffのまま。Hyprlandが死んで短押しが効かないときの逃げ道として残しておく。

ここで1つ痛い目にあった。systemdのsystem-sleepフックでロック画面を待たせてはいけない。 system-sleepフックはsystemd-sleepのcritical pathで走り、そのときuser.sliceはフリーズ対象になっている。 caelestiaが応答できずにマシンごとハングして、強制電断するはめになった。

蓋はlogindに任せている。

1
2
3
4
5
# /etc/systemd/logind.conf.d/60-lid.conf
[Login]
HandleLidSwitch=suspend-then-hibernate
HandleLidSwitchExternalPower=suspend
HandleLidSwitchDocked=ignore

バッテリー駆動ならS3で寝て30分後にハイバーネート、AC接続なら復帰の速いsuspendのみ。

まとめ

GPD MicroPC2 キーボード接続の様子
GPD MicroPC2 キーボード接続の様子

  • GPD MicroPC 2はArch Linuxで普通に常用できる。タッチも加速度センサーも追加ドライバなしで認識した
  • 画面の向きはカーネル・Xorg・Hyprland・タッチ座標の4か所で個別に指定する。Xorgはpanel orientationを見ないのでSDDMのログイン画面だけ別対応が要る
  • タブレットモードの自動判別はハードウェア的に不可能。手動トグルで妥協する
  • TDPを8Wにするとファンレスになる。体感はほぼ変わらない
  • ハイバーネート復帰でUEFI設定画面に落ちるならBIOSのFast Bootを切る
  • system-sleepフックでユーザープロセスを待ってはいけない

小さいのにちゃんとキーボードがあって、Hyprlandが動いて、ファンが回らない。だいぶ気に入っている。