FPGA

FPGAとは?
-> Field Programmable Gate Arrayの略
-> 現場で書き換え可能な論理回路の多数配列:ハードウェア言語で修正が出来るデバイス

ハードウェア言語とは一般的に半導体の回路記述をする際に用いる言語
論理回路とはデジタル信号を扱う回路のこと
論理合成と配置配線はハードウェア言語で記述された回路をFPGAに書き込む為のデータに変換すること

CPLDは汎用ロジックIC数百個~数千個分の回路を内部で構成できる
LSIを超える規模の回路を簡単に構成できる
PLGの一種

【組み込み系の開発工程】
要求分析→要件定義→基本設計・詳細設計→RTL設計(Verilog、VHDLなどを用いてコーディング) →論理合成→動作シミュレーション→配置配線

ビッグデータのデータ処理やディープラーニング向けの並列計算等にFPGAやASICが使われることもある

[CPU]命令セット

– 命令の集まり
– コンピュータで使われる命令の表現形式と各命令の動作を定めたもの
命令 = 操作オペランド + 対象
L ソースオペランド
L デスティネーションオペランド
オペランドとなるものはデータレジスタ、メモリ語、プログラムカウンタ、その他レジスタ

### 命令の表現形式
(1)R型: op(5:操作コード) rs(5:オペランドレジスタ) rt(5) rd(5) aux(11:実行細則)
(2)I型: op(6) rs(5) rt(5) imm/dpl(16:immediate displacement)
(3)A型: op(6) addr(26:メモリアドレス)
命令語が32ビット、命令セットの大きさが64、レジスタ数が32

アセンブリ言語表現
R型:add r2 r3 r1 0
I型:subi r2 r1 14
A型:j 1048581

算術論理演算命令(R型(整数)、I型、 R型(浮動小数点))
加算:add, addi, fadd
減算:sub, subi, fsub
乗算:mul, muli, fmul
除算:div, divi, fdiv
除余:rem, remi
絶対値:abs, , fabs
算術左シフト: sla, ,
算術右シフト: sra, ,
論理積:and, andi
論理和:or, ori
否定:not,
NOR:nor, nori
NAND:nand, nandi
排他的論理和:xor, xori
EQUIV:eq, eqi
論理左シフト:sll
論理右シフト:srl

命令の動作はオペランドがデコーダでALUに行き、レジスタのアドレスを取得して計算する

シリコンチップで集積回路を作るには、シリコン上の構造物の配置を図面に落とす必要がある
基本素子を作り、それを配置していく

ICチップを作るには、まず原材料としてシリコンウェハー(Si)が必要
ピラニア溶液(H2SO4:H2O2)、RCA1(H2O:NH3:H2O2)、RCA2(H2O:HCL:H2O2)で洗浄してHF液につけて自然酸化膜を作る

なるほど、CPUの設計って回路設計だけでなく、物理、化学、光学、電気学などかなり幅広い知識を応用してんだな。

[C言語]カーネル

Unix系では新しいプロセスはfork()により生成されexec()系の関数により新たなプログラムに書き換わる
プログラムを実行する為のライブラリ関数としてexeclp()やexecvp()などがある
execveシステムコールが発行されるとカーネルの仕事となる
– 実行ファイルを読み込み、仮想メモリ上にマッピングする
– argc/argv[]、BSSの初期化、環境変数の引き渡しなどを行う
– 実行ファイル上のエントリポイントから実行を開始する

※カーネルを読み込むには5年程度の技術と時間がかかる
カーネルの大部分はC言語で書かれているが、CPU固有の処理部分はアセンブラ言語で書かれている

## カーネルのディレクトリ
Documentation ドキュメント
arch アーキテクチャ依存
block ブロック入出力層
crypto 暗号化
drivers デバイス・ドライバ
firmware ファームウェア
fs VFS(Virtual File System)とファイル・システム
include カーネル用のヘッダ・ファイル
init 起動と初期化(initialization)
ipc プロセス間通信(interprocess communication)
kernel カーネルの中心部分
lib ヘルパ
mm メモリ管理(memory management)
net ネットワーク
samples サンプルコード
scripts カーネルのコンパイルに必要なスクリプト
security Lnux Security Module
sound サウンド・サブシステム
tools カーネル開発用のツール
usr 起動直後にユーザ空間で実行されるプログラム(initramfs)
virt 仮想化インフラ

C言語ではcrt(C RunTime startup)というアセンブリで記述されたプログラムが一番最初に実行される
OSの開発ではこのcrtを環境に合わせて用意する

[C言語]メモリリーク

メモリリークとは、動的に割当てたメモリ領域を解放し忘れることで次第にメモリ資源を食い潰していき、いずれプログラムやシステムに異常をきたすという問題。
c言語のメモリ解放はmalloc()やfree()が使われてきた。
malloc()で割当てて、free()で解放する。
メモリの解放を忘れていると、プログラムが終了するまでメモリ資源を無駄に占有し続ける。

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int maikFile(char *fileName, int size){
	FILE *fp;
	char *pData;

	// メモリ解放
	pData = malloc(size);
	if(pData == NULL){
		return 1;
	}

	fp = fopen(fileName, "wb");
	if(fp == NULL){
		return 1;
	}

	memset(pData, 0x20, size);
	fwrite(pData, size, 1, fp);
	fclose(fp);

	free(pData);
	return 0;
}


int main(int argc, char** argv[]){

	return 0;

}

ファイルシステムオープンの失敗を繰り返すと、メモリは解放されずにreturn1となるのでメモリリークになる。

[C言語]ファイヤーウォール

ファイヤーウォールとはパケットの制御または破棄を行うソフトウェアである

特定のパケットとは、
– 特定のポートにアクセスするパケット
– 特定のIPアドレスからのパケット
– 特定の内容をもつパケット
などがある。

ファイヤーウォールを作成するには
– パケットの中身を見る
– パケットの転送可否を行う

### パケットキャプチャ
パケットの中身を見る
TCPやUDPはもとより、IPやEthernetレベルのデータリンク情報も解析する
一般的に tcpdump や wireshark などがある

#include <stdio.h>
#include <net/if.h> // ネットワークインターフェイス構造体 PF_PACKET
#include <net/ethernet.h> // ETH_P_ALL

void analyzePacket(u_char *buf){
	printEtherHeader(buf);
}

void printEtherHeader(u_char *buf){
	struct ether_header *eth;
	eth = (struct ether_header *)buf;
	printf("Dst MAC addr :%17s\n", mac_ntoa(eth->ether_dhost));
	printf("Src MAC addr :%17s\n", mac_ntoa(eth->ether_shost));
	printf("Ethernet Type :0x%04x\n", ntohs(ether_type));
}

char *mac_ntoa(u_char *d){
	static char str[18];
	sprintf(str,"%02x:%02x:%02x:%02x:%02x:%02x",d[0],d[1],d[2],d[3],d[4],d[5]);
	return str;
}

int main(int argc, char** argv[]){

	int soc;
	u_char buf[65535]; // u_charはunsigned char
	soc = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	while(1){
		read(soc,buf,sizeof(buf));
		analyzePacket(buf);
	}
	return 0;

}

int socket(int domain, int type, int protocol);
PF_PACKETを指定すると,データリンク層やネットワーク層の生データを扱える
通常はSOCK_STREAM(TCPの場合)やSOCK_DGRAM(UDPの場合)
ETHERNETとは、TCP/IPプロトコルのネットワークインターフェース層に対応する有線の規格

宛先MAC address(固有識別番号)、送信元MAC address, type, ip以降
ビッグエンディアン

[C言語]ICMP

ICMPとはInternet Control Message Protocol
Internet Protocolのデータグラム処理における誤りの通知や通信に関する情報の通知などのために使用される

#include <stdio.h>

#include <sys/socket.h> // Internet Protocol family
#include <netinet/in.h> // Internet Protocol family

#include <netinet/ip.h>  // IPヘッダ構造体
#include <netinet/ip_icmp.h> // ICMPヘッダ

unsigned short checksum(unsigned short *buf, int bufsz){

	unsigned long sum = 0;

	while(bufsz > 1){
		sum += *buf;
		buf++;
		bufsz -= 2;
	}

	if(bufsz == 1){
		sum += *(unsigned char *)buf;
	}

	sum = (sum & 0xffff) + (sum >> 16);
	sum = (sum & 0xffff) + (sum >> 16);

	return ~sum;
}

int main(int argc, char** argv[]){

	int sock;
	struct icmphdr hdr;
	struct sockaddr_in addr;
	int n;

	char buf[2000];
	struct icmphdr *icmphdrptr;
	struct iphdr *iphdrptr;

	if(argc != 2){
		printf("usage : %s IPADDR\n", argv[0]);
		return 1;
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(argv[1]);

	sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if(sock < 0){
		perror("socket");
		return 1;
	}

	memset(&hdr, 0, sizeof(hdr));

	hdr.type = ICMP_ECHO;
	hdr.code = 0;
	hdr.checksum = 0;
	hdr.un.echo.id = 0;
	hdr.un.echo.sequence = 0;

	hdr.checksum = chechsum((unsigned short *)&hdr, sizeof(hdr));

	n = sendto(sock, (char *)&hdr, sizeof(hdr), 0, (struct sockaddr *)&addr, sizeof(addr));
	if (n < 1){
		perror("sendto");
	}

	memset(buf, 0, sizeof(buf));

	n = recv(sock, buf, sizeof(buf), 0);
	if(n < 1){
		perror("recv");
	}

	iphdrptr = (struct iphdr *) buf;

	icmphdrptr = (struct icmphdr *)(buf + (iphdrptr->ihl * 4));

	if(icmphdrptr->type == ICMP_ECHOREPLY){
		printf("received ICMP ECHO REPLY\n");
	} else {
		printf("received ICMP %d\n", icmphdrptr->type);
	}

	close(sock);
	

	return 0;

}

[C言語]UDP

UDPはデータが宛先に届いたかどうかを関知しない為、到着を保証しない
複数の相手に同時にデータを送信できる、TCPは1対1のユニキャストのみ
TCPよりリアルタイム性が高い
用途は映像、音楽のストリーミング、Voice Over IPなど

### UDP受信
– ソケットを作る
– bindするIPアドレスとポートを設定
– ソケットに名前をつける
– データを受け取る

#include <stdio.h>
#include <sys/types.h> // typedef シンボルおよび構造体のコレクション
#include <sys/socket.h> // Internet Protocol family
#include <netinet/in.h> // Internet Protocol family

int main(int argc, char** argv){

	int sock;
	struct sockaddr_in addr; // sockaddr_inはIPアドレスやポート番号を保持する為の構造体

	char buf[2048];

	sock = socket(AF_INET, SOCK_DGRAM, 0); // ソケットの作成

	addr.sin_family = AF_INET; // アドレスファミリ
	addr.sin_port = htons(12345); // ポート番号、 htonsはネットワークバイトオーダに変換
	addr.sin_addr.s_addr = INADDR_ANY; // IPアドレス

	bind(sock, (struct sockaddr *)&addr, sizeof(addr)); // sockはソケットとアドレスの結合

	memset(buf, 0, sizeof(buf)); // バイトメモリブロックのセット
	recv(sock, buf, sizeof(buf), 0); // ソケットからメッセージを受け取る

	printf("%s\n", buf);

	close(sock);

	return 0;

}

### UDP送信
– ソケットを作る
– 宛先を指定して送信

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
	
	int sock;
	struct sockaddr_in addr;

	sock = socket(AF_INET, SOCK_DGRAM, 0);

	addr.sin_family = AF_INET;
	addr.sin_port = htons(12345);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));

	close(sock);

	return 0;
}

TCP/IPはデータを切れ目のないストリームとして扱う、ストリームのイメージは固定された通信路
一方、UDPはデータグラム(塊)として扱う

TCPとUDPについてわかってきました。

[C言語]TCP/IP

サーバ側

#include 
#include 
#include 
#include 

int main(int argc, char** argv){
	int sd;
	int acc_sd;
	struct sockaddr_in addr;

	socklen_t sin_size = sizeof(struct sockaddr_in);
	struct sock_in from addr;

	char buf[2048];

	memset(buf, 0, sizeof(buf));

	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
		perror("socket");
		return -1;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(22222);
	addr.sin_addr.s_addr = INADDR_ANY;

	if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0){
		perror("bind");
		return -1;
	}

	if(listen(sd, 10) < 0){
		perror("listen");
		return -1;
	}

	if((acc_sd) = accept(sd, (struct sockaddr *)&from_addr, &sin_size)) < 0 {
		perror("accept");
		return -1;
	}

	if(recv(acc_sc, buf, sizeof(buf), 0) < 0){
		perror("recv");
		return -1;
	}

	close(acc_sd);

	close(sd);

	printf("%s\n", buf);

	return 0;

}

client

#include 
#include 
#include 

int main(int argc, char** argv){
	int sd;
	struct sockaddr_in addr;

	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
		perror("socket");
		return -1;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(22222);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	connect(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));

	if(send(sd, "sending process", 17, 0) < 0){
		perror("send");
		return -1;
	}

	close(sd);

	return 0;
}

[C言語]バイナリファイル

パケットフィルタリングとは、通信機器やコンピュータの持つネットワーク制御機能の一つで、外部から受信したデータを管理者が設定した一定の基準に従って通したり破棄したりすること
Berkeley Packet Filterとは、ユーザランドからのコードをカーネル内で安全に実行する為の仕組み

$ grep BPF /boot/config-`uname -r`
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m

#include 
#include 
#include 
#include 
#include "bpf_load.h"
#include "sock_example.h"
#include 
#include 

int main(int ac, char **argv){

	char filename[256];
	FILE *f;
	int i, sock;

	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

	if(load_bpf_file(filename)){
		printf("%s", bpf_log_buf);
		return 1;
	}

	sock = open_raw_sock("lo");

	assert(setsockopt(sock, SQL_SOCKET, SO_ATTACH_BPF, prog_fd, sizeof(prog_fd[0])) == 0);

	f = popen("ping -c5 localhost", "r");
	(void) f;

	for(i = 0; i < 5; i++){
		long long tcp_cnt, udp_cnt, icmp_cnt;
		int key;

		key = IPPROTO_TCP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &tcp_cnt) == 0);

		key = IPPROTO_UDP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &udp_cnt) == 0);

		key = IPPROTO_ICMP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &icmp_cnt) == 0);

		printf("TCP %lld UDP %lld ICMP %lld bytes\n", tcp_cnt, udp_cnt, icmp_cnt);
		sleep(1);
	}

	return 0;
}

TCPとはIPと同様にインターネットにおいて標準的に利用されている プロトコル。TCPは、IPの上位プロトコルでトランスポート層で動作する。
ネットワーク層のIPとセッション層以上のプロトコル(HTTP、FTP、Telnetなど)の橋渡しをする

UDPはUser Datagram Protocolの略、アプリケーション同士が最小限の仕組みでデータを送受信するプロトコル、リアルタイム性が重要視される通信で使われる、送信者アドレスの偽装が容易であるためDNSなどを使ったDDoS攻撃で使われることも多い

ICMPはIPプロトコルの「エラー通知」や「制御メッセージ」を転送するためのプロトコル、TCP/IPが実装されたコンピュータ間で通信状態を確認するために使用

[C言語]バイナリファイル

0と1のビットの並びで表現されたファイルをバイナリファイルと呼ぶ。また、そのデータをバイナリデータと呼ぶ。
行を変えるという概念がない。

– エンディアン
2バイト以上あるデータをメモリ上に配置する時に、どのように並べるかというルールのことで、リトルエンディアンとビッグエンディアンがある。
「0x00 0x00 0x003 0x84」(ビッグエンディアン)と「0x84 0x003 0x00 0x00」(リトルエンディアン)
IntelのCPUはリトルエンディアン

#include <stdio.h>

int main(void){
	printf("%X\n", 'x');
	printf("%X\n", 'y');
	printf("%X\n", 'z');
}

– 読み書き
fopen関数に”b”を含む

#include
#include

int main(void){
FILE *fp = fopen(“test.bin”,”rb”);
if(fp == NULL){
fputs(“ファイルオープンに失敗しました。\n”, stderr);
exit(EXIT_FAILURE);
}

int num = 900;
double d = 7.85;
char str[] = “xyzxyz”;

if(fwrite(&num, sizeof(num), 1, fp) < 1){ fputs("1.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(&d, sizeof(d), 1, fp) < 1){ fputs("2.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(str, sizeof(str[0]),sizeof(str),fp) < sizeof(str)){ fputs("3.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fclose(fp) == EOF){ fputs("ファイルクローズに失敗しました。\n", stderr); exit(EXIT_FAILURE); } return 0; } [/code] $ ./test 1.ファイル書き込みに失敗しました。