30日でできるOS自作入門【22日目】
概要
これはMozyの1人アドベントカレンダー 2018 の22日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 起動方法を少し変更した
今日やったこと
- 起動情報をasmhead.nasから受け取るようにした
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); void init_screen(char *vram, int x, int y); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *vram; int xsize, ysize; short *binfo_scrnx, *binfo_scrny; int *binfo_vram; init_palette(); binfo_scrnx = (short *) 0x0ff4; binfo_scrny = (short *) 0x0ff6; binfo_vram = (int *) 0x0ff8; xsize = *binfo_scrnx; ysize = *binfo_scrny; vram = (char *) *binfo_vram; init_screen(vram, xsize, ysize); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; } void init_screen(char *vram, int x, int y) { boxfill8(vram, x, COL8_008484, 0, 0, x - 1, y - 29); boxfill8(vram, x, COL8_C6C6C6, 0, y - 28, x - 1, y - 28); boxfill8(vram, x, COL8_FFFFFF, 0, y - 27, x - 1, y - 27); boxfill8(vram, x, COL8_C6C6C6, 0, y - 26, x - 1, y - 1); boxfill8(vram, x, COL8_FFFFFF, 3, y - 24, 59, y - 24); boxfill8(vram, x, COL8_FFFFFF, 2, y - 24, 2, y - 4); boxfill8(vram, x, COL8_848484, 3, y - 4, 59, y - 4); boxfill8(vram, x, COL8_848484, 59, y - 23, 59, y - 5); boxfill8(vram, x, COL8_000000, 2, y - 3, 59, y - 3); boxfill8(vram, x, COL8_000000, 60, y - 24, 60, y - 3); boxfill8(vram, x, COL8_848484, x - 47, y - 24, x - 4, y - 24); boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y - 4); boxfill8(vram, x, COL8_FFFFFF, x - 47, y - 3, x - 4, y - 3); boxfill8(vram, x, COL8_FFFFFF, x - 3, y - 24, x - 3, y - 3); return; }
0x0ff4;
とかの番地はasmhead.nasに合わせただけです。特に難しい意味はありませんね。
また、背景の描画を、init_screen関数にはき出した。
ハマりポイント
特になし。
知ったこと
一つ一つ積み上げて実装をしているので、init_screenを書き出す意味とか、そういう実装の意図がきちんと理解できるので大変良いと思った。
普段の、誰かが実装したコードに対してコードを追加していく作業とは少し違う頭を使うなぁ。
30日でできるOS自作入門【21日目】【祝3週間目】
概要
これはMozyの1人アドベントカレンダー 2018 の21日目の記事です。
書こうとした経緯は、こちら
今日の内容
- どんどん画面を作っていく
今日やったこと
- タスクバーっぽいものを実装したw
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *vram; int xsize, ysize; init_palette(); vram = (char *) 0xa0000; xsize = 320; ysize = 200; boxfill8(vram, xsize, COL8_008484, 0, 0, xsize - 1, ysize - 29); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 28, xsize - 1, ysize - 28); boxfill8(vram, xsize, COL8_FFFFFF, 0, ysize - 27, xsize - 1, ysize - 27); boxfill8(vram, xsize, COL8_C6C6C6, 0, ysize - 26, xsize - 1, ysize - 1); boxfill8(vram, xsize, COL8_FFFFFF, 3, ysize - 24, 59, ysize - 24); boxfill8(vram, xsize, COL8_FFFFFF, 2, ysize - 24, 2, ysize - 4); boxfill8(vram, xsize, COL8_848484, 3, ysize - 4, 59, ysize - 4); boxfill8(vram, xsize, COL8_848484, 59, ysize - 23, 59, ysize - 5); boxfill8(vram, xsize, COL8_000000, 2, ysize - 3, 59, ysize - 3); boxfill8(vram, xsize, COL8_000000, 60, ysize - 24, 60, ysize - 3); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize - 4, ysize - 24); boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize - 4); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize - 3, xsize - 4, ysize - 3); boxfill8(vram, xsize, COL8_FFFFFF, xsize - 3, ysize - 24, xsize - 3, ysize - 3); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; }
基本的にはHariMainしか変更していないですが、OSっぽい画面になってきたでしょ!
ハマりポイント
ピクセルズレとかを考えて計算式を書くのがツラかった。。
知ったこと
なるほど。こうやってGUIは発展してきたのだなぁと 体感
できたのは大きかった
3週間目を迎えて
さすがに、3週間毎日ブログを書いているのを見返すと、やればできるじゃん俺って気持ちになってくる。
あと1週間。ここまできたらどんなことがあっても終わらせてやるぜ!
CSS のセレクタ名は数字から始めることができないって話
経緯
プログラミング関連を教えている際に、
Selenium (自動化ツール) を使い、CSSセレクタを選択してエレメントを取得する場合に、HTMLファイル側の <div id="101">
など、IDが数字のみだと要素が取得できない。
<div id="A101">
だと取得できるてな問題に関して質問されました。
そこでパッとは回答が思いつかなくて考えていたんですが、さっき家でボケーっとしてる時にふと回答を思い出しましたよ!
答え
これってCSSのセレクタ名の制約に引っかかっているから問題が起こるんだった。遥か昔に悩んだ記憶がある
CSSのセレクタ名で使える文字は、
- 大小アルファベットと数字 [A-Za-z0-9]
- ASCII以外のUnicode文字
- ハイフン(-)
- アンダースコア(_)
に限る。
のでした。
それと制約条件としてセレクタ名は
- 数字もしくはハイフンと数字の組合せで始めることはできない
- セレクタの要素型名、クラス名、ID名はハイフンで始めることはできない
のです。
そのため使用していたSelenium にて driver.find_elements_by_css_selector(selector)
などのcss_selector
を利用するような関数を使っていた場合はエラーが出て動かないのだと思われます。
該当する関数定義がここ
最終的に呼ばれている部分はここ
SchemaをModelにコメントとして書き出してくれるGem annotate
導入
Gemfileにannotate
を追加してbundle install で導入できる。
Schema情報の追加
実行する。
Table Schemaをコメントとして追加するコマンド
bundle exec annotate
結果
以下のように書き込まれる。便利〜
# == Schema Information # # Table name: hoge_fuga_piyo # # id :integer not null, primary key # user_id :integer not null # created_at :datetime not null # updated_at :datetime not null # hoge huga piyopiyo
【Android】Bluetooth HCI スヌープ ログの取り方 【2018年12月 最新版】
経緯
あるところから、あるハードウェアのBluetooth通信解析(パケットキャプチャ)を頼まれて、悩んだことのメモです。
今回の検証端末はNexus5X Android 8.1.0
を使用しています
本題
WiresharkをDL
ここら辺から適当にDLしてくださいな〜。
Wireshark · Go Deep.
ADBコマンドを使えるようにする
Mac ユーザで brewコマンド、brew caskコマンドが使える人は以下のようにインストール出来ます。
brew cask install android-platform-tools
brew caskってのは簡単にいうとmacOS のアプリケーションをバイナリから良い感じにインストールして使えるようにしてくれるナイスツールです。
caskのインストールは以下を参照のこと。
github.com
Android端末設定
- 設定 > ビルド番号 を連打しまくって開発者オプションを出す
- 開発者オプションから、USBデバッグをON
- 開発者オプションから、Bluetooth HCIスヌープログをON
- いつも通りBluetooth通信をしてみるとその生ログがどんどん端末内のファイルに書き込まれる
Bluetooth HCIスヌープログをOFFにしないと端末の中に、Bluetooth通信のログがどんどん溜まってあっという間に、容量無くなるので注意!
ログを書き出す
ここが一番鬼門だった場所でやっと突破できた。
以前までのadb shell cat
などのコマンドでログの保存場所をみつけることができなくなったので、バグレポートの機能を使うことで同じことを実現できる。
端末とPCをUSBで繋いで
adb bugreport bugreportfolder
を叩くとbugreportfolder
というzipが生成されるので、解凍する。
そして以下のようなファイルが確認できるはず
バグレポートの中身
バグレポートのファイル名は以下のような感じになっているハズ
bugreport-bullhead-OPM4.171019.016.A1-2018-12-21-00-02-56.txt
んでこれから Bluetooth に関するログ部分を抽出する必要がある。
この抽出のためのPythonスクリプトをGoogleが用意しているのでありがたく使わせていただく。
tools/scripts/btsnooz.py - platform/system/bt - Git at Google
このスクリプトを使ってログを抽出する。
./btsnooz.py bugreport-bullhead-OPM4.171019.016.A1-2018-12-21-00-02-56.txt > BTSNOOP.log
そうすると生ログのみのファイルが生成される。
Wireshark で解析をする
Wiresharkのファイル > 開く から先ほど生成したBTSNOOP.log
を選択するとこんな感じでログファイルがみることができるようになる!
そしてこれを元にどんどん辿っていって通信の方法や、どんなやりとりをしているかを逐一追っていけば、Android端末と、その他のハードウェアがどういったやりとりをしているかが解析できるってわけです。
参考
30日でできるOS自作入門【20日目】
概要
これはMozyの1人アドベントカレンダー 2018 の20日目の記事です。
書こうとした経緯は、こちら
今日の内容
- 四角形を書いてみるぞ
今日やったこと
- 今まで知ったことを使って図形を描いてみる
今の画面モードでは、320 x 200 (64000)個の画素がある。その左上を(0,0)として右下を(319, 199) とすると、画像座標(x,y)に対応するVRAMの番地は、
0xa0000 + x + y * 320
で計算できるから、このメモリに色番号を記憶させれば原理上指定した色が出るわけか。
やってみよう
bootpack.c
void io_hlt(void); void io_cli(void); void io_out8(int port, int data); int io_load_eflags(void); void io_store_eflags(int eflags); void init_palette(void); void set_palette(int start, int end, unsigned char *rgb); void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1); #define COL8_000000 0 #define COL8_FF0000 1 #define COL8_00FF00 2 #define COL8_FFFF00 3 #define COL8_0000FF 4 #define COL8_FF00FF 5 #define COL8_00FFFF 6 #define COL8_FFFFFF 7 #define COL8_C6C6C6 8 #define COL8_840000 9 #define COL8_008400 10 #define COL8_848400 11 #define COL8_000084 12 #define COL8_840084 13 #define COL8_008484 14 #define COL8_848484 15 void HariMain(void) { char *p; /* pはBYTE [...]用の番地 */ init_palette(); /* パレット設定 */ p = (char *) 0xa0000; /* 番地を代入 */ boxfill8(p, 320, COL8_FF0000, 20, 20, 120, 120); boxfill8(p, 320, COL8_00FF00, 70, 50, 170, 150); boxfill8(p, 320, COL8_0000FF, 120, 80, 220, 180); for (;;) { io_hlt(); } } void init_palette(void) { static unsigned char table_rgb[16 * 3] = { 0x00, 0x00, 0x00, /* 0:黒 */ 0xff, 0x00, 0x00, /* 1:明るい赤 */ 0x00, 0xff, 0x00, /* 2:明るい緑 */ 0xff, 0xff, 0x00, /* 3:明るい黄色 */ 0x00, 0x00, 0xff, /* 4:明るい青 */ 0xff, 0x00, 0xff, /* 5:明るい紫 */ 0x00, 0xff, 0xff, /* 6:明るい水色 */ 0xff, 0xff, 0xff, /* 7:白 */ 0xc6, 0xc6, 0xc6, /* 8:明るい灰色 */ 0x84, 0x00, 0x00, /* 9:暗い赤 */ 0x00, 0x84, 0x00, /* 10:暗い緑 */ 0x84, 0x84, 0x00, /* 11:暗い黄色 */ 0x00, 0x00, 0x84, /* 12:暗い青 */ 0x84, 0x00, 0x84, /* 13:暗い紫 */ 0x00, 0x84, 0x84, /* 14:暗い水色 */ 0x84, 0x84, 0x84 /* 15:暗い灰色 */ }; set_palette(0, 15, table_rgb); return; /* static char 命令は、データにしか使えないけどDB命令相当 */ } void set_palette(int start, int end, unsigned char *rgb) { int i, eflags; eflags = io_load_eflags(); /* 割り込み許可フラグの値を記録する */ io_cli(); /* 許可フラグを0にして割り込み禁止にする */ io_out8(0x03c8, start); for (i = start; i <= end; i++) { io_out8(0x03c9, rgb[0] / 4); io_out8(0x03c9, rgb[1] / 4); io_out8(0x03c9, rgb[2] / 4); rgb += 3; } io_store_eflags(eflags); /* 割り込み許可フラグを元に戻す */ return; } void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1) { int x, y; for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) vram[y * xsize + x] = c; } return; }
ハマりポイント
特になし〜。順調だ。
知ったこと
画素とメモリとの対応を直接考えてプログラミングしたのは初めてだった笑
面白いなぁ。
30日でできるOS自作入門【19日目】
概要
これはMozyの1人アドベントカレンダー 2018 の19日目の記事です。
書こうとした経緯は、こちら
今日の内容
- naskfunc.nas をどんどん書いていく
今日やったこと
- 昨日作っていたC言語では実現できなかったハードウェアのIO部分に関する部分を作成した。
; [FORMAT "WCOFF"] ; [INSTRSET "i486p"] [BITS 32] ; [FILE "naskfunc.nas"] GLOBAL io_hlt, io_cli, io_sti, io_stihlt GLOBAL io_in8, io_in16, io_in32 GLOBAL io_out8, io_out16, io_out32 GLOBAL io_load_eflags, io_store_eflags [SECTION .text] io_hlt: ; void io_hlt(void); hlt ret io_cli: ; void io_cli (void); cli ret io_sti: ; void io_sti (void); sti ret io_stihlt: ; void io_stihlt (void); sti hlt ret io_in8: ; io_in8 (int port); mov edx,[esp+4] ; port mov eax, 0 in al, dx ret io_in16: ; int io_in16 (int port); mov edx,[esp+4] ; port mov eax, 0 in ax, dx ret io_in32: ; int io_in32 (int port); mov edx,[esp+4] ; port in eax, dx ret io_out8: ; void io_out8(int port, int data); mov edx,[esp+4] ; port mov al, [esp+8] ; data out dx, al ret io_out16: ; void io_out16(int port, int data); mov edx,[esp+4] ; port mov ax, [esp+8] ; data out dx, ax ret io_out32: ; void io_out32(int port, int data); mov edx,[esp+4] ; port mov eax,[esp+8] ; data out dx, eax ret io_load_eflags: ; int io_load_eflags (void); pushfd ; push eflags pop eax ret io_store_eflags: ; void io_store_eflags (int eflags); mov eax,[esp+4] push eax popfd ; pop eflags ret
ハマりポイント
特になし〜。昨日ポインタ周りとかをきちんと追ったからだな。
知ったこと
EFLAGS関連はPUSHFDとPOPFDで実現できる。
それぞれ フラグをダブルワードでスタックから飛ばす、スタックに登録するという意味