pshikoro's blog

休日プログラミング

PIC[Programmable Interrupt Controller]とICW[Initical Control Word]とは

PICとICW

どちらもCPUの割り込み制御に関する話題のキーワードである。

CPUには割り込み処理を受け付けるための入力ピンがある。

この割り込み処理を受け付ける入力ピンに信号を送る処理を受け持つのがPIC=>Programmable Interrupt Controllerである。

PIC自体は複数ピンの入力と1本の出力を持ち、その出力がCPUの割り込み入力ピンにつながっている。

PICの各入力ピンに信号が入ってきたときに、どのようにCPUへ信号を出力するかをICWに設定することで、割り込み信号に対する制御をプログラムすることができる。
これがProgrammableと名付けられる所以である。

ICWは4種類あり、ICW2以外は各ICWの1bitごとがPICの各入力ピンに対応しているような設定値である。

PICのマスタとスレーブについて

PICが一個であると、PIC一個についてるピンの数だけしか割り込み信号を受けられない事となる。

より多くの割り込み信号を受け取るために、PICを多段に組み、一つのPICの入力ピンにもう一つのPICの入力ピンをつなぐことで、より多くの信号を受け取れるようにしてあることがある。

このときの、直接CPUにつながっているPICをマスタ、子の方をスレーブと呼ぶ。

なおスレーブの方は割り込み信号が来たということを伝えることはできるが、子のどのピンに割り込みが来たかを伝えることはできない。

ICWについて

ICWは4種類あるが、ICW1と4はPICが基板上でどのように配線されているかというハードウェア的な設定値であるので、各基盤ごとの固定値以外を設定することはほぼない。

ICW3については、PICのマスタとスレーブが、マスタのどのピンでつながっているがを設定する。 これもハードウェア的な設定値であるので、基盤ごとの固定値以外を設定することがない。

なので、プログラマ的に設定することがあるICWは2番だけになる。

ICW2は、各割り込み信号が何番の割り込み信号として認識されるかを設定する値である。 0x20を設定した場合はピン1-8の割り込みがが0x20-0x27の割り込みとして認識されるようになる。

割り込み信号が来た際にCPUの実行するべき命令が何番の割り込み命令か◯◯(◯◯はICW2で設定した数値)に見えるようにハードウェア的に設定されている。 各番号の割り込み時にどの関数を実行するかをIDT(Interrupt descriptor table)に設定することで、割り込み時の処理を設定することができる。

なおICW2で設定する割り込み信号に対する割り込み番号の設定だが、0x00~0x1fはアプリケーションで発生した例外に対してCPUが自動的に割り込みを発生させてOSに知らせる際の番号として利用されているため、設定することができない。

ICW2には0x00~0x1f以外の値を設定することが望ましい。

GDT(Global segment Descriptor Table)とは

GDTとは大域セグメント記述子表の略である。

これを理解するには、セグメンテーションについて理解する必要がある。

セグメンテーションは各プログラムが使用するメモリ領域の区分けのことである。

各プログラムにはそのセグメント領域の起点からの相対アドレスが記述されている。
OSは実行時に各プログラムが使用するセグメント領域を割り振る。
CPUがメモリを操作する際は、プログラムに割り振られたセグメントを起点とした相対位置のメモリを操作する。

なぜこのような操作が必要かというと、OSなどの特殊なプログラムを除き、どのようなプログラムが同時に動作するかはプログラム作成者が知ることは基本的にできないため、操作するメモリの絶対位置を指定することができないからである。

GDTとはこのCPUがプログラムに記述された相対位置を絶対位置に変換する際に参照する、各プログラムに割り当てられたセグメントに関する設定が記述されたテーブルのことである。

このテーブルはそれなりのサイズになるので、メモリ上に配置される。

プログラム実行時にGDTのどのテーブルを参照するかは、セグメントレジスタに設定された値によって変更される。

またこのセグメントの用途としては、リングプロテクションの実装に用いられる。

つまりは、特定のセグメントのみをシステム用のセグメントとしてGDTに設定することで、それ意外のセグメント内での、GDT変更のような特権操作を防ぐことができる。

eflags

eflgasはflagレジスタ

CPUの割り込みフラグの制御などを担当する。

EFLAGS ‐ 通信用語の基礎知識

このレジスタのアドレスに直接書き込みなどはできないのでpushやpopfdなどの命令を仕様する。

_io_load_eflags:    ; int io_load_eflags(void);
    PUSHFD
    POP EAX
    RET

_io_store_eflags:    ; void io_store_eflags(int eflags);
    MOV EAX,[ESP+4]
    PUSH EAX
    POPFD
    RET

30日os本では、ビデオDAコンバータのパレット番号にRGB値を書き込む前後に割り込み処理の禁止→もとに戻す処理の際に初出。

OAuth1.0の署名(Signature)をPythonで生成してみた

経緯

はてなのブログ投稿APIを叩こうと思ったから

そもそもOAuthとは

以下のサイトによくまとまっている。

ゼロから学ぶOAuth【gihyo.jp】 OAuthとは何か【暇なメモ帳】

Signatureの生成方法

作成方法は以下を参考にした OAuth1.0の署名(Signature)を作成する方法

材料

キーの材料 * Consumer secret (client_secret) * Token secret (resource_owner_secret)

データの材料 * Request method * Request URL * Parameter

上のParameterは、リクエストヘッダに記載するAuthorizationパラメータのうちoauthで始まる値及びBodyに記載したデータのこと

たとえばはてなブログのリクエストトークンを取得するリクエストヘッダは以下のとおり

# HTTPS
POST /oauth/initiate HTTP/1.1
Host: www.hatena.com
Authorization: OAuth realm="",
    oauth_callback="oob",
    oauth_consumer_key="yTVGWKqa6OiH5A%3D%3D",
    oauth_nonce="0c670efea71547422662",
    oauth_signature="lvQC7AXTRIaqxbjwVGgPlYuNaaw%3D",
    oauth_signature_method="HMAC-SHA1",
    oauth_timestamp="1291689730",oauth_version="1.0"
Content-Type: application/x-www-form-urlencoded
Content-Length: 33

scope=read_public%2Cread_private

この場合以下の値を材料として用いる + oauth_callback="oob", + oauth_consumer_key="yTVGWKqa6OiH5A%3D%3D", + oauth_nonce="0c670efea71547422662", + oauth_signature="lvQC7AXTRIaqxbjwVGgPlYuNaaw%3D", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="1291689730" + oauth_version="1.0" + scope=read_public%2Cread_private

なおnonceは適当な文字列なのでなんでもよい。

以下はてなのOAuth認を題材にsignatureキーの生成をPythonで行うコード

なおPtynonにはrequestsという便利なライブラリがあるのでそれを使うのが一番早い