├── .gitignore ├── KL-01 ├── LICENSE ├── Makefile ├── command.c ├── consdrv.c ├── consdrv.h ├── defines.h ├── interrupt.c ├── interrupt.h ├── interrupt_handler.S ├── intr.h ├── kozos.c ├── kozos.h ├── ld.scr ├── lib.c ├── lib.h ├── main.c ├── memory.c ├── memory.h ├── raspi.cfg ├── raspi_with_ngxtech.cfg ├── raspi_with_olimex.cfg ├── rpi_peripherals.h ├── serial.c ├── serial.h ├── startup.S ├── syscall.c ├── syscall.h └── vector.S /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.o 3 | *.disas 4 | *.elf 5 | *.img 6 | *.d 7 | *.bin 8 | *~ 9 | -------------------------------------------------------------------------------- /KL-01: -------------------------------------------------------------------------------- 1 | 川合堂ライセンス-01 ver.1.0 2 | 2000.12.30 H.Kawai (川合秀実) 3 | 2007.10.07 リンク修正:あっきぃ 4 | 5 | 0.概要 6 | 7 | 平たく言うと、「フリーソフトです。使用前使用後に対価を支払うことなく、自由に使 8 | えます。コピーしてもいいです。改変してもいいです。商業利用してもいいです。でもバ 9 | グなどで損害が出ても責任はとれません。」ってことです。 10 | 11 | 利用者や改変したり参考にしたりする人の利益のために、プログラム中で使っているア 12 | ルゴリズムで著作者が将来特許をとることがあっても、特許料を要求したりはしないとい 13 | う保証もあります。 14 | 15 | 1.目的 16 | 17 | このライセンスで提供されるソフトウェアは、少しでも多くの人に利益をもたらし、ソ 18 | フトウェア技術の進歩に少しでも貢献できればという目的で公開する。 19 | 20 | 2.趣旨 21 | 22 | このライセンスは、著作権を放棄するものではない(独占的にコピーする権利は放棄し 23 | ている)。利用者はこのソフトウェアの一部または全部を自由にコピーし、再配布するこ 24 | とができる。利用に際して対価を要求しない。解析、改変も対価なしに認める。 25 | 26 | このライセンスが適用されるソフトウェアの利用について、商業的な利用も無条件で認 27 | める。そのまま有償で販売しても構わない。 28 | 29 | このライセンスが適用されるソフトウェアの一部または全部を元にして作成されたソフ 30 | トウェア(以降、派生物と称する)に対し、どんなライセンスを付与してもよい。すなわ 31 | ち、派生物がコピー禁止であってもよいし、派生物が有償でしか配布されなくても構わな 32 | い。もちろん無償であってもよい。派生物に対する著作権は、派生物を生成した者に帰し 33 | 、このライセンスが適用されるソフトウェアの著作者が派生物に対して著作権を主張する 34 | ことはない。 35 | 36 | 派生物のドキュメント中に、元にしたソフトウェアの著作者を紹介する義務はない。こ 37 | の文は、もちろん、紹介することを禁止するものでもない。 38 | 39 | 派生物の公開に際して、元にしたソフトウェアの著作者に確認を取る義務はない。この 40 | 文は、もちろん、確認を禁止するものではない。 41 | 42 | 著作者は、ソフトウェアの質を保証しない。したがって、このソフトウェアで被害を被 43 | ったり、期待した結果が得られなくても、著作者は責任を負わない。 44 | 45 | このライセンスが適用されるソフトウェアで使われている技術については、事前に著作 46 | 者に許された者以外が特許を取得することは禁止する。新たな技術を加えた派生物を生成 47 | し、その追加された部分の特許をとることは認める。著作者がソフトウェア中の技術に対 48 | して後から特許をとることはありうるが、派生物やこのソフトウェアの利用に対して特許 49 | 料やその他の対価を求めることはないことを保証する。この保証は、特許取得前に生成さ 50 | れた派生物だけでなく、特許取得後に生成された派生物にも適用される。 51 | 52 | 解析結果をまとめて特許をとることには事前の著作者の許可が必要だか、特許をとるこ 53 | と以外については何ら制限はない。 54 | 55 | 3.補足 56 | 57 | 基本的に、コピーは大歓迎です。もし、著作者に何か恩を感じたら、一人でも多くの人 58 | にこのソフトウェアをすすめて、コピーしてあげて下さい。著作者は多くの人に使っても 59 | らいたいと思っているので、コピーすれば著作者は喜びます。それでも足りないと感じた 60 | ら、是非、感想を著作者に送ってあげて下さい。そうすれば、もっと喜ぶでしょう。 61 | 62 | これでライセンスされたソフトウェアの著作権情報だけを改変し、それを再配布するこ 63 | とはこのライセンスによって禁止されていません。派生物扱いです。これは抜け穴ではな 64 | いです。したがって、著作権情報だけを書き換えて再配布することが必要なら、していた 65 | だいてかまいません。 66 | 67 | バグを取ったり、機能を追加していただくのはもちろんですが、プログラムに註釈を付 68 | けて読みやすくしたり、ドキュメントを補足するなど、そういうバイナリーや実行結果に 69 | 反映されないような改変も大歓迎です。そういう派生物ができたら、連絡してもらえると 70 | うれしいです(義務ではありません)。 71 | 72 | 何か疑問点があったり、派生物を作成する上で情報が不足していると感じたら、著作者 73 | に連絡をとって質問することができます。ただ、著作者の都合ですぐには返事ができない 74 | かもしれません。それはご容赦ください。このライセンスそのものの不備などを指摘する 75 | 場合は、著作者か川合堂にご連絡ください。 76 | 77 | もしかすると、これでライセンスされたソフトウェアで利用されている技術について、 78 | 著作者の許可の無い者が特許を取得することを禁じていることが、日本の特許法に抵触し 79 | ているかもしれません(ご意見を待っています)。これについて、ライセンスを最初に提 80 | 唱した川合秀実の見解を以下に書いておきます。 81 | 82 | 特許法が制定された背景には、発明者が自分の発明による利益を守るために発明の詳細 83 | を公表しないことが科学技術の進歩を遅らせるから、公表してもらう代わりに一定期間の 84 | 独占利用を法的に保護する、という精神があります。このライセンスでは、発明の詳細を 85 | 意図的に隠すつもりはなく、したがって特許を取ることを禁止しても特許法の精神には反 86 | していないと考えています。むしろ、このライセンスの精神を汲まない者が特許を取得し 87 | オリジナルのソフトウェアや派生物に対して特許料を請求するかもしれない不安の方が、 88 | 科学技術の進歩を遅らせると考えます。したがって、その不安を事前に払拭したこのライ 89 | センスは特許法に適ったものだと考えています。 90 | 91 | もちろん、一番安心なのは、オリジナルのソフトウェアで発明と認められるすべてのも 92 | のについて著作者が特許を取得して、他者の特許取得を事前に妨げればいいのですが、そ 93 | れは著作者には負担になる場合があります。その負担とソフトウェアを公開するかどうか 94 | を天秤にかけなければいけないとしたら、公開をあきらめてしまう場合もあるかもしれま 95 | せん。それは特許法の精神の期待するものではありませんし、我々の目的(「1.目的」 96 | を参照)にも沿いません。 97 | 98 | また、発明の詳細が特許法の形式によって記述されていないために明らかでない場合、 99 | 著作者以外のものが許可なくそれを解析して明らかにすることは、このライセンスで認め 100 | られていています。それを無償で公開してもいいですし、有償で販売することもできます 101 | 。 102 | 103 | なお、これでライセンスされたソフトウェア中のすべての技術に対して、利用に際して 104 | 特許料を支払う心配が全く無いわけではありません。公開の時点で有効な特許による技術 105 | がソフトウェア内で使われていれば、それについては特許保持者からの特許料要求があり 106 | えます。このライセンスが特許料の心配無しと保証しているのは、このソフトウェア内で 107 | 新たに発明と認められる技術に対してのみです。 108 | 109 | このライセンスを自分のソフトウェアに適用したいと思う方がおられましたら、事前・ 110 | 事後に許可を求めることなく使っていただいてかまいません。もし不都合があれば、ライ 111 | センス文を改変して使っていただいてもいいです。改変の際には、混乱を防ぐためにライ 112 | センス名を変更するのを忘れないようにしてください。 113 | 114 | 4.リンク 115 | 116 | 川合秀実URL http://k.osask.jp/ 117 | e-mail kawai@osask.jp 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | このソフトウエアは坂井弘亮によって作成されたものであり,KL-01で配布します. 2 | KL-01については添付の KL-01 か,もしくは以下を参照してください. 3 | 4 | http://wiki.osask.jp/?KL-01 5 | 6 | 以上 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PREFIX = /usr/ 2 | ARCH = arm-none-eabi 3 | BINDIR = $(PREFIX)/bin 4 | ADDNAME = $(ARCH)- 5 | 6 | AR = $(BINDIR)/$(ADDNAME)ar 7 | AS = $(BINDIR)/$(ADDNAME)as 8 | CC = $(BINDIR)/$(ADDNAME)gcc 9 | LD = $(BINDIR)/$(ADDNAME)ld 10 | NM = $(BINDIR)/$(ADDNAME)nm 11 | OBJCOPY = $(BINDIR)/$(ADDNAME)objcopy 12 | OBJDUMP = $(BINDIR)/$(ADDNAME)objdump 13 | RANLIB = $(BINDIR)/$(ADDNAME)ranlib 14 | STRIP = $(BINDIR)/$(ADDNAME)strip 15 | 16 | OBJS = startup.o main.o interrupt.o vector.o interrupt_handler.o 17 | OBJS += lib.o serial.o 18 | 19 | # sources of kozos 20 | OBJS += kozos.o syscall.o memory.o consdrv.o command.o 21 | 22 | TARGET = kozos 23 | 24 | CFLAGS = -Wall -nostdinc -nostdlib -fno-builtin 25 | #CFLAGS += -mint32 # intを32ビットにすると掛算/割算ができなくなる 26 | CFLAGS += -I. 27 | CFLAGS += -g3 28 | CFLAGS += -Os 29 | CFLAGS += -march=armv6kz -mtune=arm1176jzf-s 30 | CFLAGS += -DKOZOS 31 | 32 | LFLAGS = -static -T ld.scr -L. 33 | 34 | .SUFFIXES: .c .o 35 | .SUFFIXES: .s .o 36 | .SUFFIXES: .S .o 37 | .SUFFIXES: .elf .bin 38 | 39 | all : $(TARGET).bin 40 | 41 | $(TARGET).elf : $(OBJS) 42 | $(CC) $(OBJS) -o $@ $(CFLAGS) $(LFLAGS) 43 | 44 | .elf.bin: 45 | $(OBJCOPY) -O binary $< $@ 46 | 47 | .c.o : $< 48 | $(CC) -c $(CFLAGS) $< 49 | 50 | .s.o : $< 51 | $(CC) -c $(CFLAGS) $< 52 | 53 | .S.o : $< 54 | $(CC) -c $(CFLAGS) $< 55 | 56 | clean : 57 | rm -f $(OBJS) $(TARGET) $(TARGET).elf 58 | -------------------------------------------------------------------------------- /command.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "consdrv.h" 4 | #include "lib.h" 5 | 6 | /* コンソール・ドライバの使用開始をコンソール・ドライバに依頼する */ 7 | static void send_use(int index) 8 | { 9 | char *p; 10 | p = kz_kmalloc(3); 11 | p[0] = '0'; 12 | p[1] = CONSDRV_CMD_USE; 13 | p[2] = '0' + index; 14 | kz_send(MSGBOX_ID_CONSOUTPUT, 3, p); 15 | } 16 | 17 | /* コンソールへの文字列出力をコンソール・ドライバに依頼する */ 18 | static void send_write(char *str) 19 | { 20 | char *p; 21 | int len; 22 | len = strlen(str); 23 | p = kz_kmalloc(len + 2); 24 | p[0] = '0'; 25 | p[1] = CONSDRV_CMD_WRITE; 26 | memcpy(&p[2], str, len); 27 | kz_send(MSGBOX_ID_CONSOUTPUT, len + 2, p); 28 | } 29 | 30 | int command_main(int argc, char *argv[]) 31 | { 32 | char *p; 33 | int size; 34 | 35 | send_use(SERIAL_DEFAULT_DEVICE); 36 | 37 | while (1) { 38 | send_write("command> "); /* プロンプト表示 */ 39 | 40 | /* コンソールからの受信文字列を受け取る */ 41 | kz_recv(MSGBOX_ID_CONSINPUT, &size, &p); 42 | p[size] = '\0'; 43 | 44 | if (!strncmp(p, "echo", 4)) { /* echoコマンド */ 45 | send_write(p + 4); /* echoに続く文字列を出力する */ 46 | send_write("\n"); 47 | } else { 48 | send_write("unknown.\n"); 49 | } 50 | 51 | kz_kmfree(p); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /consdrv.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "intr.h" 4 | #include "interrupt.h" 5 | #include "serial.h" 6 | #include "lib.h" 7 | #include "consdrv.h" 8 | 9 | #define CONS_BUFFER_SIZE 24 10 | 11 | static struct consreg { 12 | kz_thread_id_t id; /* コンソールを利用するスレッド */ 13 | int index; /* 利用するシリアルの番号 */ 14 | 15 | char *send_buf; /* 送信バッファ */ 16 | char *recv_buf; /* 受信バッファ */ 17 | int send_len; /* 送信バッファ中のデータサイズ */ 18 | int recv_len; /* 受信バッファ中のデータサイズ */ 19 | 20 | /* kozos.c の kz_msgbox と同様の理由で,ダミー・メンバでサイズ調整する */ 21 | long dummy[3]; 22 | } consreg[CONSDRV_DEVICE_NUM]; 23 | 24 | /* 25 | * 以下の2つの関数(send_char(), send_string())は割込み処理とスレッドから 26 | * 呼ばれるが送信バッファを操作しており再入不可のため,スレッドから呼び出す 27 | * 場合は排他のため割込み禁止状態で呼ぶこと. 28 | */ 29 | 30 | /* 送信バッファの先頭1文字を送信する */ 31 | static void send_char(struct consreg *cons) 32 | { 33 | int i; 34 | serial_send_byte(cons->index, cons->send_buf[0]); 35 | cons->send_len--; 36 | /* 先頭文字を送信したので,1文字ぶんずらす */ 37 | for (i = 0; i < cons->send_len; i++) 38 | cons->send_buf[i] = cons->send_buf[i + 1]; 39 | } 40 | 41 | /* 文字列を送信バッファに書き込み送信開始する */ 42 | static void send_string(struct consreg *cons, char *str, int len) 43 | { 44 | int i; 45 | for (i = 0; i < len; i++) { /* 文字列を送信バッファにコピー */ 46 | if (str[i] == '\n') /* \n→\r\nに変換 */ 47 | cons->send_buf[cons->send_len++] = '\r'; 48 | cons->send_buf[cons->send_len++] = str[i]; 49 | } 50 | /* 51 | * 送信割込み無効ならば,送信開始されていないので送信開始する. 52 | * 送信割込み有効ならば送信開始されており,送信割込みの延長で 53 | * 送信バッファ内のデータが順次送信されるので,何もしなくてよい. 54 | */ 55 | if (cons->send_len && !serial_intr_is_send_enable(cons->index)) { 56 | serial_intr_send_enable(cons->index); /* 送信割込み有効化 */ 57 | send_char(cons); /* 送信開始 */ 58 | } 59 | } 60 | 61 | /* 62 | * 以下は割込みハンドラから呼ばれる割込み処理であり,非同期で 63 | * 呼ばれるので,ライブラリ関数などを呼び出す場合には注意が必要. 64 | * 基本として,以下のいずれかに当てはまる関数しか呼び出してはいけない. 65 | * ・再入可能である. 66 | * ・スレッドから呼ばれることは無い関数である. 67 | * ・スレッドから呼ばれることがあるが,割込み禁止で呼び出している. 68 | * また非コンテキスト状態で呼ばれるため,システム・コールは利用してはいけない. 69 | * (サービス・コールを利用すること) 70 | */ 71 | static int consdrv_intrproc(struct consreg *cons) 72 | { 73 | unsigned char c; 74 | char *p; 75 | 76 | if (serial_is_recv_enable(cons->index)) { /* 受信割込み */ 77 | c = serial_recv_byte(cons->index); 78 | if (c == '\r') /* 改行コード変換(\r→\n) */ 79 | c = '\n'; 80 | 81 | send_string(cons, &c, 1); /* エコーバック処理 */ 82 | 83 | if (cons->id) { 84 | if (c != '\n') { 85 | /* 改行でないなら,受信バッファにバッファリングする */ 86 | cons->recv_buf[cons->recv_len++] = c; 87 | } else { 88 | /* 89 | * Enterが押されたら,バッファの内容を 90 | * コマンド処理スレッドに通知する. 91 | * (割込みハンドラなので,サービス・コールを利用する) 92 | */ 93 | p = kx_kmalloc(CONS_BUFFER_SIZE); 94 | memcpy(p, cons->recv_buf, cons->recv_len); 95 | kx_send(MSGBOX_ID_CONSINPUT, cons->recv_len, p); 96 | cons->recv_len = 0; 97 | } 98 | } 99 | } 100 | 101 | if (serial_is_send_enable(cons->index)) { /* 送信割込み */ 102 | if (!cons->id || !cons->send_len) { 103 | /* 送信データが無いならば,送信処理終了 */ 104 | serial_intr_send_disable(cons->index); 105 | } else { 106 | /* 送信データがあるならば,引続き送信する */ 107 | send_char(cons); 108 | } 109 | } 110 | 111 | return 0; 112 | } 113 | 114 | /* 割込みハンドラ */ 115 | static void consdrv_intr(void) 116 | { 117 | int i; 118 | struct consreg *cons; 119 | 120 | for (i = 0; i < CONSDRV_DEVICE_NUM; i++) { 121 | cons = &consreg[i]; 122 | if (cons->id) { 123 | if (serial_is_send_enable(cons->index) || 124 | serial_is_recv_enable(cons->index)) 125 | /* 割込みがあるならば,割込み処理を呼び出す */ 126 | consdrv_intrproc(cons); 127 | } 128 | } 129 | } 130 | 131 | static int consdrv_init(void) 132 | { 133 | memset(consreg, 0, sizeof(consreg)); 134 | return 0; 135 | } 136 | 137 | /* スレッドからの要求を処理する */ 138 | static int consdrv_command(struct consreg *cons, kz_thread_id_t id, 139 | int index, int size, char *command) 140 | { 141 | switch (command[0]) { 142 | case CONSDRV_CMD_USE: /* コンソール・ドライバの使用開始 */ 143 | cons->id = id; 144 | cons->index = command[1] - '0'; 145 | cons->send_buf = kz_kmalloc(CONS_BUFFER_SIZE); 146 | cons->recv_buf = kz_kmalloc(CONS_BUFFER_SIZE); 147 | cons->send_len = 0; 148 | cons->recv_len = 0; 149 | serial_init(cons->index); 150 | serial_intr_recv_enable(cons->index); /* 受信割込み有効化(受信開始) */ 151 | break; 152 | 153 | case CONSDRV_CMD_WRITE: /* コンソールへの文字列出力 */ 154 | /* 155 | * send_string()では送信バッファを操作しており再入不可なので, 156 | * 排他のために割込み禁止にして呼び出す. 157 | */ 158 | INTR_DISABLE; 159 | send_string(cons, command + 1, size - 1); /* 文字列の送信 */ 160 | INTR_ENABLE; 161 | break; 162 | 163 | default: 164 | break; 165 | } 166 | 167 | return 0; 168 | } 169 | 170 | int consdrv_main(int argc, char *argv[]) 171 | { 172 | int size, index; 173 | kz_thread_id_t id; 174 | char *p; 175 | 176 | consdrv_init(); 177 | kz_setintr(SOFTVEC_TYPE_SERINTR, consdrv_intr); /* 割込みハンドラ設定 */ 178 | 179 | while (1) { 180 | id = kz_recv(MSGBOX_ID_CONSOUTPUT, &size, &p); 181 | index = p[0] - '0'; 182 | consdrv_command(&consreg[index], id, index, size - 1, p + 1); 183 | kz_kmfree(p); 184 | } 185 | 186 | return 0; 187 | } 188 | -------------------------------------------------------------------------------- /consdrv.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONSDRV_H_INCLUDED_ 2 | #define _CONSDRV_H_INCLUDED_ 3 | 4 | #define CONSDRV_DEVICE_NUM 1 5 | #define CONSDRV_CMD_USE 'u' /* コンソール・ドライバの使用開始 */ 6 | #define CONSDRV_CMD_WRITE 'w' /* コンソールへの文字列出力 */ 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /defines.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEFINES_H_INCLUDED_ 2 | #define _DEFINES_H_INCLUDED_ 3 | 4 | #define NULL ((void *)0) 5 | #define SERIAL_DEFAULT_DEVICE 1 6 | 7 | typedef unsigned char uint8; 8 | typedef unsigned short uint16; 9 | typedef unsigned long uint32; 10 | 11 | typedef uint32 kz_thread_id_t; 12 | typedef int (*kz_func_t)(int argc, char *argv[]); 13 | typedef void (*kz_handler_t)(void); 14 | 15 | typedef enum { 16 | MSGBOX_ID_CONSINPUT = 0, 17 | MSGBOX_ID_CONSOUTPUT, 18 | MSGBOX_ID_NUM 19 | } kz_msgbox_id_t; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /interrupt.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "intr.h" 3 | #include "interrupt.h" 4 | 5 | /* ソフトウエア・割込みベクタの初期化 */ 6 | int softvec_init(void) 7 | { 8 | int type; 9 | for (type = 0; type < SOFTVEC_TYPE_NUM; type++) 10 | softvec_setintr(type, NULL); 11 | return 0; 12 | } 13 | 14 | /* ソフトウエア・割込みベクタの設定 */ 15 | int softvec_setintr(softvec_type_t type, softvec_handler_t handler) 16 | { 17 | SOFTVECS[type] = handler; 18 | return 0; 19 | } 20 | 21 | /* 22 | * 共通割込みハンドラ. 23 | * ソフトウエア・割込みベクタを見て,各ハンドラに分岐する. 24 | */ 25 | void interrupt(softvec_type_t type, unsigned long sp) 26 | { 27 | softvec_handler_t handler = SOFTVECS[type]; 28 | if (handler) 29 | handler(type, sp); 30 | } 31 | -------------------------------------------------------------------------------- /interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTERRUPT_H_INCLUDED_ 2 | #define _INTERRUPT_H_INCLUDED_ 3 | 4 | /* 以下はリンカ・スクリプトで定義してあるシンボル */ 5 | extern char _softvec; 6 | #define SOFTVEC_ADDR (&_softvec) 7 | 8 | typedef short softvec_type_t; 9 | 10 | typedef void (*softvec_handler_t)(softvec_type_t type, unsigned long sp); 11 | 12 | #define SOFTVECS ((softvec_handler_t *)SOFTVEC_ADDR) 13 | 14 | // #define INTR_ENABLE asm volatile ("andc.b #0x3f,ccr") 15 | // #define INTR_DISABLE asm volatile ("orc.b #0xc0,ccr") 16 | // TODO: ARM対応 17 | #define INTR_ENABLE asm volatile ("cpsie i") 18 | #define INTR_DISABLE asm volatile ("cpsid i") 19 | 20 | /* ソフトウエア・割込みベクタの初期化 */ 21 | int softvec_init(void); 22 | 23 | /* ソフトウエア・割込みベクタの設定 */ 24 | int softvec_setintr(softvec_type_t type, softvec_handler_t handler); 25 | 26 | /* 共通割込みハンドラ */ 27 | void interrupt(softvec_type_t type, unsigned long sp); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /interrupt_handler.S: -------------------------------------------------------------------------------- 1 | #include "intr.h" 2 | 3 | .global SVC_Handler_asm 4 | SVC_Handler_asm: 5 | @ r13-r14(sp,lr): banked 6 | @ goto system mode 7 | ldr sp, =_intrstack 8 | @ push r0-r3 to intrstack 9 | push {r0-r3} 10 | mov r0, sp 11 | mrs r1, spsr 12 | mov r3, lr 13 | @ enter system mode 14 | cps #0x1f 15 | @ backup 16 | mov r2, sp 17 | @ push return address to stack 18 | push {r3} 19 | @ push r4-r12 to system stack 20 | push {r4-r12} 21 | @ restore original r0-r3 to r4-r7 22 | ldmia r0, {r4-r7} 23 | @ push r0-r3 to system stack 24 | push {r4-r7} 25 | @ push spsr to stack 26 | push {r1} 27 | @ push system mode sp and lr 28 | push {r2, lr} 29 | @ set interrupt type to r0 30 | mov r0, #SOFTVEC_TYPE_SYSCALL 31 | @ set stack pointer to r1 32 | mov r1, sp 33 | @ interrupt(softvec_type_t type, unsigned long sp) 34 | b interrupt 35 | @ not return 36 | 37 | .global IRQ_Handler_asm 38 | IRQ_Handler_asm: 39 | @ r0-r12: not banked 40 | @ r13-r14(sp,lr): banked 41 | @ goto system mode 42 | ldr sp, =_intrstack 43 | @ push r0-r3 to intrstack 44 | push {r0-r3} 45 | mov r0, sp 46 | mrs r1, spsr 47 | sub r3, lr, #4 48 | @ enter system mode 49 | cps #0x1f 50 | @ backup 51 | mov r2, sp 52 | @ push return address to stack 53 | push {r3} 54 | @ push r4-r12 to system stack 55 | push {r4-r12} 56 | @ restore original r0-r3 to r4-r7 57 | ldmia r0, {r4-r7} 58 | @ push r0-r3 to system stack 59 | push {r4-r7} 60 | @ push spsr to stack 61 | push {r1} 62 | @ push system mode sp and lr 63 | push {r2, lr} 64 | @ set interrupt type to r0 65 | mov r0, #SOFTVEC_TYPE_SERINTR 66 | @ set stack pointer to r1 67 | mov r1, sp 68 | @ interrupt(softvec_type_t type, unsigned long sp) 69 | b interrupt 70 | @ not return 71 | 72 | 73 | @ void dispatch(kz_context *context); 74 | @ typedef struct _kz_context { 75 | @ uint32 sp; /* スタック・ポインタ */ 76 | @ } kz_context; 77 | .global dispatch 78 | dispatch: 79 | ldr r0, [r0] 80 | @ set system mode sp and lr 81 | ldmia r0!, {sp, lr} 82 | @ enter svc mode 83 | cps #0x13 84 | @ set user sp to svc sp 85 | mov sp, r0 86 | @ restore spsr 87 | pop {r0} 88 | msr spsr_cxsf, r0 89 | @ pop r0-r12 and restore CPSR and return 90 | pop {r0-r3} 91 | pop {r4-r12} 92 | ldmfd sp!, {pc}^ 93 | -------------------------------------------------------------------------------- /intr.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTR_H_INCLUDED_ 2 | #define _INTR_H_INCLUDED_ 3 | 4 | /* ソフトウエア・割込みベクタの定義 */ 5 | 6 | #define SOFTVEC_TYPE_NUM 3 7 | 8 | #define SOFTVEC_TYPE_SOFTERR 0 9 | #define SOFTVEC_TYPE_SYSCALL 1 10 | #define SOFTVEC_TYPE_SERINTR 2 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /kozos.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "intr.h" 4 | #include "interrupt.h" 5 | #include "syscall.h" 6 | #include "memory.h" 7 | #include "lib.h" 8 | 9 | #define THREAD_NUM 6 10 | #define PRIORITY_NUM 16 11 | #define THREAD_NAME_SIZE 15 12 | 13 | /* スレッド・コンテキスト */ 14 | typedef struct _kz_context { 15 | uint32 sp; /* スタック・ポインタ */ 16 | } kz_context; 17 | 18 | /* タスク・コントロール・ブロック(TCB) */ 19 | typedef struct _kz_thread { 20 | struct _kz_thread *next; 21 | char name[THREAD_NAME_SIZE + 1]; /* スレッド名 */ 22 | int priority; /* 優先度 */ 23 | uint32 *stack; /* スタック */ 24 | uint32 flags; /* 各種フラグ */ 25 | #define KZ_THREAD_FLAG_READY (1 << 0) 26 | 27 | struct { /* スレッドのスタート・アップ(thread_init())に渡すパラメータ */ 28 | kz_func_t func; /* スレッドのメイン関数 */ 29 | int argc; /* スレッドのメイン関数に渡す argc */ 30 | char **argv; /* スレッドのメイン関数に渡す argv */ 31 | } init; 32 | 33 | struct { /* システム・コール用バッファ */ 34 | kz_syscall_type_t type; 35 | kz_syscall_param_t *param; 36 | } syscall; 37 | 38 | kz_context context; /* コンテキスト情報 */ 39 | } kz_thread; 40 | 41 | /* メッセージ・バッファ */ 42 | typedef struct _kz_msgbuf { 43 | struct _kz_msgbuf *next; 44 | kz_thread *sender; /* メッセージを送信したスレッド */ 45 | struct { /* メッセージのパラメータ保存領域 char*/ 46 | int size; 47 | char *p; 48 | } param; 49 | } kz_msgbuf; 50 | 51 | /* メッセージ・ボックス */ 52 | typedef struct _kz_msgbox { 53 | kz_thread *receiver; /* 受信待ち状態のスレッド */ 54 | kz_msgbuf *head; 55 | kz_msgbuf *tail; 56 | 57 | /* 58 | * H8は16ビットCPUなので,32ビット整数に対しての乗算命令が無い.よって 59 | * 構造体のサイズが2の累乗になっていないと,構造体の配列のインデックス 60 | * 計算で乗算が使われて「___mulsi3が無い」などのリンク・エラーになる場合が 61 | * ある.(2の累乗ならばシフト演算が利用されるので問題は出ない) 62 | * 対策として,サイズが2の累乗になるようにダミー・メンバで調整する. 63 | * 他構造体で同様のエラーが出た場合には,同様の対処をすること. 64 | */ 65 | long dummy[1]; 66 | } kz_msgbox; 67 | 68 | /* スレッドのレディー・キュー */ 69 | static struct { 70 | kz_thread *head; 71 | kz_thread *tail; 72 | } readyque[PRIORITY_NUM]; 73 | 74 | static kz_thread *current; /* カレント・スレッド */ 75 | static kz_thread threads[THREAD_NUM]; /* タスク・コントロール・ブロック */ 76 | static kz_handler_t handlers[SOFTVEC_TYPE_NUM]; /* 割込みハンドラ */ 77 | static kz_msgbox msgboxes[MSGBOX_ID_NUM]; /* メッセージ・ボックス */ 78 | 79 | void dispatch(kz_context *context); 80 | static void thread_intr(softvec_type_t type, unsigned long sp); 81 | 82 | /* カレント・スレッドをレディー・キューから抜き出す */ 83 | static int getcurrent(void) 84 | { 85 | if (current == NULL) { 86 | return -1; 87 | } 88 | if (!(current->flags & KZ_THREAD_FLAG_READY)) { 89 | /* すでに無い場合は無視 */ 90 | return 1; 91 | } 92 | 93 | /* カレント・スレッドは必ず先頭にあるはずなので,先頭から抜き出す */ 94 | readyque[current->priority].head = current->next; 95 | if (readyque[current->priority].head == NULL) { 96 | readyque[current->priority].tail = NULL; 97 | } 98 | current->flags &= ~KZ_THREAD_FLAG_READY; 99 | current->next = NULL; 100 | 101 | return 0; 102 | } 103 | 104 | /* カレント・スレッドをレディー・キューに繋げる */ 105 | static int putcurrent(void) 106 | { 107 | if (current == NULL) { 108 | return -1; 109 | } 110 | if (current->flags & KZ_THREAD_FLAG_READY) { 111 | /* すでに有る場合は無視 */ 112 | return 1; 113 | } 114 | 115 | /* レディー・キューの末尾に接続する */ 116 | if (readyque[current->priority].tail) { 117 | readyque[current->priority].tail->next = current; 118 | } else { 119 | readyque[current->priority].head = current; 120 | } 121 | readyque[current->priority].tail = current; 122 | current->flags |= KZ_THREAD_FLAG_READY; 123 | 124 | return 0; 125 | } 126 | 127 | static void thread_end(void) 128 | { 129 | kz_exit(); 130 | } 131 | 132 | /* スレッドのスタート・アップ */ 133 | static void thread_init(kz_thread *thp) 134 | { 135 | /* スレッドのメイン関数を呼び出す */ 136 | thp->init.func(thp->init.argc, thp->init.argv); 137 | thread_end(); 138 | } 139 | 140 | static int thread_exit(void); 141 | 142 | /* システム・コールの処理(kz_run():スレッドの起動) */ 143 | static kz_thread_id_t thread_run(kz_func_t func, char *name, int priority, 144 | int stacksize, int argc, char *argv[]) 145 | { 146 | int i; 147 | kz_thread *thp; 148 | uint32 *sp; 149 | extern char _userstack; /* リンカ・スクリプトで定義されるスタック領域 */ 150 | static char *thread_stack = &_userstack; 151 | 152 | /* 空いているタスク・コントロール・ブロックを検索 */ 153 | for (i = 0; i < THREAD_NUM; i++) { 154 | thp = &threads[i]; 155 | if (!thp->init.func) /* 見つかった */ 156 | break; 157 | } 158 | if (i == THREAD_NUM) /* 見つからなかった */ 159 | return -1; 160 | 161 | memset(thp, 0, sizeof(*thp)); 162 | 163 | /* タスク・コントロール・ブロック(TCB)の設定 */ 164 | strcpy(thp->name, name); 165 | thp->next = NULL; 166 | thp->priority = priority; 167 | thp->flags = 0; 168 | 169 | thp->init.func = func; 170 | thp->init.argc = argc; 171 | thp->init.argv = argv; 172 | 173 | /* スタック領域を獲得 */ 174 | memset(thread_stack, 0, stacksize); 175 | thread_stack += stacksize; 176 | 177 | thp->stack = thread_stack; /* スタックを設定 */ 178 | 179 | 180 | // ARM版のスレッドコンテキスト 181 | // TODO: lkの実装を参考にいい感じにする 182 | typedef struct { 183 | volatile uint32 sp; 184 | volatile uint32 lr; 185 | volatile uint32 spsr; 186 | volatile uint32 r[13]; 187 | volatile uint32 pc; 188 | } kz_arm_context; 189 | /* スタックの初期化 */ 190 | // TODO: RasPi対応スタック形式にする 191 | // sp = (uint32 *)thp->stack; 192 | // *(--sp) = (uint32)thread_end; 193 | kz_arm_context *thc = (kz_arm_context *)((thp->stack - sizeof(kz_arm_context))); 194 | 195 | thc->lr = (volatile uint32)thread_end; 196 | thc->sp = thp->stack; 197 | thc->spsr = 0x0000001f; 198 | 199 | for (int i = 0; i < 13; i++) { 200 | thc->r[i] = 0; 201 | } 202 | 203 | /* 204 | * プログラム・カウンタを設定する. 205 | * スレッドの優先度がゼロの場合には,割込み禁止スレッドとする. 206 | */ 207 | thc->pc = (volatile uint32)thread_init; 208 | 209 | /* スレッドのスタート・アップ(thread_init())に渡す引数 */ 210 | thc->r[0] = (volatile uint32)thp; 211 | 212 | /* スレッドのコンテキストを設定 */ 213 | thp->context.sp = (uint32)thc; 214 | 215 | /* システム・コールを呼び出したスレッドをレディー・キューに戻す */ 216 | putcurrent(); 217 | 218 | /* 新規作成したスレッドを,レディー・キューに接続する */ 219 | current = thp; 220 | putcurrent(); 221 | 222 | return (kz_thread_id_t)current; 223 | } 224 | 225 | /* システム・コールの処理(kz_exit():スレッドの終了) */ 226 | static int thread_exit(void) 227 | { 228 | /* 229 | * 本来ならスタックも解放して再利用できるようにすべきだが省略. 230 | * このため,スレッドを頻繁に生成・消去するようなことは現状でできない. 231 | */ 232 | puts(current->name); 233 | puts(" EXIT.\n"); 234 | memset(current, 0, sizeof(*current)); 235 | return 0; 236 | } 237 | 238 | /* システム・コールの処理(kz_wait():スレッドの実行権放棄) */ 239 | static int thread_wait(void) 240 | { 241 | putcurrent(); 242 | return 0; 243 | } 244 | 245 | /* システム・コールの処理(kz_sleep():スレッドのスリープ) */ 246 | static int thread_sleep(void) 247 | { 248 | return 0; 249 | } 250 | 251 | /* システム・コールの処理(kz_wakeup():スレッドのウェイク・アップ) */ 252 | static int thread_wakeup(kz_thread_id_t id) 253 | { 254 | /* ウェイク・アップを呼び出したスレッドをレディー・キューに戻す */ 255 | putcurrent(); 256 | 257 | /* 指定されたスレッドをレディー・キューに接続してウェイク・アップする */ 258 | current = (kz_thread *)id; 259 | putcurrent(); 260 | 261 | return 0; 262 | } 263 | 264 | /* システム・コールの処理(kz_getid():スレッドID取得) */ 265 | static kz_thread_id_t thread_getid(void) 266 | { 267 | putcurrent(); 268 | return (kz_thread_id_t)current; 269 | } 270 | 271 | /* システム・コールの処理(kz_chpri():スレッドの優先度変更) */ 272 | static int thread_chpri(int priority) 273 | { 274 | int old = current->priority; 275 | if (priority >= 0) 276 | current->priority = priority; /* 優先度変更 */ 277 | putcurrent(); /* 新しい優先度のレディー・キューに繋ぎ直す */ 278 | return old; 279 | } 280 | 281 | /* システム・コールの処理(kz_kmalloc():動的メモリ獲得) */ 282 | static void *thread_kmalloc(int size) 283 | { 284 | putcurrent(); 285 | return kzmem_alloc(size); 286 | } 287 | 288 | /* システム・コールの処理(kz_kfree():メモリ解放) */ 289 | static int thread_kmfree(char *p) 290 | { 291 | kzmem_free(p); 292 | putcurrent(); 293 | return 0; 294 | } 295 | 296 | /* メッセージの送信処理 */ 297 | static void sendmsg(kz_msgbox *mboxp, kz_thread *thp, int size, char *p) 298 | { 299 | kz_msgbuf *mp; 300 | 301 | /* メッセージ・バッファの作成 */ 302 | mp = (kz_msgbuf *)kzmem_alloc(sizeof(*mp)); 303 | if (mp == NULL) 304 | kz_sysdown(); 305 | mp->next = NULL; 306 | mp->sender = thp; 307 | mp->param.size = size; 308 | mp->param.p = p; 309 | 310 | /* メッセージ・ボックスの末尾にメッセージを接続する */ 311 | if (mboxp->tail) { 312 | mboxp->tail->next = mp; 313 | } else { 314 | mboxp->head = mp; 315 | } 316 | mboxp->tail = mp; 317 | } 318 | 319 | /* メッセージの受信処理 */ 320 | static void recvmsg(kz_msgbox *mboxp) 321 | { 322 | kz_msgbuf *mp; 323 | kz_syscall_param_t *p; 324 | 325 | /* メッセージ・ボックスの先頭にあるメッセージを抜き出す */ 326 | mp = mboxp->head; 327 | mboxp->head = mp->next; 328 | if (mboxp->head == NULL) 329 | mboxp->tail = NULL; 330 | mp->next = NULL; 331 | 332 | /* メッセージを受信するスレッドに返す値を設定する */ 333 | p = mboxp->receiver->syscall.param; 334 | p->un.recv.ret = (kz_thread_id_t)mp->sender; 335 | if (p->un.recv.sizep) 336 | *(p->un.recv.sizep) = mp->param.size; 337 | if (p->un.recv.pp) 338 | *(p->un.recv.pp) = mp->param.p; 339 | 340 | /* 受信待ちスレッドはいなくなったので,NULLに戻す */ 341 | mboxp->receiver = NULL; 342 | 343 | /* メッセージ・バッファの解放 */ 344 | kzmem_free(mp); 345 | } 346 | 347 | /* システム・コールの処理(kz_send():メッセージ送信) */ 348 | static int thread_send(kz_msgbox_id_t id, int size, char *p) 349 | { 350 | kz_msgbox *mboxp = &msgboxes[id]; 351 | 352 | putcurrent(); 353 | sendmsg(mboxp, current, size, p); /* メッセージの送信処理 */ 354 | 355 | /* 受信待ちスレッドが存在している場合には受信処理を行う */ 356 | if (mboxp->receiver) { 357 | current = mboxp->receiver; /* 受信待ちスレッド */ 358 | recvmsg(mboxp); /* メッセージの受信処理 */ 359 | putcurrent(); /* 受信により動作可能になったので,ブロック解除する */ 360 | } 361 | 362 | return size; 363 | } 364 | 365 | /* システム・コールの処理(kz_recv():メッセージ受信) */ 366 | static kz_thread_id_t thread_recv(kz_msgbox_id_t id, int *sizep, char **pp) 367 | { 368 | kz_msgbox *mboxp = &msgboxes[id]; 369 | 370 | if (mboxp->receiver) /* 他のスレッドがすでに受信待ちしている */ 371 | kz_sysdown(); 372 | 373 | mboxp->receiver = current; /* 受信待ちスレッドに設定 */ 374 | 375 | if (mboxp->head == NULL) { 376 | /* 377 | * メッセージ・ボックスにメッセージが無いので,スレッドを 378 | * スリープさせる.(システム・コールがブロックする) 379 | */ 380 | return -1; 381 | } 382 | 383 | recvmsg(mboxp); /* メッセージの受信処理 */ 384 | putcurrent(); /* メッセージを受信できたので,レディー状態にする */ 385 | 386 | return current->syscall.param->un.recv.ret; 387 | } 388 | 389 | /* システム・コールの処理(kz_setintr():割込みハンドラ登録) */ 390 | static int thread_setintr(softvec_type_t type, kz_handler_t handler) 391 | { 392 | /* 393 | * 割込みを受け付けるために,ソフトウエア・割込みベクタに 394 | * OSの割込み処理の入口となる関数を登録する. 395 | */ 396 | softvec_setintr(type, thread_intr); 397 | 398 | handlers[type] = handler; /* OS側から呼び出す割込みハンドラを登録 */ 399 | putcurrent(); 400 | 401 | return 0; 402 | } 403 | 404 | static void call_functions(kz_syscall_type_t type, kz_syscall_param_t *p) 405 | { 406 | /* システム・コールの実行中にcurrentが書き換わるので注意 */ 407 | switch (type) { 408 | case KZ_SYSCALL_TYPE_RUN: /* kz_run() */ 409 | p->un.run.ret = thread_run(p->un.run.func, p->un.run.name, 410 | p->un.run.priority, p->un.run.stacksize, 411 | p->un.run.argc, p->un.run.argv); 412 | break; 413 | case KZ_SYSCALL_TYPE_EXIT: /* kz_exit() */ 414 | /* TCBが消去されるので,戻り値を書き込んではいけない */ 415 | thread_exit(); 416 | break; 417 | case KZ_SYSCALL_TYPE_WAIT: /* kz_wait() */ 418 | p->un.wait.ret = thread_wait(); 419 | break; 420 | case KZ_SYSCALL_TYPE_SLEEP: /* kz_sleep() */ 421 | p->un.sleep.ret = thread_sleep(); 422 | break; 423 | case KZ_SYSCALL_TYPE_WAKEUP: /* kz_wakeup() */ 424 | p->un.wakeup.ret = thread_wakeup(p->un.wakeup.id); 425 | break; 426 | case KZ_SYSCALL_TYPE_GETID: /* kz_getid() */ 427 | p->un.getid.ret = thread_getid(); 428 | break; 429 | case KZ_SYSCALL_TYPE_CHPRI: /* kz_chpri() */ 430 | p->un.chpri.ret = thread_chpri(p->un.chpri.priority); 431 | break; 432 | case KZ_SYSCALL_TYPE_KMALLOC: /* kz_kmalloc() */ 433 | p->un.kmalloc.ret = thread_kmalloc(p->un.kmalloc.size); 434 | break; 435 | case KZ_SYSCALL_TYPE_KMFREE: /* kz_kmfree() */ 436 | p->un.kmfree.ret = thread_kmfree(p->un.kmfree.p); 437 | break; 438 | case KZ_SYSCALL_TYPE_SEND: /* kz_send() */ 439 | p->un.send.ret = thread_send(p->un.send.id, 440 | p->un.send.size, p->un.send.p); 441 | break; 442 | case KZ_SYSCALL_TYPE_RECV: /* kz_recv() */ 443 | p->un.recv.ret = thread_recv(p->un.recv.id, 444 | p->un.recv.sizep, p->un.recv.pp); 445 | break; 446 | case KZ_SYSCALL_TYPE_SETINTR: /* kz_setintr() */ 447 | p->un.setintr.ret = thread_setintr(p->un.setintr.type, 448 | p->un.setintr.handler); 449 | break; 450 | default: 451 | break; 452 | } 453 | } 454 | 455 | /* システム・コールの処理 */ 456 | static void syscall_proc(kz_syscall_type_t type, kz_syscall_param_t *p) 457 | { 458 | /* 459 | * システム・コールを呼び出したスレッドをレディー・キューから 460 | * 外した状態で処理関数を呼び出す.このためシステム・コールを 461 | * 呼び出したスレッドをそのまま動作継続させたい場合には, 462 | * 処理関数の内部で putcurrent() を行う必要がある. 463 | */ 464 | getcurrent(); 465 | call_functions(type, p); 466 | } 467 | 468 | /* サービス・コールの処理 */ 469 | static void srvcall_proc(kz_syscall_type_t type, kz_syscall_param_t *p) 470 | { 471 | /* 472 | * システム・コールとサービス・コールの処理関数の内部で, 473 | * システム・コールの実行したスレッドIDを得るために current を 474 | * 参照している部分があり(たとえば thread_send() など), 475 | * current が残っていると誤動作するため NULL に設定する. 476 | * サービス・コールは thread_intrvec() 内部の割込みハンドラ呼び出しの 477 | * 延長で呼ばれているはずでなので,呼び出し後に thread_intrvec() で 478 | * スケジューリング処理が行われ,current は再設定される. 479 | */ 480 | current = NULL; 481 | call_functions(type, p); 482 | } 483 | 484 | /* スレッドのスケジューリング */ 485 | static void schedule(void) 486 | { 487 | int i; 488 | 489 | /* 490 | * 優先順位の高い順(優先度の数値の小さい順)にレディー・キューを見て, 491 | * 動作可能なスレッドを検索する. 492 | */ 493 | for (i = 0; i < PRIORITY_NUM; i++) { 494 | if (readyque[i].head) /* 見つかった */ 495 | break; 496 | } 497 | if (i == PRIORITY_NUM) /* 見つからなかった */ 498 | kz_sysdown(); 499 | 500 | current = readyque[i].head; /* カレント・スレッドに設定する */ 501 | } 502 | 503 | static void syscall_intr(void) 504 | { 505 | syscall_proc(current->syscall.type, current->syscall.param); 506 | } 507 | 508 | static void softerr_intr(void) 509 | { 510 | puts(current->name); 511 | puts(" DOWN.\n"); 512 | getcurrent(); /* レディーキューから外す */ 513 | thread_exit(); /* スレッド終了する */ 514 | } 515 | 516 | /* 割込み処理の入口関数 */ 517 | static void thread_intr(softvec_type_t type, unsigned long sp) 518 | { 519 | /* カレント・スレッドのコンテキストを保存する */ 520 | current->context.sp = sp; 521 | 522 | /* 523 | * 割込みごとの処理を実行する. 524 | * SOFTVEC_TYPE_SYSCALL, SOFTVEC_TYPE_SOFTERR の場合は 525 | * syscall_intr(), softerr_intr() がハンドラに登録されているので, 526 | * それらが実行される. 527 | * それ以外の場合は,kz_setintr()によってユーザ登録されたハンドラが 528 | * 実行される. 529 | */ 530 | if (handlers[type]) 531 | handlers[type](); 532 | 533 | schedule(); /* スレッドのスケジューリング */ 534 | 535 | /* 536 | * スレッドのディスパッチ 537 | * (dispatch()関数の本体はstartup.sにあり,アセンブラで記述されている) 538 | */ 539 | dispatch(¤t->context); 540 | /* ここには返ってこない */ 541 | } 542 | 543 | void kz_start(kz_func_t func, char *name, int priority, int stacksize, 544 | int argc, char *argv[]) 545 | { 546 | kzmem_init(); /* 動的メモリの初期化 */ 547 | 548 | /* 549 | * 以降で呼び出すスレッド関連のライブラリ関数の内部で current を 550 | * 見ている場合があるので,current を NULL に初期化しておく. 551 | */ 552 | current = NULL; 553 | 554 | memset(readyque, 0, sizeof(readyque)); 555 | memset(threads, 0, sizeof(threads)); 556 | memset(handlers, 0, sizeof(handlers)); 557 | memset(msgboxes, 0, sizeof(msgboxes)); 558 | 559 | /* 割込みハンドラの登録 */ 560 | thread_setintr(SOFTVEC_TYPE_SYSCALL, syscall_intr); /* システム・コール */ 561 | thread_setintr(SOFTVEC_TYPE_SOFTERR, softerr_intr); /* ダウン要因発生 */ 562 | 563 | /* システム・コール発行不可なので直接関数を呼び出してスレッド作成する */ 564 | current = (kz_thread *)thread_run(func, name, priority, stacksize, 565 | argc, argv); 566 | 567 | /* 最初のスレッドを起動 */ 568 | dispatch(¤t->context); 569 | 570 | /* ここには返ってこない */ 571 | } 572 | 573 | void kz_sysdown(void) 574 | { 575 | puts("system error!\n"); 576 | while (1) 577 | ; 578 | } 579 | 580 | /* システム・コール呼び出し用ライブラリ関数 */ 581 | void kz_syscall(kz_syscall_type_t type, kz_syscall_param_t *param) 582 | { 583 | current->syscall.type = type; 584 | current->syscall.param = param; 585 | // asm volatile ("trapa #0"); /* トラップ割込み発行 */ 586 | // TODO: ARM対応 587 | asm volatile ("svc #0"); /* トラップ割込み発行 */ 588 | } 589 | 590 | /* サービス・コール呼び出し用ライブラリ関数 */ 591 | void kz_srvcall(kz_syscall_type_t type, kz_syscall_param_t *param) 592 | { 593 | srvcall_proc(type, param); 594 | } 595 | -------------------------------------------------------------------------------- /kozos.h: -------------------------------------------------------------------------------- 1 | #ifndef _KOZOS_H_INCLUDED_ 2 | #define _KOZOS_H_INCLUDED_ 3 | 4 | #include "defines.h" 5 | #include "interrupt.h" 6 | #include "syscall.h" 7 | 8 | /* システム・コール */ 9 | kz_thread_id_t kz_run(kz_func_t func, char *name, int priority, int stacksize, 10 | int argc, char *argv[]); 11 | void kz_exit(void); 12 | int kz_wait(void); 13 | int kz_sleep(void); 14 | int kz_wakeup(kz_thread_id_t id); 15 | kz_thread_id_t kz_getid(void); 16 | int kz_chpri(int priority); 17 | void *kz_kmalloc(int size); 18 | int kz_kmfree(void *p); 19 | int kz_send(kz_msgbox_id_t id, int size, char *p); 20 | kz_thread_id_t kz_recv(kz_msgbox_id_t id, int *sizep, char **pp); 21 | int kz_setintr(softvec_type_t type, kz_handler_t handler); 22 | 23 | /* サービス・コール */ 24 | int kx_wakeup(kz_thread_id_t id); 25 | void *kx_kmalloc(int size); 26 | int kx_kmfree(void *p); 27 | int kx_send(kz_msgbox_id_t id, int size, char *p); 28 | 29 | /* ライブラリ関数 */ 30 | void kz_start(kz_func_t func, char *name, int priority, int stacksize, 31 | int argc, char *argv[]); 32 | void kz_sysdown(void); 33 | void kz_syscall(kz_syscall_type_t type, kz_syscall_param_t *param); 34 | void kz_srvcall(kz_syscall_type_t type, kz_syscall_param_t *param); 35 | 36 | /* システム・タスク */ 37 | int consdrv_main(int argc, char *argv[]); 38 | 39 | /* ユーザ・タスク */ 40 | int command_main(int argc, char *argv[]); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /ld.scr: -------------------------------------------------------------------------------- 1 | OUTPUT_ARCH(arm) 2 | ENTRY("_start") 3 | 4 | MEMORY 5 | { 6 | /* o: ORIGIN, l:LENGTH */ 7 | ramall(rwx) : o = 0x00000000, l = 0x1c000000 /* 512-64MB */ 8 | ram(rwx) : o = 0x00008000, l = 0x1bff8000 /* entry point(0x8000) - end(0x1c000000) */ 9 | 10 | softvec(rw) : o = 0x1a000000, l = 0x00000040 /* top of RAM */ 11 | userstack(rw) : o = 0x1b000000, l = 0x00000000 /* fiq - 16MB */ 12 | bootstack(rw) : o = 0x1c000000, l = 0x00000000 /* svc - 16MB */ 13 | intrstack(rw) : o = 0x1c000000, l = 0x00000000 /* end of RAM */ 14 | } 15 | 16 | SECTIONS 17 | { 18 | .text : { 19 | _text_start = . ; 20 | *(.text) 21 | _etext = . ; 22 | } > ram 23 | 24 | . = ALIGN(4); 25 | 26 | .rodata : { 27 | _rodata_start = . ; 28 | *(.strings) 29 | *(.rodata) 30 | *(.rodata.*) 31 | _erodata = . ; 32 | } > ram 33 | 34 | . = ALIGN(4); 35 | 36 | .data : { 37 | _data_start = . ; 38 | *(.data) 39 | _edata = . ; 40 | } > ram 41 | 42 | . = ALIGN(4); 43 | 44 | .bss : { 45 | _bss_start = . ; 46 | *(.bss) 47 | *(COMMON) 48 | _ebss = . ; 49 | } > ram 50 | 51 | . = ALIGN(4); 52 | _end = . ; 53 | 54 | .freearea : { 55 | _freearea = .; 56 | } > ram 57 | 58 | . = ALIGN(4); 59 | 60 | .softvec : { 61 | _softvec = .; 62 | } > softvec 63 | 64 | . = ALIGN(4); 65 | 66 | .userstack : { 67 | _userstack = .; 68 | } > userstack 69 | 70 | . = ALIGN(4); 71 | 72 | .bootstack : { 73 | _bootstack = .; 74 | } > bootstack 75 | 76 | . = ALIGN(4); 77 | 78 | .intrstack : { 79 | _intrstack = .; 80 | } > intrstack 81 | 82 | . = ALIGN(4); 83 | } 84 | -------------------------------------------------------------------------------- /lib.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "serial.h" 3 | #include "lib.h" 4 | 5 | void *memset(void *b, int c, long len) 6 | { 7 | char *p; 8 | for (p = b; len > 0; len--) 9 | *(p++) = c; 10 | return b; 11 | } 12 | 13 | void *memcpy(void *dst, const void *src, long len) 14 | { 15 | char *d = dst; 16 | const char *s = src; 17 | for (; len > 0; len--) 18 | *(d++) = *(s++); 19 | return dst; 20 | } 21 | 22 | int memcmp(const void *b1, const void *b2, long len) 23 | { 24 | const char *p1 = b1, *p2 = b2; 25 | for (; len > 0; len--) { 26 | if (*p1 != *p2) 27 | return (*p1 > *p2) ? 1 : -1; 28 | p1++; 29 | p2++; 30 | } 31 | return 0; 32 | } 33 | 34 | int strlen(const char *s) 35 | { 36 | int len; 37 | for (len = 0; *s; s++, len++) 38 | ; 39 | return len; 40 | } 41 | 42 | char *strcpy(char *dst, const char *src) 43 | { 44 | char *d = dst; 45 | for (;; dst++, src++) { 46 | *dst = *src; 47 | if (!*src) break; 48 | } 49 | return d; 50 | } 51 | 52 | int strcmp(const char *s1, const char *s2) 53 | { 54 | while (*s1 || *s2) { 55 | if (*s1 != *s2) 56 | return (*s1 > *s2) ? 1 : -1; 57 | s1++; 58 | s2++; 59 | } 60 | return 0; 61 | } 62 | 63 | int strncmp(const char *s1, const char *s2, int len) 64 | { 65 | while ((*s1 || *s2) && (len > 0)) { 66 | if (*s1 != *s2) 67 | return (*s1 > *s2) ? 1 : -1; 68 | s1++; 69 | s2++; 70 | len--; 71 | } 72 | return 0; 73 | } 74 | 75 | /* 1文字送信 */ 76 | int putc(unsigned char c) 77 | { 78 | if (c == '\n') 79 | serial_send_byte(SERIAL_DEFAULT_DEVICE, '\r'); 80 | return serial_send_byte(SERIAL_DEFAULT_DEVICE, c); 81 | } 82 | 83 | /* 1文字受信 */ 84 | unsigned char getc(void) 85 | { 86 | unsigned char c = serial_recv_byte(SERIAL_DEFAULT_DEVICE); 87 | c = (c == '\r') ? '\n' : c; 88 | putc(c); /* エコー・バック */ 89 | return c; 90 | } 91 | 92 | /* 文字列送信 */ 93 | int puts(unsigned char *str) 94 | { 95 | while (*str) 96 | putc(*(str++)); 97 | return 0; 98 | } 99 | 100 | /* 文字列受信 */ 101 | int gets(unsigned char *buf) 102 | { 103 | int i = 0; 104 | unsigned char c; 105 | do { 106 | c = getc(); 107 | if (c == '\n') 108 | c = '\0'; 109 | buf[i++] = c; 110 | } while (c); 111 | return i - 1; 112 | } 113 | 114 | /* 数値の16進表示 */ 115 | int putxval(unsigned long value, int column) 116 | { 117 | char buf[9]; 118 | char *p; 119 | 120 | p = buf + sizeof(buf) - 1; 121 | *(p--) = '\0'; 122 | 123 | if (!value && !column) 124 | column++; 125 | 126 | while (value || column) { 127 | *(p--) = "0123456789abcdef"[value & 0xf]; 128 | value >>= 4; 129 | if (column) column--; 130 | } 131 | 132 | puts(p + 1); 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /lib.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIB_H_INCLUDED_ 2 | #define _LIB_H_INCLUDED_ 3 | 4 | void *memset(void *b, int c, long len); 5 | void *memcpy(void *dst, const void *src, long len); 6 | int memcmp(const void *b1, const void *b2, long len); 7 | int strlen(const char *s); 8 | char *strcpy(char *dst, const char *src); 9 | int strcmp(const char *s1, const char *s2); 10 | int strncmp(const char *s1, const char *s2, int len); 11 | 12 | int putc(unsigned char c); /* 1文字送信 */ 13 | unsigned char getc(void); /* 1文字受信 */ 14 | int puts(unsigned char *str); /* 文字列送信 */ 15 | int gets(unsigned char *buf); /* 文字列受信 */ 16 | int putxval(unsigned long value, int column); /* 数値の16進表示 */ 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "interrupt.h" 4 | #include "lib.h" 5 | 6 | /* システム・タスクとユーザ・タスクの起動 */ 7 | static int start_threads(int argc, char *argv[]) 8 | { 9 | kz_run(consdrv_main, "consdrv", 1, 0x200, 0, NULL); 10 | kz_run(command_main, "command", 8, 0x200, 0, NULL); 11 | 12 | kz_chpri(15); /* 優先順位を下げて,アイドルスレッドに移行する */ 13 | INTR_ENABLE; /* 割込み有効にする */ 14 | while (1) { 15 | asm volatile ("wfi"); /* 省電力モードに移行 */ 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | int main(void) 22 | { 23 | INTR_DISABLE; /* 割込み無効にする */ 24 | 25 | puts("kozos boot succeed!\n"); 26 | 27 | /* OSの動作開始 */ 28 | kz_start(start_threads, "idle", 0, 0x100, 0, NULL); 29 | /* ここには戻ってこない */ 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "lib.h" 4 | #include "memory.h" 5 | 6 | /* 7 | * メモリ・ブロック構造体 8 | * (獲得された各領域は,先頭に以下の構造体を持っている) 9 | */ 10 | typedef struct _kzmem_block { 11 | struct _kzmem_block *next; 12 | int size; 13 | } kzmem_block; 14 | 15 | /* メモリ・プール */ 16 | typedef struct _kzmem_pool { 17 | int size; 18 | int num; 19 | kzmem_block *free; 20 | } kzmem_pool; 21 | 22 | /* メモリ・プールの定義(個々のサイズと個数) */ 23 | static kzmem_pool pool[] = { 24 | { 16, 8, NULL }, { 32, 8, NULL }, { 64, 4, NULL }, 25 | }; 26 | 27 | #define MEMORY_AREA_NUM (sizeof(pool) / sizeof(*pool)) 28 | 29 | /* メモリ・プールの初期化 */ 30 | static int kzmem_init_pool(kzmem_pool *p) 31 | { 32 | int i; 33 | kzmem_block *mp; 34 | kzmem_block **mpp; 35 | extern char _freearea; /* リンカ・スクリプトで定義される空き領域 */ 36 | static char *area = &_freearea; 37 | 38 | mp = (kzmem_block *)area; 39 | 40 | /* 個々の領域をすべて解放済みリンクリストに繋ぐ */ 41 | mpp = &p->free; 42 | for (i = 0; i < p->num; i++) { 43 | *mpp = mp; 44 | memset(mp, 0, sizeof(*mp)); 45 | mp->size = p->size; 46 | mpp = &(mp->next); 47 | mp = (kzmem_block *)((char *)mp + p->size); 48 | area += p->size; 49 | } 50 | 51 | return 0; 52 | } 53 | 54 | /* 動的メモリの初期化 */ 55 | int kzmem_init(void) 56 | { 57 | int i; 58 | for (i = 0; i < MEMORY_AREA_NUM; i++) { 59 | kzmem_init_pool(&pool[i]); /* 各メモリ・プールを初期化する */ 60 | } 61 | return 0; 62 | } 63 | 64 | /* 動的メモリの獲得 */ 65 | void *kzmem_alloc(int size) 66 | { 67 | int i; 68 | kzmem_block *mp; 69 | kzmem_pool *p; 70 | 71 | for (i = 0; i < MEMORY_AREA_NUM; i++) { 72 | p = &pool[i]; 73 | if (size <= p->size - sizeof(kzmem_block)) { 74 | if (p->free == NULL) { /* 解放済み領域が無い(メモリ・ブロック不足) */ 75 | kz_sysdown(); 76 | return NULL; 77 | } 78 | /* 解放済みリンクリストから領域を取得する */ 79 | mp = p->free; 80 | p->free = p->free->next; 81 | mp->next = NULL; 82 | 83 | /* 84 | * 実際に利用可能な領域は,メモリ・ブロック構造体の直後の領域に 85 | * なるので,直後のアドレスを返す. 86 | */ 87 | return mp + 1; 88 | } 89 | } 90 | 91 | /* 指定されたサイズの領域を格納できるメモリ・プールが無い */ 92 | kz_sysdown(); 93 | return NULL; 94 | } 95 | 96 | /* メモリの解放 */ 97 | void kzmem_free(void *mem) 98 | { 99 | int i; 100 | kzmem_block *mp; 101 | kzmem_pool *p; 102 | 103 | /* 領域の直前にある(はずの)メモリ・ブロック構造体を取得 */ 104 | mp = ((kzmem_block *)mem - 1); 105 | 106 | for (i = 0; i < MEMORY_AREA_NUM; i++) { 107 | p = &pool[i]; 108 | if (mp->size == p->size) { 109 | /* 領域を解放済みリンクリストに戻す */ 110 | mp->next = p->free; 111 | p->free = mp; 112 | return; 113 | } 114 | } 115 | 116 | kz_sysdown(); 117 | } 118 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | #ifndef _KOZOS_MEMORY_H_INCLUDED_ 2 | #define _KOZOS_MEMORY_H_INCLUDED_ 3 | 4 | int kzmem_init(void); /* 動的メモリの初期化 */ 5 | void *kzmem_alloc(int size); /* 動的メモリの獲得 */ 6 | void kzmem_free(void *mem); /* メモリの解放 */ 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /raspi.cfg: -------------------------------------------------------------------------------- 1 | # Broadcom 2835 on Raspberry Pi 2 | 3 | telnet_port 4444 4 | #gdb_port 0 5 | #tcl_port 0 6 | 7 | #jtag_khz 1000 8 | adapter_khz 1000 9 | 10 | #jtag_nsrst_delay 400 11 | #jtag_ntrst_delay 400 12 | 13 | if { [info exists CHIPNAME] } { 14 | set _CHIPNAME $CHIPNAME 15 | } else { 16 | set _CHIPNAME raspi 17 | } 18 | 19 | reset_config none 20 | 21 | if { [info exists CPU_TAPID ] } { 22 | set _CPU_TAPID $CPU_TAPID 23 | } else { 24 | set _CPU_TAPID 0x07b7617F 25 | } 26 | jtag newtap $_CHIPNAME arm -irlen 5 -expected-id $_CPU_TAPID 27 | 28 | set _TARGETNAME $_CHIPNAME.arm 29 | target create $_TARGETNAME arm11 -chain-position $_TARGETNAME 30 | 31 | -------------------------------------------------------------------------------- /raspi_with_ngxtech.cfg: -------------------------------------------------------------------------------- 1 | # Author: Toshifumi NISHINAGA 2 | # E-Mail: tnishinaga DOT dev AT gmail DOT com 3 | # (please replace AT to @, DOT to ., and remove space) 4 | 5 | source [find interface/ngxtech.cfg] 6 | source raspi.cfg 7 | 8 | -------------------------------------------------------------------------------- /raspi_with_olimex.cfg: -------------------------------------------------------------------------------- 1 | # Author: Toshifumi NISHINAGA 2 | # E-Mail: tnishinaga DOT dev AT gmail DOT com 3 | # (please replace AT to @, DOT to ., and remove space) 4 | 5 | source [find interface/olimex-arm-usb-tiny-h.cfg] 6 | source raspi.cfg 7 | 8 | -------------------------------------------------------------------------------- /rpi_peripherals.h: -------------------------------------------------------------------------------- 1 | #ifndef RPILIB_PERIPHERALS_H 2 | #define RPILIB_PERIPHERALS_H 3 | 4 | #define PHY_PERI_ADDR(x) (0x20000000 + (x)) 5 | 6 | // GPIO Peripheral 7 | #define GPIO_BASE (0x00200000) 8 | #define GPFSEL0 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x00)) 9 | #define GPFSEL1 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x04)) 10 | #define GPFSEL2 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x08)) 11 | #define GPFSEL3 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x0c)) 12 | #define GPFSEL4 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x10)) 13 | #define GPFSEL5 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x14)) 14 | #define GPSET0 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x1c)) 15 | #define GPSET1 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x20)) 16 | #define GPCLR0 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x28)) 17 | #define GPCLR1 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x2c)) 18 | #define GPLEV0 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x34)) 19 | #define GPLEV1 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x38)) 20 | // for GPFSEL mask 21 | // use AND mask 22 | #define GPFSEL_MASK_IN(n) (~(volatile uint32)(0x07 << ((n % 10) * 3))) 23 | // use OR mask 24 | #define GPFSEL_MASK_OUT(n) (0x01 << ((n % 10) * 3)) 25 | #define GPFSEL_MASK_ALT0(n) (0x04 << ((n % 10) * 3)) 26 | #define GPFSEL_MASK_ALT1(n) (0x05 << ((n % 10) * 3)) 27 | #define GPFSEL_MASK_ALT2(n) (0x06 << ((n % 10) * 3)) 28 | #define GPFSEL_MASK_ALT3(n) (0x07 << ((n % 10) * 3)) 29 | #define GPFSEL_MASK_ALT4(n) (0x03 << ((n % 10) * 3)) 30 | #define GPFSEL_MASK_ALT5(n) (0x02 << ((n % 10) * 3)) 31 | // GPIO PULLUP/DOWN 32 | #define GPPUD ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x94)) 33 | #define GPPUDCLK0 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x98)) 34 | #define GPPUDCLK1 ((volatile uint32 *)PHY_PERI_ADDR(GPIO_BASE + 0x9C)) 35 | 36 | 37 | // SystemTimer Peripheral 38 | #define SYST_BASE (0x00003000) 39 | #define SYST_CS ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x00)) 40 | #define SYST_CLO ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x04)) 41 | #define SYST_CHI ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x08)) 42 | #define SYST_C0 ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x0c)) 43 | #define SYST_C1 ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x10)) 44 | #define SYST_C2 ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x14)) 45 | #define SYST_C3 ((volatile uint32 *)PHY_PERI_ADDR(SYST_BASE + 0x18)) 46 | 47 | 48 | // UART peripheral 49 | #define UART0_BASE 0x00201000 50 | #define UART0_DR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x00)) 51 | #define UART0_RSRECR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x04)) 52 | #define UART0_FR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x18)) 53 | // #define UART0_ILPR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x20)) // not use 54 | #define UART0_IBRD ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x24)) 55 | #define UART0_FBRD ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x28)) 56 | #define UART0_LCRH ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x2c)) 57 | #define UART0_CR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x30)) 58 | #define UART0_IFLS ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x34)) 59 | #define UART0_IMSC ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x38)) 60 | #define UART0_RIS ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x3c)) 61 | #define UART0_MIS ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x40)) 62 | #define UART0_ICR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x44)) 63 | #define UART0_DMACR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x48)) 64 | #define UART0_ITCR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x80)) 65 | #define UART0_ITIP ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x84)) 66 | #define UART0_ITOP ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x88)) 67 | #define UART0_TDR ((volatile uint32 *)PHY_PERI_ADDR(UART0_BASE + 0x8c)) 68 | 69 | 70 | // SPI0 peripheral 71 | #define SPI0_BASE (0x00204000) 72 | #define SPI0_CS ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x00)) 73 | #define SPI0_FIFO ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x04)) 74 | #define SPI0_CLK ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x08)) 75 | #define SPI0_DLEN ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x0C)) 76 | #define SPI0_LTOH ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x10)) 77 | #define SPI0_DC ((volatile uint32 *)PHY_PERI_ADDR(SPI0_BASE + 0x14)) 78 | 79 | // I2C(BSC1) peripheral 80 | #define BSC1_BASE (0x00804000) 81 | #define BSC1_C ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x00)) 82 | #define BSC1_S ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x04)) 83 | #define BSC1_DLEN ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x08)) 84 | #define BSC1_A ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x0C)) 85 | #define BSC1_FIFO ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x10)) 86 | #define BSC1_DIV ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x14)) 87 | #define BSC1_DEL ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x18)) 88 | #define BSC1_CLKT ((volatile uint32 *)PHY_PERI_ADDR(BSC1_BASE + 0x1C)) 89 | 90 | 91 | // Timer(ARM side) peripheral 92 | #define TIMER_BASE (0x0000B000) 93 | #define TIMER_LOAD ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x400)) 94 | #define TIMER_VALUE ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x404)) 95 | #define TIMER_CONTROL ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x408)) 96 | #define TIMER_IRQ_CLR ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x40C)) 97 | #define TIMER_RAWIRQ ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x410)) 98 | #define TIMER_MASKEDIRQ ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x414)) 99 | #define TIMER_RELOAD ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x418)) 100 | #define TIMER_PREDIVIDER ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x41C)) 101 | #define TIMER_FREECOUNTER ((volatile uint32 *)PHY_PERI_ADDR(TIMER_BASE + 0x420)) 102 | 103 | 104 | // Interrupt 105 | #define INTERRUPT_BASE (0x0000B000) 106 | #define INTERRUPT_IRQ_BASIC_PENDING ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x200)) 107 | #define INTERRUPT_IRQ_PENDING1 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x204)) 108 | #define INTERRUPT_IRQ_PENDING2 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x208)) 109 | #define INTERRUPT_FIQ_CTRL ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x20C)) 110 | #define INTERRUPT_ENABLE_IRQS1 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x210)) 111 | #define INTERRUPT_ENABLE_IRQS2 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x214)) 112 | #define INTERRUPT_ENABLE_BASIC_IRQS ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x218)) 113 | #define INTERRUPT_DISABLE_IRQS1 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x21C)) 114 | #define INTERRUPT_DISABLE_IRQS2 ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x220)) 115 | #define INTERRUPT_DISABLE_BASIC_IRQS ((volatile uint32 *)PHY_PERI_ADDR(INTERRUPT_BASE + 0x224)) 116 | 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /serial.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "serial.h" 3 | #include "rpi_peripherals.h" 4 | 5 | /* デバイス初期化 */ 6 | int serial_init(int index) 7 | { 8 | // UART無効化 9 | *UART0_CR = 0; 10 | 11 | //ポートの設定 12 | // GPIO14: ALT0 13 | // GPIO15: ALT0 14 | *GPFSEL1 &= ~((uint32)0x07 << ((14 % 10) * 3)); 15 | *GPFSEL1 &= ~((uint32)0x07 << ((15 % 10) * 3)); 16 | *GPFSEL1 |= ((uint32)0x04 << ((14 % 10) * 3)); 17 | *GPFSEL1 |= ((uint32)0x04 << ((15 % 10) * 3)); 18 | 19 | // 割り込みフラグのクリア 20 | *UART0_ICR = 0x7ff; 21 | 22 | // ボーレートの設定(9600) 23 | *UART0_IBRD = 19; 24 | *UART0_FBRD = 34; 25 | 26 | // LCRH 27 | // stick parity dis, 8bit, FIFO en, two stop bit no, odd parity, parity dis, break no 28 | *UART0_LCRH = 3 << 5; 29 | 30 | // CR 31 | // CTS dis, RTS dis, OUT1-2=0, RTS dis, DTR dis, RXE en, TXE en, loop back dis, SIRLP=0, SIREN=0, UARTEN en 32 | *UART0_CR = 0x0301; 33 | 34 | // UART割り込みを有効化 35 | // UARTのIRQ番号は57 36 | *INTERRUPT_ENABLE_IRQS2 = ((uint32)1 << (57 % 32)); 37 | 38 | return 0; 39 | } 40 | 41 | /* 送信可能か? */ 42 | int serial_is_send_enable(int index) 43 | { 44 | // check FR:TXFF 45 | return (*UART0_FR & (1 << 5)) ? 0:1; 46 | } 47 | 48 | /* 1文字送信 */ 49 | int serial_send_byte(int index, unsigned char c) 50 | { 51 | *UART0_DR = c; 52 | return 0; 53 | } 54 | 55 | /* 受信可能か? */ 56 | int serial_is_recv_enable(int index) 57 | { 58 | // check FR:RXFE 59 | return (*UART0_FR & (1 << 4)) ? 0:1; 60 | } 61 | 62 | /* 1文字受信 */ 63 | unsigned char serial_recv_byte(int index) 64 | { 65 | return (*UART0_DR & 0xff); 66 | } 67 | 68 | /* 送信割込み有効か? */ 69 | int serial_intr_is_send_enable(int index) 70 | { 71 | // Raspberry Pi で割り込みを有効にするためには以下の2つを行う必要がある 72 | // * IRQレジスタを使ったUART自体の割り込み有効化 73 | // * UARTレジスタの割り込みマスク設定 74 | // 前者はinit処理時に行うので必要なし 75 | // 後者のみを行う 76 | return (*UART0_IMSC & ((uint32)1 << 5)) ? 1 : 0; 77 | } 78 | 79 | /* 送信割込み有効化 */ 80 | void serial_intr_send_enable(int index) 81 | { 82 | *UART0_IMSC |= (uint32)1 << 5; 83 | } 84 | 85 | /* 送信割込み無効化 */ 86 | void serial_intr_send_disable(int index) 87 | { 88 | *UART0_IMSC &= ~((uint32)1 << 5); 89 | } 90 | 91 | /* 受信割込み有効か? */ 92 | int serial_intr_is_recv_enable(int index) 93 | { 94 | return (*UART0_IMSC & ((uint32)1 << 4)) ? 1 : 0; 95 | } 96 | 97 | /* 受信割込み有効化 */ 98 | void serial_intr_recv_enable(int index) 99 | { 100 | *UART0_IMSC |= (uint32)1 << 4; 101 | } 102 | 103 | /* 受信割込み無効化 */ 104 | void serial_intr_recv_disable(int index) 105 | { 106 | *UART0_IMSC &= ~((uint32)1 << 4); 107 | } 108 | -------------------------------------------------------------------------------- /serial.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERIAL_H_INCLUDED_ 2 | #define _SERIAL_H_INCLUDED_ 3 | 4 | int serial_init(int index); /* デバイス初期化 */ 5 | int serial_is_send_enable(int index); /* 送信可能か? */ 6 | int serial_send_byte(int index, unsigned char b); /* 1文字送信 */ 7 | int serial_is_recv_enable(int index); /* 受信可能か? */ 8 | unsigned char serial_recv_byte(int index); /* 1文字受信 */ 9 | int serial_intr_is_send_enable(int index); /* 送信割込み有効か? */ 10 | void serial_intr_send_enable(int index); /* 送信割込み有効化 */ 11 | void serial_intr_send_disable(int index); /* 送信割込み無効化 */ 12 | int serial_intr_is_recv_enable(int index); /* 受信割込み有効か? */ 13 | void serial_intr_recv_enable(int index); /* 受信割込み有効化 */ 14 | void serial_intr_recv_disable(int index); /* 受信割込み無効化 */ 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /startup.S: -------------------------------------------------------------------------------- 1 | #define CPSR_MODE_USER 0x10 2 | #define CPSR_MODE_FIQ 0x11 3 | #define CPSR_MODE_IRQ 0x12 4 | #define CPSR_MODE_SVC 0x13 5 | #define CPSR_MODE_MONITOR 0x16 6 | #define CPSR_MODE_ABORT 0x17 7 | #define CPSR_MODE_UNDEFINED 0x1b 8 | #define CPSR_MODE_SYSTEM 0x1f 9 | #define CPSR_THUMB 1 << 5 10 | #define CPSR_FIQ_DIS 1 << 6 11 | #define CPSR_IRQ_DIS 1 << 7 12 | #define CPSR_ASYNC_ABORT 1 << 8 13 | #define CPSR_ENDIAN_BE 1 << 9 14 | 15 | 16 | .section .text 17 | .global _start 18 | # .type _start,@function 19 | _start: 20 | @ jtag setup 21 | bl jtag_setup_asm 22 | @ disable interrupt and enter system mode 23 | @ ldr r0, =(CPSR_ASYNC_ABORT | CPSR_IRQ_DIS | CPSR_FIQ_DIS | CPSR_MODE_SYSTEM) 24 | @ msr cpsr, r0 25 | cpsid aif, #0x1f 26 | @ set system stack pointer 27 | ldr sp, =_bootstack 28 | @ clear BSS 29 | @ r1: BSS start address 30 | @ r2: BSS end address 31 | @ r3: 0 32 | ldr r1, =_bss_start 33 | ldr r2, =_ebss 34 | movs r3, #0 35 | clear_bss: 36 | @ if r1 == r2 then goto clear_bss_done 37 | cmp r1, r2 38 | bpl clear_bss_done 39 | @ write 0 to memory 40 | str r3, [r1], #4 @ [r0] = r3, r0++ 41 | @ jump to clear_bss 42 | b clear_bss 43 | clear_bss_done: 44 | @ set vector table 45 | bl set_vector_table 46 | 47 | @ disable all IRQ source 48 | ldr r0, =0x2000B21C 49 | mvn r1, #0 50 | str r1, [r0], #4 @ IRQs 1 51 | str r1, [r0], #4 @ IRQs 2 52 | strb r1, [r0] @ Basic IRQs 53 | 54 | @ goto main function 55 | bl main 56 | 1: 57 | wfi @ sleep 58 | b 1b 59 | 60 | .global get_cpsr 61 | get_cpsr: 62 | mrs r0, cpsr 63 | bx lr 64 | 65 | .global set_vector_table 66 | set_vector_table: 67 | ldr r0, =Vector_Table 68 | ldr r1, =Vector_Table_end 69 | mov r2, #0 @ vector table start address 70 | 1: 71 | @ if r0 == r1 then goto 1 72 | cmp r0, r1 73 | beq 2f 74 | ldr r3, [r0], #4 75 | str r3, [r2], #4 76 | @ jump to clear_bss 77 | b 1b 78 | 2: 79 | bx lr 80 | 81 | @@@ JTAG setup @@@ 82 | @ 3.3V : ARM_VREF 83 | @ GPIO22 (ALT4): ARM_TRST 84 | @ GPIO4 (ALT5): ARM_TDI 85 | @ GPIO27 (ALT4): ARM_TMS 86 | @ GPIO25 (ALT4): ARM_TCK 87 | @ GPIO24 (ALT4): ARM_TDO 88 | @ GND : ARM_GND 89 | jtag_setup_asm: 90 | ldr r1, =0x20200000 @ load GPFSEL address 91 | ldr r2, =0xffff8fff @ load GPIO4 mask 92 | ldr r3, =0xff1c0e3f @ load GPIO22,24,25,27 mask 93 | ldr r4, [r1, #0] @ load GPFSEL0 value 94 | ldr r5, [r1, #8] @ load GPFSEL2 value 95 | and r4, r4, r2 @ clear GPIO4 mode 96 | and r5, r5, r3 @ clear GPIO22,24,25,27 mode 97 | ldr r2, =0x00002000 @ load GPIO4 ALT4 98 | ldr r3, =0x0061b0c0 @ load GPIO22,24,25,27 ALT5 99 | orr r4, r4, r2 @ set GPIO4 mode to ALT4 100 | orr r5, r5, r3 @ set GPIO22,24,25,27 mode to ALT5 101 | str r4, [r1, #0] @ save GPFSEL0 value 102 | str r5, [r1, #8] @ save GPFSEL2 value 103 | bx lr 104 | -------------------------------------------------------------------------------- /syscall.c: -------------------------------------------------------------------------------- 1 | #include "defines.h" 2 | #include "kozos.h" 3 | #include "interrupt.h" 4 | #include "syscall.h" 5 | 6 | /* システム・コール */ 7 | 8 | kz_thread_id_t kz_run(kz_func_t func, char *name, int priority, int stacksize, 9 | int argc, char *argv[]) 10 | { 11 | kz_syscall_param_t param; 12 | param.un.run.func = func; 13 | param.un.run.name = name; 14 | param.un.run.priority = priority; 15 | param.un.run.stacksize = stacksize; 16 | param.un.run.argc = argc; 17 | param.un.run.argv = argv; 18 | kz_syscall(KZ_SYSCALL_TYPE_RUN, ¶m); 19 | return param.un.run.ret; 20 | } 21 | 22 | void kz_exit(void) 23 | { 24 | kz_syscall(KZ_SYSCALL_TYPE_EXIT, NULL); 25 | } 26 | 27 | int kz_wait(void) 28 | { 29 | kz_syscall_param_t param; 30 | kz_syscall(KZ_SYSCALL_TYPE_WAIT, ¶m); 31 | return param.un.wait.ret; 32 | } 33 | 34 | int kz_sleep(void) 35 | { 36 | kz_syscall_param_t param; 37 | kz_syscall(KZ_SYSCALL_TYPE_SLEEP, ¶m); 38 | return param.un.sleep.ret; 39 | } 40 | 41 | int kz_wakeup(kz_thread_id_t id) 42 | { 43 | kz_syscall_param_t param; 44 | param.un.wakeup.id = id; 45 | kz_syscall(KZ_SYSCALL_TYPE_WAKEUP, ¶m); 46 | return param.un.wakeup.ret; 47 | } 48 | 49 | kz_thread_id_t kz_getid(void) 50 | { 51 | kz_syscall_param_t param; 52 | kz_syscall(KZ_SYSCALL_TYPE_GETID, ¶m); 53 | return param.un.getid.ret; 54 | } 55 | 56 | int kz_chpri(int priority) 57 | { 58 | kz_syscall_param_t param; 59 | param.un.chpri.priority = priority; 60 | kz_syscall(KZ_SYSCALL_TYPE_CHPRI, ¶m); 61 | return param.un.chpri.ret; 62 | } 63 | 64 | void *kz_kmalloc(int size) 65 | { 66 | kz_syscall_param_t param; 67 | param.un.kmalloc.size = size; 68 | kz_syscall(KZ_SYSCALL_TYPE_KMALLOC, ¶m); 69 | return param.un.kmalloc.ret; 70 | } 71 | 72 | int kz_kmfree(void *p) 73 | { 74 | kz_syscall_param_t param; 75 | param.un.kmfree.p = p; 76 | kz_syscall(KZ_SYSCALL_TYPE_KMFREE, ¶m); 77 | return param.un.kmfree.ret; 78 | } 79 | 80 | int kz_send(kz_msgbox_id_t id, int size, char *p) 81 | { 82 | kz_syscall_param_t param; 83 | param.un.send.id = id; 84 | param.un.send.size = size; 85 | param.un.send.p = p; 86 | kz_syscall(KZ_SYSCALL_TYPE_SEND, ¶m); 87 | return param.un.send.ret; 88 | } 89 | 90 | kz_thread_id_t kz_recv(kz_msgbox_id_t id, int *sizep, char **pp) 91 | { 92 | kz_syscall_param_t param; 93 | param.un.recv.id = id; 94 | param.un.recv.sizep = sizep; 95 | param.un.recv.pp = pp; 96 | kz_syscall(KZ_SYSCALL_TYPE_RECV, ¶m); 97 | return param.un.recv.ret; 98 | } 99 | 100 | int kz_setintr(softvec_type_t type, kz_handler_t handler) 101 | { 102 | kz_syscall_param_t param; 103 | param.un.setintr.type = type; 104 | param.un.setintr.handler = handler; 105 | kz_syscall(KZ_SYSCALL_TYPE_SETINTR, ¶m); 106 | return param.un.setintr.ret; 107 | } 108 | 109 | /* サービス・コール */ 110 | 111 | int kx_wakeup(kz_thread_id_t id) 112 | { 113 | kz_syscall_param_t param; 114 | param.un.wakeup.id = id; 115 | kz_srvcall(KZ_SYSCALL_TYPE_WAKEUP, ¶m); 116 | return param.un.wakeup.ret; 117 | } 118 | 119 | void *kx_kmalloc(int size) 120 | { 121 | kz_syscall_param_t param; 122 | param.un.kmalloc.size = size; 123 | kz_srvcall(KZ_SYSCALL_TYPE_KMALLOC, ¶m); 124 | return param.un.kmalloc.ret; 125 | } 126 | 127 | int kx_kmfree(void *p) 128 | { 129 | kz_syscall_param_t param; 130 | param.un.kmfree.p = p; 131 | kz_srvcall(KZ_SYSCALL_TYPE_KMFREE, ¶m); 132 | return param.un.kmfree.ret; 133 | } 134 | 135 | int kx_send(kz_msgbox_id_t id, int size, char *p) 136 | { 137 | kz_syscall_param_t param; 138 | param.un.send.id = id; 139 | param.un.send.size = size; 140 | param.un.send.p = p; 141 | kz_srvcall(KZ_SYSCALL_TYPE_SEND, ¶m); 142 | return param.un.send.ret; 143 | } 144 | -------------------------------------------------------------------------------- /syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _KOZOS_SYSCALL_H_INCLUDED_ 2 | #define _KOZOS_SYSCALL_H_INCLUDED_ 3 | 4 | #include "defines.h" 5 | #include "interrupt.h" 6 | 7 | /* システム・コール番号の定義 */ 8 | typedef enum { 9 | KZ_SYSCALL_TYPE_RUN = 0, 10 | KZ_SYSCALL_TYPE_EXIT, 11 | KZ_SYSCALL_TYPE_WAIT, 12 | KZ_SYSCALL_TYPE_SLEEP, 13 | KZ_SYSCALL_TYPE_WAKEUP, 14 | KZ_SYSCALL_TYPE_GETID, 15 | KZ_SYSCALL_TYPE_CHPRI, 16 | KZ_SYSCALL_TYPE_KMALLOC, 17 | KZ_SYSCALL_TYPE_KMFREE, 18 | KZ_SYSCALL_TYPE_SEND, 19 | KZ_SYSCALL_TYPE_RECV, 20 | KZ_SYSCALL_TYPE_SETINTR, 21 | } kz_syscall_type_t; 22 | 23 | /* システム・コール呼び出し時のパラメータ格納域の定義 */ 24 | typedef struct { 25 | union { 26 | struct { 27 | kz_func_t func; 28 | char *name; 29 | int priority; 30 | int stacksize; 31 | int argc; 32 | char **argv; 33 | kz_thread_id_t ret; 34 | } run; 35 | struct { 36 | int dummy; 37 | } exit; 38 | struct { 39 | int ret; 40 | } wait; 41 | struct { 42 | int ret; 43 | } sleep; 44 | struct { 45 | kz_thread_id_t id; 46 | int ret; 47 | } wakeup; 48 | struct { 49 | kz_thread_id_t ret; 50 | } getid; 51 | struct { 52 | int priority; 53 | int ret; 54 | } chpri; 55 | struct { 56 | int size; 57 | void *ret; 58 | } kmalloc; 59 | struct { 60 | char *p; 61 | int ret; 62 | } kmfree; 63 | struct { 64 | kz_msgbox_id_t id; 65 | int size; 66 | char *p; 67 | int ret; 68 | } send; 69 | struct { 70 | kz_msgbox_id_t id; 71 | int *sizep; 72 | char **pp; 73 | kz_thread_id_t ret; 74 | } recv; 75 | struct { 76 | softvec_type_t type; 77 | kz_handler_t handler; 78 | int ret; 79 | } setintr; 80 | } un; 81 | } kz_syscall_param_t; 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /vector.S: -------------------------------------------------------------------------------- 1 | .global Vector_Table 2 | .align 4 3 | Vector_Table: 4 | ldr pc, Reset_Addr 5 | ldr pc, Undefined_Addr 6 | ldr pc, SVC_Addr 7 | ldr pc, Prefetch_Addr 8 | ldr pc, Abort_Addr 9 | nop 10 | ldr pc, IRQ_Addr 11 | FIQ_Handler: 12 | @ 4KB max 13 | 1: 14 | wfi 15 | b 1b 16 | 17 | Reset_Addr: 18 | .word _start 19 | Undefined_Addr: 20 | .word undefined_fault 21 | Prefetch_Addr: 22 | .word prefetch_fault 23 | Abort_Addr: 24 | .word abort_fault 25 | IRQ_Addr: 26 | .word IRQ_Handler_asm 27 | SVC_Addr: 28 | .word SVC_Handler_asm 29 | .global Vector_Table_end 30 | Vector_Table_end: 31 | nop 32 | 33 | undefined_fault: 34 | wfi 35 | b undefined_fault 36 | 37 | prefetch_fault: 38 | subs pc, lr, #4 39 | 1: 40 | wfi 41 | b 1b 42 | 43 | abort_fault: 44 | wfi 45 | b abort_fault --------------------------------------------------------------------------------