OSが書けなくても画面にお絵描きがしたい
PCでお絵描きがしたい、けど…
冬です
外は寒いのでこたつに入ってPCでお絵描きでもしたいところです
しかし、筆者のパソコンはOSもペイントソフトも入っておらずお絵描きをすることができません
どうしてもお絵描きがしたいので、今日は頑張ってPCの画面にお絵描きできるようにします
この記事はWORDIAN Advent Calendar 2018 - 23日目の記事です
戦略
さて、PCを動かすためにまずはブートローダが必要です。ブートローダはBIOSの仕様に沿って実装する訳ですが、アセンブリを書いてプログラムがメモリの0x7c00にロードされ...32bitプロテクトモードに移行して...のように非常に難解なことをしないといけません。冬が終わってしまいます。世の中は便利なものでGRUBと呼ばれる素晴らしいブートローダが存在するため、ありがたく利用することにします。GRUBはよろしくやってくれた後にフレームバッファの場所を教えてくれるのでそこに色を書き込むことでお絵描きができます。
あ、GRUBを用意したりプログラムをコンパイルしたりするためのPCは別途用意することにしました。
GRUBを用意する
PCにGRUBをインストールします。ArchLinuxの人は
sudo pacman -S grub
で入ります。
GRUBで読み込めるプログラムの形式について
GRUBではmultibootと呼ばれるプログラムの形式を使用することができます。お絵描きするために最低限必要な事項は本記事で記述しますが、詳しい仕様についてはMultiboot Specification version 0.6.96をご確認ください。
Multiboot Specificationの3.1 OS image formatではプログラムの形式についての規定がされています。いろいろ書いてありますが、どうやらプログラムにはMultiboot headerが必要でファイルの先頭8192バイトに格納されている必要があるようです。3.2 Machine stateと3.3 Boot information formatではmultibootが読み込まれた後にGRUBが返してくれるマシンの状態に関する記述があります。これについても後述します。
Multibot headerの形式
Offset | Type | Field Name | Note | |
---|---|---|---|---|
0 | unsigned 32bit | magic | required | |
4 | unsigned 32bit | flags | required | |
8 | unsigned 32bit | checksum | required | |
12 | unsigned 32bit | header_addr | if flags[16] is set | 今回は使わない |
16 | unsigned 32bit | load_addr | if flags[16] is set | 今回は使わない |
20 | unsigned 32bit | load_end_addr | if flags[16] is set | 今回は使わない |
24 | unsigned 32bit | bss_end_addr | if flags[16] is set | 今回は使わない |
28 | unsigned 32bit | entry_addr | if flags[16] is set | 今回は使わない |
32 | unsigned 32bit | mode_type | if flags[2] is set | |
36 | unsigned 32bit | width | if flags[2] is set | |
40 | unsigned 32bit | height | if flags[2] is set | |
44 | unsigned 32bit | depth | if flags[2] is set |
magic
マジックナンバーです。必ず0x1BADB002を格納します。flags
bit 0,1,2,15を使います。bit 2を1にするとビデオモードを設定することができます。今回はとりあえず1にしましょう。 bit 0,1,15はそれぞれ1,1,0にしておきます。お絵描きに関係ないので説明は割愛します。checksum
チェックサムです。-(magic+flags)を格納します。mode_type
ビデオモードの希望です。グラフィックモード(0)かテキストモード(1)のどちらかに設定することができます。お絵描きするにはグラフィックモードのほうが嬉しいので今回は0に設定しておきます。width,height
画面のサイズの希望を設定することができます。お絵描きにおけるキャンパスサイズとなります。とりあえず最初はwidthを640、heightを480くらいにしておくことにします。depth
ビット深度の希望です。32にします。その他
今回は使わないため説明は割愛します。値は適当に0にしておきましょう。
multibootが読み込まれた後のマシンのレジスタの状態
色々と記述がありますがとりあえずEBXとついて気にしておけば良さそうです。
GRUBから渡されるブート情報について
multibootがGRUBに読み込まれるとEBXにブート情報構造体のポインタが格納されます。お絵描きをするために必要なフレームバッファの情報もあります。
+-------------------+ 0 | flags | (required) +-------------------+ 4 | mem_lower | (present if flags[0] is set) 8 | mem_upper | (present if flags[0] is set) +-------------------+ 12 | boot_device | (present if flags[1] is set) +-------------------+ 16 | cmdline | (present if flags[2] is set) +-------------------+ 20 | mods_count | (present if flags[3] is set) 24 | mods_addr | (present if flags[3] is set) +-------------------+ 28 - 40 | syms | (present if flags[4] or | | flags[5] is set) +-------------------+ 44 | mmap_length | (present if flags[6] is set) 48 | mmap_addr | (present if flags[6] is set) +-------------------+ 52 | drives_length | (present if flags[7] is set) 56 | drives_addr | (present if flags[7] is set) +-------------------+ 60 | config_table | (present if flags[8] is set) +-------------------+ 64 | boot_loader_name | (present if flags[9] is set) +-------------------+ 68 | apm_table | (present if flags[10] is set) +-------------------+ 72 | vbe_control_info | (present if flags[11] is set) 76 | vbe_mode_info | 80 | vbe_mode | 82 | vbe_interface_seg | 84 | vbe_interface_off | 86 | vbe_interface_len | +-------------------+ 88 | framebuffer_addr | (present if flags[12] is set) 96 | framebuffer_pitch | 100 | framebuffer_width | 104 | framebuffer_height| 108 | framebuffer_bpp | 109 | framebuffer_type | 110-115 | color_info | +-------------------+
色々ありますが必要な部分はオフセット88からのフレームバッファに関する情報のみです。
Offset | Type | Field Name |
---|---|---|
88 | unsigned 64bit | framebuffer_addr |
96 | unsigned 32bit | framebuffer_pitch |
100 | unsigned 32bit | framebuffer_width |
104 | unsigned 32bit | framebuffer_height |
108 | unsigned 32bit | framebuffer_bpp |
109 | unsigned 32bit | framebuffer_type |
110-115 | unsigned 32bit | color_info |
framebuffer_addr
フレームバッファの先頭のアドレスです。64bitです。注意framebuffer_pitch
バイトのピッチです。単位はバイトframebuffer_width , framebuffer_hight GRUBが設定したフレームバッファの縦横のサイズです。
framebuffer_bpp GRUBが設定したフレームバッファのビット深度です。
framebuffer_type GRUBが設定したフレームバッファの種類です。0だとインデックスカラー、1だとダイレクトカラー、2だとテキストモードになっています。また、0,1ではこの後のcolor_infoが使用されます。
color_info
framebuffer_typeが1(ダイレクトカラーの場合)
+----------------------------------+ 110 | framebuffer_red_field_position | 111 | framebuffer_red_mask_size | 112 | framebuffer_green_field_position | 113 | framebuffer_green_mask_size | 114 | framebuffer_blue_field_position | 115 | framebuffer_blue_mask_size | +----------------------------------+
32bit中に各色がどのように配置されるかが格納されています。positionが下位ビットから何bit目からかを、mask_sizeがビットの幅を表しています。 今回はダイレクトカラーに設定されることを前提とするため、インデックスカラーの場合の説明は割愛します。
実装
Multiboot Specificationの4.3 Example OS codeにはサンプルコードがあります。せっかくなので利用します。
プリプロセッサ定義や構造体が含まているmultiboot.hはそのまま使います。
multiboot.h (クリックで展開)
boot.SではMultiboot headerを配置してC言語をコンパイルした関数を呼びます。サンプルから不要な部分を削除して最小限必要な部分のみを残しました。
画像データを描画するCプログラムです。ダイレクトカラーでdepthが32bitに設定されていることが前提です。とりあえず画面を緑色で塗りました。
コードが書けたら
$ gcc -m32 -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o oekaki.o oekaki.c $ gcc -m32 -ffreestanding -fno-common -fno-builtin -fomit-frame-pointer -O2 -c -o boot.o boot.S $ ld -melf_i386 -Ttext=0x100000 --oformat elf32-i386 -o Oekaki boot.o oekaki.o
のようにコンパイルとリンクを行います。テキストエディタでgrub.cfgも作成しましょう。
menuentry "oekaki" { multiboot /boot/Oekaki boot }
grub-mkrescueでブートイメージを作成します。
$ mkdir -p iso/boot/grub $ mv Oekaki iso/boot $ mv grub.cfg iso/boot/grub $ grub-mkrescue -o oekaki.iso iso
作成したプログラムのブートイメージが作成されました。試しにqemuでブートしてみましょう。
これでフレームバッファの中身を画面に出せるようになりました。後はソースコードを適当にいじれば画像等も表示することができます。
めでたしめでたし
JRの指定席の空席を確認するSlack botを作った
この記事は#一人GWハッカソン
の記事です
前置き(?)
JRにはサイバーステーションというWeb上で指定席の空き状況が確認できるサービスがあります。 今回はこのサイバーステーションから空席情報を取得するbotを作ってみました。
内部ではseleniumとNokogiriで情報を取得しています。
副産物(というか今回のメイン)
人気列車の指定席は発売開始後すぐ売れ切れてしまい、なかなか取れないことがあります。
そういった列車の指定席を取るためにはキャンセルを待たなければなりません。しかし、いちいち空席情報を確認するのは非常に面倒くさい作業です。
この面倒臭さを解消するために空席情報を監視するプログラムを書きました。
このように取得したい列車の情報をSQLでDBに登録して実行すると...
このように変化を通知してくれます。
あとはこのプログラムをcronで定期実行させSlack等に通知が行くようにすれば、空席が発生し通知を受信した瞬間にえきねっとやe5489で座席を購入することができるでしょう。
githubリポジトリ
MNPのためのLinksMate(検証)
MNP弾としてLinksMateを利用してみました。
申し込み→転出までの費用
項目 | 金額 |
---|---|
1GBプラン¥500(日割り適用) | ¥323 |
音声通話機能 | ¥600 |
ユニバーサルサービス料 | ¥2 |
新規契約事務手数料 | ¥3000 |
SIMカード発行手数料 | ¥400 |
MNP予約番号発行手数料 | ¥2000 |
SIMカード削除事務手数料 | ¥3000 |
消費税 | ¥746 |
合計 | ¥10071 |
手続きの流れ
(1日目)
↓申し込み開始
↓書類審査通過
↓
(2日目)
↓SIMカード発送
↓MNP番号申請
↓
(3日目)
↓SIMカード到着
↓MNP番号通知
↓
MNP転出→解約
申し込みからMNP番号発行まで3日を要しました。
データ料金の日割りについて
解約月は日割りは適用されませんが契約月に解約する場合は日割り適用になります。データ容量も日割りになります。
料金発生が一日のみの場合(一月31日で計算しました)
(1/31)*500+他料金(9002)+税 = 9740
申し込み完了日の5日後が料金発生日です。
初月の解約について
一部記事でMNP転出は契約翌月から可能との記述があるが誤り。
契約月の転出は可能(サポートに確認済
まとめ
その他
docomo系MVNOでもdocomoにMNP転入は可能です(DS店員に確認済み
事務手数料¥1000割引キャンペーン期間なら8000円台での転出が可能?
秋の大感謝祭キャンペーン | LinksMate(リンクスメイト) - ゲームプレイヤーのためのお得なSIM
(TC安すぎ...)
セキュリティ・キャンプ2016の思い出
ポンコツ過ぎるし、頭大丈夫じゃない気がする…
応募まで
気づいたら締め切り3日前だった。
土日寝ないで書いたから文章がヤバい。
応募するだけでもためになると思う。
選考結果発表
授業中に結果のメールがスマートウォッチに来た。
受かると思ってなかったので嬉しすぎてその日は授業に身が入らなかった。
去年の発表は6/14だったので今年もそろそろですね。
/*
この日からはtwitterとかで「セキュキャン」とか「セキュリティ・キャンプ」とかで検索しないほうが良い。
妬みは非常に見苦しいのでやめましょう
*/
前日
正直当日起きれるか微妙だったので夜行バスで東京に行くことにした。
しかし、夜行バスに乗り遅れて死
1日目
早朝に新宿に到着し時間まで東京をふらつく。
(当時流行っていたアニメ「NewGame!!」の聖地巡礼で阿佐ヶ谷へ行ったり秋葉原行ったりしてました)
阿佐ヶ谷までお越しの方は都区内パスがおすすめです(750円)
— あきー (@akkkix) 2016年8月8日
イーグルジャンプに来ました pic.twitter.com/NsAWwWXgM2
— あきー (@akkkix) 2016年8月8日
時間ギリギリになりつつも会場に到着し名刺交換等…
3日目
寝坊した。
運営からのモーニングコール(絶望)で飛び起き、急いで支度して部屋を出ようとしていたところに運営の人が部屋まで来た。
寝坊からの中鍵をキメてしまった
— あきー (@akkkix) 2016年8月11日
今気づいたけど名札つけてない
— あきー (@akkkix) 2016年8月11日
5日目
貰いました
👍👍👍👍👍👍👍 pic.twitter.com/dsEN6zr4xR
— あきー (@akkkix) 2016年8月12日
とても楽しい実験ですねー 次はクリップを持ってどちらかにぶっさすロシアンルーレットでもどうでしょうk(ry
— taniho (@taniho_0707) 2016年8月12日
一応穴が長い極がcoldなのでそっちに刺すせばいけそうw
— あきー (@akkkix) 2016年8月12日
ビル内の配線が正しい保証はないんだよなあ(白目)
— taniho (@taniho_0707) 2016年8月12日
これ(白目
— あきー (@akkkix) 2016年8月12日
修了証書授与の時に「眠い?」って聞かれた。(大丈夫です。ちゃんと起きてます。) このあと適当に東京ふらついて赤羽の宿へ
X日目(コミックマーケット90)
セキュキャン6日目です pic.twitter.com/0xJl5Jipth
— あきー (@akkkix) 2016年8月14日
二回目のコミケ参加。
やっぱりまだ入れないか pic.twitter.com/Twi4JGBQJL
— あきー (@akkkix) 2016年8月14日
セキュリティキャンプ関係者のサークル等を廻る。
その後新幹線で帰路へ
これだけの荷物を持ち帰るのしんどかった pic.twitter.com/kX6rvMfOK8
— あきー (@akkkix) 2016年8月14日
グループ「おねぇちゃぁん(裏声)」の人たちへ
クソ無能で本当に申し訳ありませんでした
BrainFu*kインタプリタを書いた
この記事は#一人GWハッカソン
5/3の記事です
今日のテーマはなんかのインタプリタを作る
です
最初は自分で言語作る気満々でした
11:00~12:00 言語仕様の妄想
- 四則演算ができる
- スタックが用意されていて自由に使える
- 変数は予め定められた8つ
- 配列なんてなかった
- 標準で用意されている関数はprintのみ
- if,while,breakが使える
- for文なんてなかった
…
12:30~13:55
AbemaTVで「変態王子と笑わない猫。」一挙放送やってたので見ました。
脳が溶けました。
13:00 ~ 14:00 感覚でコードを書き始める
昔javascriptで作った四則演算のプログラムを参考にprintとかを実装し始めるものの、
途中でわけわからなくなって死。
14:00 ~ 調査
流石に感覚で書くには無理があると感じ、ネットの情報を漁り始める。
一般的なインタプリタでは字句解析と構文解析というものが行われているらしい。
そして構文解析によって生成された構文木を元にプログラムが実行される。
なるほどなるほど。構文木とかどうやって実装したら良いのか全くわからないんですけど…ウケる…
15:00~16:00 (:3 」∠ )
寝
17:00~ BrainがFu*ck
結局何もできてねーなとか思いながら微妙な気分になる。
何も成果物が無いのは流石にアレなので最終手段として考えていたBrainFu*ckを書き始める…
BrainFuckの実装は[
,]
さえ実装してしまえば後は簡単だった。
なんの捻りもないただのBrainFuc*kが完成した。
反省…
昔四則演算のプログラム書いたことあるしいけると思ってた
実装力がなくてつらいなぁ…
GW後半らへんにネタ切れになったらまた挑戦したい…
参考:
http://www.hpcs.cs.tsukuba.ac.jp/~msato/lecture-note/comp-lecture/
OSなしでHelloWorld
この記事は#一人GWハッカソン 5/2の記事です
本日のテーマはOSなしでHelloWorldをする
です
最初はOSを作ろうと思っていましたが一日では無理でした。
10:00~12:00 環境構築
Windowsで環境を構築しようとしたけど上手くいかない… 仕方なくVirtualBoxの上のLinuxを使用する
OSはXubuntu16.04、アセンブラはnasm、仮想マシンにはqemuとvirtualboxを使用
12:00~13:00 初めてのプログラム
[BITS 16] ORG 0x7C00 BOOT: CLI HLT TIMES 510 - ($ - $$) DB 0 DW 0xAA55
起動した後にブートセクタがメモリの0x7C00に読み込まれるらしいのでORGで0x7C00をセット(GASではORGは使えないみたいですね)
CLIで割り込み禁止、HLTでプログラム終了
最後に位置合わせに0x00を出力しブートセクタ終端の0xAA55
C言語でいう
#include ‹stdio.h› int main(void){ return 0; }
みたいなプログラムらしい。
13:00~14:00 いろいろ
スタックとかセグメントとか
14:00~15:00 INT10
画面入出力とかディスクの読み書きとかするためにはBIOSが提供している機能を使う
画面入出力をするためにはINT 0x10を使う。
INT0x10を使って文字を出力するためには
AHに0x0E
ALに文字のASCIIコード
BHにビデオページ番号
(よくわからないけど0x00で良いらしい)
BLに色を指定
[BITS 16] ORG 0x7C00 BOOT: CLI MOV AH, 0x0E MOV AL, 0x41 ;'A' MOV BH, 0x00 MOV BL, 0x07 ;グレー INT 0x10 HLT TIMES 510 - ($ - $$) DB 0 DW 0xAA55
色が変わらないと思ったらビデオモードというのを変えないといけないらしい
グラフィックモードを指定するためにはAXに0x4f02を入れてBXにビデオモードを入れる
ビデオモードは
VESA BIOS Extensions - Wikipedia
で解説されている
[BITS 16] ORG 0x7C00 BOOT: CLI MOV AX, 0x4f02 MOV BX, 0x0102 ;800x600 16色モード INT 0x10 MOV AH, 0x0E MOV AL, 0x41 ;'A' MOV BH, 0x00 MOV BL, 0x0A ;ライトグリーン INT 0x10 HLT TIMES 510 - ($ - $$) DB 0 DW 0xAA55
AHに0x13を入れてINT 0x10すると文字列が表示できるらしいです
なんかちょっと感動
15:00~16:00 寝
昼寝
16:00~ ゚Ω\ζ°)チーン
ディスクの読み書きにハマる
解決方法が分からず終
反省とか
またいつか挑戦したい
こんな感じであと5日浅く広く色々やれればと思う
INT0x10しただけだしハッカソンじゃなくね!?
参考:
http://softwaretechnique.jp/OS_Development/scratchbuild.html
VyOSでルーターを作る
お久しぶりです。
訳あって家のネットワークを分ける必要がでてきたので、今日はVyOSを使ってルーターを作ってみます。
VyOSとは
- Vyatta からフォークしたオープンソースのネットワーク OS
- Debian GNU/Linuxを基板として開発されている
今日の目標
トポロジ
いわゆる2重ルーターです
送信元 | 送信先 | 操作 |
---|---|---|
192.168.2.0/24 | 192.168.1.0/24 | DROP |
ポート開放
受信ポート | 送信先 | 送信ポート |
---|---|---|
1234 | 192.168.2.2 | 22 |
インストール
https://vyos.io/
stableをダウンロードしました。(v1.1.7)
イメージから起動し、ログインします。
install image
インストールが始まるので少し待ちましょう。
インターフェイスへのIPアドレスの割当
インストールが終わったら、起動させてログインします。
configure
設定モードへ入ります。
eth0を192.168.1.2/24、eth1を192.168.2.1/24にします。
set interfaces ethernet eth0 address 192.168.1.2/24 set interfaces ethernet eth1 address 192.168.2.1/24
NATの設定
外部側がeth0、内部側がeth1です。
set nat source rule 1 outbound-interface eth0 set nat source rule 1 source address 192.168.2.0/24 set nat translation address masquerade
これで192.168.2.0/24内のホストがNATされて192.168.1.0/24側に出られるようになりました。
デフォルトゲートウェイの設定
このままでは192.168.2.0/24側のホストはインターネットに出られません。
次に経由するルーター(トポロジのPR-S300NE)を指定します。
protocols static route 0.0.0.0/0 next-hop 192.168.1.1
※systemのgateway-addressでも設定できるみたいです
set system gateway-address 192.168.1.1
ファイアウォールの設定
今回は192.168.2.0/24から送信されたパケットの宛先が192.168.1.0/24だった場合のみDROPします。
set firewall name private-public default action accept set firewall name private-public rule 1 destination address 192.168.1.0/24
お好みでログを設定します。
set firewall name private-public rule 1 log enable
set interfaces ethernet eth1 firewall in name private-to-public
ポート開放
内部のホストにsshできるようにしておきます。
set nat destination rule 1 inbound-interface eth0 set nat destination rule 1 protocol tcp set nat destination rule 1 destination address 192.168.1.2 set nat destination rule 1 port 1234 set nat destination rule 1 translation address 192.168.2.2 set nat destination rule 1 port 22
2重ルーターになっているのでインターネットからアクセスしたい場合はインターネットに接続しているルーターもポート開放します。
NTPの設定
ログ等に正確な時間が記録されるようにVyOSをNTPで時刻合わせします。
set system ntp server ntp.jst.mfeed.ad.jp
設定の反映と保存
設定を変更したら忘れずに
commit save
やりましょう。
静的ルーティングの設定
最後に192.168.1.0/24から192.168.2.0/24にアクセスできるように静的ルーティングを設定しておきます。
(PR-S300NEの例)