changeset 0:42f240cc4bc6

From: 太田 篤志 <atoc@namikilab.tuat.ac.jp>
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 08 Sep 2009 13:44:18 +0900
parents
children b4285b887e18
files driver/Makefile driver/cdev_handler.c driver/cdev_handler.h driver/critical.c driver/critical.h driver/interrupt.c driver/interrupt.h driver/lspe.c driver/lspe.h driver/main.c driver/main.h driver/process_list.c driver/process_list.h driver/procfs/hypervisor.c driver/procfs/hypervisor.h driver/procfs/processes.c driver/procfs/processes.h include/hvcalls/common.h include/hvcalls/ppe.h include/hvcalls/repository.h include/hvcalls/spe.h include/ioctl.h include/spe_process.h kernel/Makefile kernel/convert kernel/entry.s kernel/kernel.c kernel/kernel.ld spe_programs/001_overhead/Makefile spe_programs/001_overhead/spe.c spe_programs/001_overhead/spe.ld spe_programs/002_qsort/Makefile spe_programs/002_qsort/spe.c spe_programs/002_qsort/spe.ld tests/001_090722/001.c tests/002_090722/002.c tests/003_090809/003.c tests/004_090809/004.c tests/005_forJSASS_1/005.c tests/005_forJSASS_1/005.exec tests/006_qsort/006.c
diffstat 41 files changed, 3964 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/Makefile	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,25 @@
+##
+## Makefile
+## SPE プロセスマネージャ用 Makefile
+##
+
+MODULE          = spe_manager
+KERNELDIR       = "/home/atoc/usr/src/linux-`uname -r`"
+#KERNELDIR       = "/lib/modules/`uname -r`/build"
+
+obj-m          := ${MODULE}.o
+clean-files    := *.o *.ko *.mod.[co] *~ Module.symvers
+${MODULE}-objs := main.o              \
+                  lspe.o              \
+                  critical.o          \
+                  process_list.o      \
+                  cdev_handler.o      \
+                  interrupt.o         \
+                  procfs/hypervisor.o \
+                  procfs/processes.o
+
+all:
+	$(MAKE) -C $(KERNELDIR) M=`pwd` modules
+
+clean:
+	$(MAKE) -C $(KERNELDIR) M=`pwd` clean
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/cdev_handler.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,351 @@
+/**
+ * cdev_handler.c
+ * SPE プロセスマネージャ spe_manager
+ * キャラクタデバイスのハンドラ
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/fs.h>          // struct inode, struct file
+#include <linux/kernel.h>      // printk
+//#include <linux/slab.h>        // kmalloc, kfree
+#include <linux/vmalloc.h>     // vmalloc, vfree
+#include <linux/semaphore.h>   // down_interruptible, up
+#include <linux/spinlock.h>    // spin_lock, spin_unlock
+#include <asm/uaccess.h>       // copy_from_user, copy_to_user
+
+#include "../include/spe_process.h"
+#include "../include/ioctl.h"
+#include "cdev_handler.h"
+#include "lspe.h"
+#include "main.h"
+#include "critical.h"
+#include "process_list.h"
+
+
+// SPE プロセス ID 割り当て用 (open ハンドラが実行されるたびに加算される)
+static int spe_pid = 0;
+
+
+
+//=================================================================================================== spe_manager_open()
+/**
+ * spe_manager_open
+ * キャラクタデバイス open イベントハンドラ
+ *
+ * @param  struct inode *  inode
+ * @param  struct file  *  filp
+ * @return int
+ */
+int spe_manager_open(struct inode *inode, struct file *filp)
+{
+	spe_process_context_list_t *this_process;
+	struct semaphore           *semaphore_for_spe_pid = get_semaphore_for_spe_pid();
+	struct semaphore           *semaphore_for_process_list = get_semaphore_for_process_list();
+
+
+	// SPE プロセスコンテキスト用のメモリを確保 (確保するまでにスリープするかもしれない)
+	if ((this_process = (spe_process_context_list_t *)vmalloc(sizeof(spe_process_context_list_t))) == NULL)
+	{
+		printk(KERN_ERR "[%s] Error: vmalloc() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		return -ENOSPC;
+	}
+
+	// SPE プロセスコンテキストの初期化
+	this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_OPENED;
+	this_process->prev_process        = NULL;
+	this_process->next_process        = NULL;
+//	this_process->context.read.spe_no = -1;   // 暫定
+
+
+//	Critical Section >>>
+	if (down_interruptible(semaphore_for_spe_pid))
+		goto spe_manager_open__error1;
+
+	// SPE プロセス ID 番号の割り当て
+	if ((this_process->context.read.spe_pid = ++spe_pid) < 0)
+	{
+	}
+
+	up(semaphore_for_spe_pid);
+//	<<< Critical Section
+
+
+//	Critical Section >>>
+	if (down_interruptible(semaphore_for_process_list))
+		goto spe_manager_open__error2;
+
+		increment_opened();
+
+	up(semaphore_for_process_list);
+//	<<< Critical Section
+
+
+	filp->private_data = (void *)this_process;
+	return 0;
+
+
+spe_manager_open__error2:
+spe_manager_open__error1:
+	return -ERESTARTSYS;
+}
+
+
+//================================================================================================== spe_manager_write()
+/**
+ * spe_manager_write
+ * キャラクタデバイス write イベントハンドラ
+ *
+ * @param  struct file *  filp
+ * @param  char        *  buf
+ * @param  size_t         count
+ * @param  loff_t      *  f_pos
+ * @return ssize_t
+ */
+ssize_t spe_manager_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
+{
+	spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data);
+	struct semaphore           *semaphore_for_process_list = get_semaphore_for_process_list();
+
+
+	if (this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_OPENED &&
+	     this_process->context.read.status != SPE_PROCESS_CONTEXT_STATUS_WRITTEN)
+	{
+		printk (
+			KERN_ERR "[%s] Error: spe_manager_write() can't be executed in the status. (%s:%u)\n",
+			SPE_MANAGER_MODULE_NAME,
+			__FILE__,
+			__LINE__
+		);
+		return -EFAULT;
+	}
+
+	//
+	// Note: (1) 以降の処理が実行されるのは、
+	//           SPE プロセスが OPENED 状態か WRITTEN 状態の時のみである。
+	//       (2) OPENED → WRITTEN の状態遷移は、
+	//           書き込みオフセットが spe_process_context_write_data_t のサイズぶん移動した際に行われる。
+	//           fseek 等でオフセットを移動してしまうとデータが不足したまま WRITTEN 状態になるおそれがあるので注意。
+	//
+
+	if (*f_pos >= sizeof(spe_process_context_write_data_t))
+	{
+//		Critical Section >>>
+		if (down_interruptible(semaphore_for_process_list))
+			goto spe_manager_write__error1;
+
+			decrement_opened();
+			increment_written();
+
+		up(semaphore_for_process_list);
+//		<<< Critical Section
+
+		// プロセス状態更新
+		this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN;
+		return 0;
+	}
+
+	if (*f_pos + count > sizeof(spe_process_context_write_data_t))
+		// そのまま転送するとサイズオーバーなので調節する
+		count = sizeof(spe_process_context_write_data_t) - *f_pos;
+
+	if (copy_from_user((void *)&(this_process->context.write) + *f_pos, buf, count))
+	{
+		printk(KERN_ERR "[%s] Error: copy_from_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		return -EFAULT;
+	}
+
+	if ((*f_pos += count) >= sizeof(spe_process_context_write_data_t))
+	{
+//		Critical Section >>>
+		if (down_interruptible(semaphore_for_process_list))
+			goto spe_manager_write__error1;
+
+			decrement_opened();
+			increment_written();
+
+		up(semaphore_for_process_list);
+//		<<< Critical Section
+
+		// プロセス状態更新
+		this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_WRITTEN;
+	}
+
+	return count;
+
+
+spe_manager_write__error1:
+	return -ERESTARTSYS;
+}
+
+
+//================================================================================================== spe_manager_ioctl()
+/**
+ * spe_manager_ioctl
+ * キャラクタデバイス ioctl イベントハンドラ [要修正]
+ *
+ * @param  struct inode  *  inode
+ * @param  struct file   *  filp
+ * @param  unsigned int     cmd
+ * @param  unsigned long    arg
+ * @return int
+ */
+int spe_manager_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	// マジック番号の判定
+	if (_IOC_TYPE(cmd) != SPE_MANAGER_IOCTL_MAGIC) return -ENOTTY;
+
+	switch (cmd)
+	{
+	// SPE プロセスを開始する
+	case SPE_MANAGER_IOCTL_START_PROCESS:
+		// データ転送方向判定
+		if (_IOC_DIR(cmd) != _IOC_NONE) return -ENOTTY;
+
+		{
+			spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data);
+			struct semaphore           *semaphore_for_process_list = get_semaphore_for_process_list();
+			spinlock_t                 *spinlock_for_process_list  = get_spinlock_for_process_list();
+			int i, lspe_count = get_lspe_count();
+
+
+//			Critical Section (semaphore) >>>
+			if (down_interruptible(semaphore_for_process_list))
+				goto spe_manager_ioctl__error1;
+
+				decrement_written();
+
+//				Critical Section (spinlock) >>>
+				spin_lock(spinlock_for_process_list);
+				{
+					for (i = 0; i < lspe_count; i++)
+					{
+						spe_process_context_list_t *running = get_running_process(i);
+
+						// この論理 SPE でプロセスが実行中ではないか
+						if (running == NULL)
+						{
+							// このプロセスを実行中にする
+//							this_process->context.read.spe_no = i;
+							this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING;
+
+							set_running_process(i, this_process);
+							break;
+						}
+					}
+					if (i >= lspe_count)
+					{
+						// 空きの SPE がなかったので実行待ちプロセスリストへ追加する
+						add_process_to_waiting(this_process);
+					}
+				}
+				spin_unlock(spinlock_for_process_list);
+//				<<< Critical Section (spinlock)
+
+			up(semaphore_for_process_list);
+//			<<< Critical Section (semaphore)
+
+
+			// SPE プロセス開始
+			if (i < lspe_count) start_spe_process(i, this_process);
+		}
+
+		break;
+
+	// それ以外のコマンド
+	default:
+		return -ENOTTY;
+	}
+
+	return 0;
+
+
+spe_manager_ioctl__error1:
+	return -ERESTARTSYS;
+}
+
+
+//=================================================================================================== spe_manager_read()
+/**
+ * spe_manager_read
+ * キャラクタデバイス read イベントハンドラ
+ *
+ * @param  struct file *  filp
+ * @param  char        *  buf
+ * @param  size_t         count
+ * @param  loff_t      *  f_pos
+ * @return ssize_t
+ */
+ssize_t spe_manager_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+	spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data);
+
+
+	if (*f_pos >= sizeof(spe_process_context_read_data_t))
+		// これ以上転送しない
+		return 0;
+
+	if (*f_pos + count > sizeof(spe_process_context_read_data_t))
+		// そのまま転送するとサイズオーバーなので調節する
+		count = sizeof(spe_process_context_read_data_t) - *f_pos;
+
+	if (copy_to_user(buf, (void *)&(this_process->context.read) + *f_pos, count))
+	{
+		printk(KERN_ERR "[%s] Error: copy_to_user() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		return -EFAULT;
+	}
+
+	*f_pos += count;
+	return count;
+}
+
+
+//================================================================================================ spe_manager_release()
+/**
+ * spe_manager_release
+ * キャラクタデバイス release イベントハンドラ
+ *
+ * @param  struct inode *  inode
+ * @param  struct file  *  filp
+ * @return int
+ */
+int spe_manager_release(struct inode *inode, struct file *filp)
+{
+	spe_process_context_list_t *this_process = (spe_process_context_list_t *)(filp->private_data);
+	struct semaphore           *semaphore_for_process_list = get_semaphore_for_process_list();
+	spinlock_t                 *spinlock_for_process_list  = get_spinlock_for_process_list();
+
+
+	//
+	//
+	// ToDo: SPE プロセスが NOT_RELEASED 状態でない時に
+	//       突然このハンドラが呼び出された場合の後始末
+	//
+	//
+
+
+//	Critical Section (semaphore) >>>
+	if (down_interruptible(semaphore_for_process_list))
+		goto spe_manager_release__error1;
+
+//		Critical Section (spinlock) >>>
+		spin_lock(spinlock_for_process_list);
+		{
+			decrement_not_released();
+		}
+		spin_unlock(spinlock_for_process_list);
+//		<<< Critical Section (spinlock)
+
+		increment_released();
+
+	up(semaphore_for_process_list);
+//	<<< Critical Section (semaphore)
+
+
+	// SPE プロセスコンテキストのためのメモリを解放
+	vfree(this_process);
+	return 0;
+
+
+spe_manager_release__error1:
+	return -ERESTARTSYS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/cdev_handler.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,21 @@
+/**
+ * cdev_handler.h
+ * SPE プロセスマネージャ spe_manager
+ * キャラクタデバイスのハンドラ
+ */
+
+#ifndef  SPE_MANAGER__CDEV_HANDLER_H
+#define  SPE_MANAGER__CDEV_HANDLER_H
+
+#include <linux/fs.h>
+
+
+// 外部から参照される関数
+int     spe_manager_open(struct inode *, struct file *);                                 // open
+ssize_t spe_manager_write(struct file *, const char __user *, size_t, loff_t *);         // write
+int     spe_manager_ioctl(struct inode *, struct file *, unsigned int, unsigned long);   // ioctl
+ssize_t spe_manager_read(struct file *, char __user *, size_t, loff_t *);                // read
+int     spe_manager_release(struct inode *, struct file *);                              // release
+
+
+#endif /*SPE_MANAGER__CDEV_HANDLER_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/critical.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,77 @@
+/**
+ * critical.c
+ * SPE プロセスマネージャ spe_manager
+ * クリティカルセクションに関する変数や関数など
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include "critical.h"
+
+
+static struct semaphore semaphore_for_spe_pid;        // SPE プロセス ID 用のセマフォ
+static struct semaphore semaphore_for_process_list;   // プロセスリスト更新用のセマフォ
+static spinlock_t       spinlock_for_process_list;    // 同スピンロック
+
+
+
+//================================================================================================ initialize_critical()
+/**
+ * initialize_critical
+ * クリティカルセクションに関する変数の初期化
+ *
+ * @return void
+ */
+void initialize_critical(void)
+{
+	init_MUTEX(&semaphore_for_spe_pid);
+	init_MUTEX(&semaphore_for_process_list);
+	spin_lock_init(&spinlock_for_process_list);
+}
+
+
+//========================================================================================== get_semaphore_for_spe_pid()
+/**
+ * get_semaphore_for_spe_pid
+ * SPE プロセス ID 番号用のセマフォを取得する
+ *
+ * Note: 単なるセマフォ変数の getter であり、ロックを行うわけではない。
+ *
+ * @return struct semaphore *
+ */
+struct semaphore *get_semaphore_for_spe_pid(void)
+{
+	return &semaphore_for_spe_pid;
+}
+
+
+//===================================================================================== get_semaphore_for_process_list()
+/**
+ * get_semaphore_for_process_list
+ * プロセスリスト更新用のセマフォを取得する
+ *
+ * Note: 単なるセマフォ変数の getter であり、ロックを行うわけではない。
+ *
+ * @return struct semaphore *
+ */
+struct semaphore *get_semaphore_for_process_list(void)
+{
+	return &semaphore_for_process_list;
+}
+
+
+//====================================================================================== get_spinlock_for_process_list()
+/**
+ * get_spinlock_for_process_list
+ * プロセスリスト更新用のスピンロックを取得する
+ *
+ * Note: 単なるスピンロック変数の getter であり、ロックを行うわけではない。
+ *
+ * @return spinlock_t *
+ */
+spinlock_t *get_spinlock_for_process_list(void)
+{
+	return &spinlock_for_process_list;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/critical.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,21 @@
+/**
+ * critical.h
+ * SPE プロセスマネージャ spe_manager
+ * クリティカルセクションに関する変数や関数など
+ */
+
+#ifndef  SPE_MANAGER__CRITICAL_H
+#define  SPE_MANAGER__CRITICAL_H
+
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+
+// 外部から参照される関数
+void initialize_critical(void);
+struct semaphore *get_semaphore_for_spe_pid(void);
+struct semaphore *get_semaphore_for_process_list(void);
+spinlock_t *get_spinlock_for_process_list(void);
+
+
+#endif /*SPE_MANAGER__CRITICAL_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/interrupt.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,253 @@
+/**
+ * interrupt.c
+ * SPE プロセスマネージャ spe_manager
+ * 割り込みハンドラ
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/kernel.h>      // printk
+#include <linux/slab.h>        // kmalloc, kfree
+#include <linux/interrupt.h>   // request_irq, free_irq
+#include <asm/ps3.h>           // ps3_irq_plug_setup, ps3_irq_plug_destroy
+#include <asm/io.h>            // ioremap, iounmap, in_xx, out_xx
+
+#include <asm/pgtable-ppc64.h> // 暫定
+#include <asm/mmu-hash64.h>    // 暫定
+
+#include "../include/hvcalls/spe.h"
+#include "interrupt.h"
+#include "lspe.h"
+#include "main.h"
+#include "critical.h"
+#include "process_list.h"
+
+
+
+
+
+
+
+
+//================================================================================================== interrupt_handler()
+/**
+ * interrupt_handler
+ * 割り込みハンドラ
+ *
+ * @param  int     irq
+ * @param  void *  dev_id
+ * @return irqreturn_t
+ */
+irqreturn_t interrupt_handler(int irq, void *dev_id)
+{
+	int           i, lspe_count = get_lspe_count();
+	unsigned long int_stat;
+
+
+	for (i = 0; i < lspe_count; i++)
+	{
+		lspe_data_t *lspe = get_lspe_data(i);
+		if (lspe == NULL) continue;
+
+		if (lspe->virq[0] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 0 割り込み
+			 *  (エラー)
+			 */
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 0, &int_stat);
+			int_stat &= spe_int_mask[0];
+			printk(KERN_INFO "[%s] INT_Stat_class0 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			/*
+			 * とりあえず今はやることなし
+			 */
+
+
+			// 割り込みステータスをクリア
+			hvc_clear_spe_int_stat(lspe->spe_id, 0, int_stat);
+			break;
+		}
+
+		if (lspe->virq[1] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 1 割り込み
+			 *  (変換)
+			 */
+			unsigned long mfc_dsisr, mfc_dar;
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 1, &int_stat);
+			int_stat &= spe_int_mask[1];
+//			printk(KERN_INFO "[%s] INT_Stat_class1 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			// MFC データ・ストレージ割り込みステータス・レジスタおよび
+			// MFC データ・アドレス・レジスタの値を取得
+			mfc_dsisr = in_be64(lspe->shadow + 0x0610 /*MFC_DSISR*/);
+			mfc_dar   = in_be64(lspe->shadow + 0x0620 /*MFC_DAR*/);
+//			printk(KERN_INFO "  MFC_DSISR = 0x%016lx\n", mfc_dsisr);
+//			printk(KERN_INFO "  MFC_DAR   = 0x%016lx\n", mfc_dar);
+
+
+
+
+
+
+			if (int_stat & 1)   // MFC データ・セグメントエラー
+			{
+				unsigned long esid = (mfc_dar & 0xFFFFFFFFF0000000UL) | 0x8000000UL /*[V]*/;
+
+				if (REGION_ID(mfc_dar) == USER_REGION_ID)
+				{
+					unsigned long vsid = get_vsid(lspe->mm->context.id, mfc_dar, MMU_SEGSIZE_256M);
+
+					// vsid を SLB エントリに登録
+					out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, lspe->slb_index);
+					out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid << 12 | 0xc00 /*Ks|Kp*/ | 0x80 /*C*/ | 0x000 /*L|LP*/);
+					out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, esid);
+
+					lspe->slb_index++;
+					if (lspe->slb_index >= 8) lspe->slb_index = 2;
+
+					// MFC コマンドの再始動
+					out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/);
+				}
+			}
+
+
+
+
+
+
+
+
+
+#if 0
+			// 割り込みステータスをクリア
+			if (int_stat & 2)
+			{
+				lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL);
+			}
+			hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat);
+
+
+			if (int_stat & 2)   // MFC データ・ストレージエラー
+			{
+				if (mfc_dsisr & 0x40000000 /*MFC_DSISR[M]*/)
+				{
+					if (REGION_ID(mfc_dar) != USER_REGION_ID)
+					{
+						int ret = hash_page(mfc_dar, _PAGE_PRESENT, 0x300);
+//						printk(KERN_INFO "hash_page() [kernel side] = %d\n", ret);
+						if (!ret)
+						{
+							// MFC コマンドの再始動
+							out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, 1UL<<32 /*[R]*/);
+						}
+					}
+				}
+			}
+#endif
+
+
+
+
+
+
+
+
+			// 割り込みステータスをクリア
+			if (int_stat & 2)
+				lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0610UL /*MFC_DSISR*/, 0UL);
+			hvc_clear_spe_int_stat(lspe->spe_id, 1, int_stat);
+			break;
+		}
+
+		if (lspe->virq[2] == (unsigned int)irq)
+		{
+			/**
+			 *  クラス 2 割り込み
+			 *  (アプリケーション)
+			 */
+			unsigned int spu_status, spu_npc, spu_stop_code;
+
+			// 割り込みステータスを取得
+			hvc_get_spe_int_stat(lspe->spe_id, 2, &int_stat);
+			int_stat &= spe_int_mask[2];
+//			printk(KERN_INFO "[%s] INT_Stat_class2 = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, int_stat);
+
+
+			// SPU ステータスおよびネクスト・プログラム・カウンタを取得
+			asm volatile("eieio");   // cf. Cell Broadband Engine アーキテクチャ version 1.01 (p.93)
+			spu_status    = in_be32(lspe->problem + 0x04024UL /*SPU_Status*/);
+			spu_stop_code = spu_status >> 16;
+			spu_npc       = in_be32(lspe->problem + 0x04034UL /*SPU_NPC*/);
+//			printk(KERN_INFO "  SPU_Status = 0x%08x\n", spu_status);
+//			printk(KERN_INFO "  StopCode   = 0x%04x\n", spu_stop_code);
+//			printk(KERN_INFO "  SPU_NPC    = 0x%08x\n", spu_npc);
+
+
+			if (spu_status & 1<<1 /*[P]*/)
+			{
+				switch (spu_stop_code)
+				{
+				case SPE_PROCESS_STOP_CODE_FINISH:
+					{
+						spe_process_context_list_t *this_process = get_running_process(i), *next_process = NULL;
+						spinlock_t                 *spinlock_for_process_list = get_spinlock_for_process_list();
+
+
+//						Critical Section (spinlock) >>>
+						spin_lock(spinlock_for_process_list);
+						{
+							next_process = get_next_waiting_process();
+
+/*
+							unsigned long addr;
+							for (addr = 0x0; addr < 0x0 + 0x60; addr+= 0x10)
+							{
+								printk(KERN_INFO "0x%04lx | %016lx %016lx\n", addr, in_be64(lspe->ls + addr), in_be64(lspe->ls + addr + 8));
+							}
+*/
+
+							// 実行プロセスコンテキストをクリア
+							clear_running_process(i);
+
+							// このプロセスのコンテキストを更新
+							this_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED;
+							increment_not_released();
+
+							// 実行待ちプロセスがあるか
+							if (next_process != NULL)
+							{
+								// このプロセスを実行中にする
+								remove_process_from_waiting(next_process);
+//								next_process->context.read.spe_no = i;
+								next_process->context.read.status = SPE_PROCESS_CONTEXT_STATUS_RUNNING;
+
+								set_running_process(i, next_process);
+							}
+						}
+						spin_unlock(spinlock_for_process_list);
+//						<<< Critical Section (spinlock)
+
+
+						// SPE プロセス開始
+						if (next_process != NULL) start_spe_process(i, next_process);
+					}
+				}
+			}
+
+			// 割り込みステータスをクリア
+			hvc_clear_spe_int_stat(lspe->spe_id, 2, int_stat);
+			break;
+		}
+	}
+
+	return IRQ_HANDLED;
+//	return int_stat ? IRQ_HANDLED : IRQ_NONE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/interrupt.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,23 @@
+/**
+ * interrupt.h
+ * SPE プロセスマネージャ spe_manager
+ * 割り込みハンドラ
+ */
+
+#ifndef  SPE_MANAGER__INTERRUPT_H
+#define  SPE_MANAGER__INTERRUPT_H
+
+#include <linux/interrupt.h>
+
+
+// 以下のストップコード定数は SPE 向け軽量カーネルではベタ書きのため
+// 変更の際は注意すること
+#define  SPE_PROCESS_STOP_CODE_FINISH  0x3FFD
+#define  SPE_PROCESS_STOP_CODE_ERROR   0x3FFE
+
+
+// 外部から参照される関数
+irqreturn_t interrupt_handler(int, void *);
+
+
+#endif /*SPE_MANAGER__INTERRUPT_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/lspe.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,299 @@
+/**
+ * lspe.c
+ * SPE プロセスマネージャ spe_manager
+ * 論理 SPE に関する処理
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/kernel.h>      // printk
+#include <linux/slab.h>        // kmalloc, kfree
+#include <linux/interrupt.h>   // request_irq, free_irq
+#include <asm/ps3.h>           // ps3_irq_plug_setup, ps3_irq_plug_destroy
+#include <asm/io.h>            // ioremap, iounmap
+
+#include <asm/pgtable-ppc64.h> // 暫定
+
+#include "../include/hvcalls/common.h"
+#include "../include/hvcalls/spe.h"
+#include "../include/hvcalls/repository.h"
+#include "lspe.h"
+#include "interrupt.h"
+#include "main.h"
+
+
+// 割り込みマスク値定数
+const HVC_u64 spe_int_mask[SPE_VIRQ_CLASS_MAX+1] = {
+	(HVC_u64)0x07,   // SPE クラス 0 割り込み (すべての要因をイネーブル)
+	(HVC_u64)0x0F,   // SPE クラス 1 割り込み (すべての要因をイネーブル)
+	(HVC_u64)0x0F    // SPE クラス 2 割り込み (INT_Mask_class2[B] はイネーブルにするとハング)
+};
+
+
+// 論理 SPE 用変数
+static int         lspe_count = 0;
+static lspe_data_t lspe_data[SPE_COUNT_MAX];
+
+
+// 内部で利用する関数
+static int initialize_logical_spe(const HVC_u64, const HVC_u64, const int, const HVC_u64, irq_handler_t);
+static void finalize_logical_spe(const int);
+
+
+
+//============================================================================================ initialize_logical_spes()
+/**
+ * initialize_logical_spes
+ * 論理 SPE の確保と初期化
+ *
+ * @param  HVC_u64  lpar_id  論理パーティション識別子
+ * @param  HVC_u64  vas_id   仮想アドレス識別子
+ * @return int
+ */
+int initialize_logical_spes(const HVC_u64 lpar_id, const HVC_u64 vas_id)
+{
+	for (
+		lspe_count = 0;
+		(SPE_COUNT_REQ && lspe_count < SPE_COUNT_REQ && lspe_count < SPE_COUNT_MAX) || (!SPE_COUNT_REQ && lspe_count < SPE_COUNT_MAX);
+		lspe_count++
+	)
+	{
+		int ret = initialize_logical_spe(lpar_id, vas_id, lspe_count, (HVC_u64)lspe_count, interrupt_handler);
+		if (ret)
+		{
+			printk (
+				KERN_NOTICE "[%s] Notice: spe%d.initialize_logical_spe() returned %d. (%s:%u)\n",
+				SPE_MANAGER_MODULE_NAME, lspe_count, ret, __FILE__, __LINE__
+			);
+			break;
+		}
+	}
+	return lspe_count;
+}
+
+
+//============================================================================================= initialize_logical_spe()
+/**
+ * initialize_logical_spe
+ * 論理 SPE の確保と初期化
+ *
+ * @param  HVC_u64        lpar_id          論理パーティション識別子
+ * @param  HVC_u64        vas_id           仮想アドレス空間識別子
+ * @param  int            n                SPE 番号 (0..x)
+ * @param  HVC_u64        spe_reserve_key  論理 SPE 予約キー (0..5)
+ * @param  irq_handler_t  irq_handler      論理 SPE 割り込みハンドラ
+ * @return int
+ * @static
+ */
+static int initialize_logical_spe (
+	const HVC_u64       lpar_id,
+	const HVC_u64       vas_id,
+	const int           n,
+	const HVC_u64       spe_reserve_key,
+	      irq_handler_t irq_handler
+)
+{
+	HVC_u64       TMP_spe_id, lpar_ls, lpar_problem, lpar_priv2, lpar_shadow;
+	HVC_u64       value1, spe_rsv;
+	HVC_u64       outlet[SPE_VIRQ_CLASS_MAX+1];
+	unsigned int  TMP_virq[SPE_VIRQ_CLASS_MAX+1];
+	char         *TMP_virq_dev_name[SPE_VIRQ_CLASS_MAX+1];
+	int           i, j;
+
+
+	if (n < 0 || n >= SPE_COUNT_MAX) return -1;
+
+	// 論理 SPE を生成
+	if (hvc_create_logical_spe(vas_id, &TMP_spe_id, &lpar_ls, &lpar_problem, &lpar_priv2, &lpar_shadow))
+	{
+		return -2;
+	}
+
+	// 論理 SPE 予約識別子を取得する
+	if (hvc_get_repository_node (
+		lpar_id,
+		hvc_make_repository_first_key("bi", 0), hvc_make_repository_key("spursv", 0), spe_reserve_key, 0,
+		&value1, &spe_rsv ))
+	{
+		hvc_destroy_logical_spe(TMP_spe_id);
+		return -3;
+	}
+
+	// 論理 SPE を利用可能状態にする
+	if (hvc_enable_logical_spe(TMP_spe_id, spe_rsv))
+	{
+		hvc_destroy_logical_spe(TMP_spe_id);
+		return -4;
+	}
+
+	// MFC ステート・レジスタ 1 (MFC_SR1) を設定
+//	lv1_set_spe_privilege_state_area_1_register(TMP_spe_id, 0UL, 0x33UL);   // S, R, T, D
+//	lv1_set_spe_privilege_state_area_1_register(TMP_spe_id, 0UL, 0x7bUL);   // TL, S, R, PR, T, D
+
+	for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++)
+	{
+		// SPE IRQ アウトレットを生成
+		if (hvc_create_spe_irq_outlet(TMP_spe_id, (HVC_u64)i, &outlet[i]))
+		{
+			for (j = 0; j < i; j++)
+			{
+				free_irq(TMP_virq[j], NULL);
+				kfree(TMP_virq_dev_name[j]);
+				ps3_irq_plug_destroy(TMP_virq[j]);
+				// Note: SPE IRQ アウトレットは解放できない?
+				//       (解放するためのハイパーバイザコールがない→論理 SPE を解放すればおk?)
+			}
+			hvc_disable_logical_spe(TMP_spe_id);
+			hvc_destroy_logical_spe(TMP_spe_id);
+			return -5;
+		}
+
+		// 仮想割り込み番号を生成 (カーネルの手助けを要する)
+		if (ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, outlet[i], &TMP_virq[i]))
+		{
+			for (j = 0; j < i; j++)
+			{
+				free_irq(TMP_virq[j], NULL);
+				kfree(TMP_virq_dev_name[j]);
+				ps3_irq_plug_destroy(TMP_virq[j]);
+				// Note: SPE IRQ アウトレットは解放できない?
+			}
+			hvc_disable_logical_spe(TMP_spe_id);
+			hvc_destroy_logical_spe(TMP_spe_id);
+			return -6;
+		}
+
+		// 割り込みハンドラの dev_name の準備
+		if ((TMP_virq_dev_name[i] = (char *)kmalloc(sizeof(char) * 32, GFP_KERNEL)) == NULL)
+		{
+			printk (
+				KERN_NOTICE "[%s] Notice: spe%d.kmalloc() returned NULL. (%s:%u)\n",
+				SPE_MANAGER_MODULE_NAME, n, __FILE__, __LINE__
+			);
+		}
+		else
+		{
+			sprintf(TMP_virq_dev_name[i], SPE_MANAGER_DEVICE_NAME " (spe%d_class%d)", n, i);
+		}
+
+		// 割り込みハンドラを登録
+		if (request_irq(TMP_virq[i], irq_handler, IRQF_DISABLED, TMP_virq_dev_name[i], NULL))
+		{
+			for (j = 0; j < i; j++)
+			{
+				free_irq(TMP_virq[j], NULL);
+				kfree(TMP_virq_dev_name[j]);
+				ps3_irq_plug_destroy(TMP_virq[j]);
+				// Note: SPE IRQ アウトレットは解放できない?
+			}
+			kfree(TMP_virq_dev_name[i]);
+			ps3_irq_plug_destroy(TMP_virq[i]);
+			// Note: SPE IRQ アウトレットは解放できない?
+			hvc_disable_logical_spe(TMP_spe_id);
+			hvc_destroy_logical_spe(TMP_spe_id);
+			return -7;
+		}
+
+		// SPE の割り込みマスクを設定
+		hvc_set_spe_int_mask(TMP_spe_id, (HVC_u64)i, spe_int_mask[i]);
+	}
+
+
+	// lspe_data の各フィールドに格納
+	lspe_data[n].spe_id = TMP_spe_id;
+	for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++)
+	{
+		lspe_data[n].virq[i]          = TMP_virq[i];
+		lspe_data[n].virq_dev_name[i] = TMP_virq_dev_name[i];
+	}
+	lspe_data[n].ls      = ioremap_flags(lpar_ls, lpar_problem - lpar_ls, _PAGE_NO_CACHE);
+	lspe_data[n].problem = ioremap(lpar_problem, lpar_priv2 - lpar_problem);
+	lspe_data[n].priv2   = ioremap(lpar_priv2, SPE_PRIV2_AREA_SIZE);
+	{
+		// Note: シャドウレジスタエリアはこのようにマップしないとレジスタの読み込み時に OS ごと落ちる
+		unsigned long shadow_flags = _PAGE_NO_CACHE | 3;
+		lspe_data[n].shadow = __ioremap(lpar_shadow, SPE_SHADOW_AREA_SIZE, shadow_flags);
+	}
+
+	// LS エリアを 0 クリア
+	memset(lspe_data[n].ls, 0, SPE_LS_AREA_SIZE);
+	asm volatile("eieio");
+
+
+	return 0;
+}
+
+
+//===================================================================================================== get_lspe_count()
+/**
+ * get_lspe_count
+ * 確保・初期化された論理 SPE の数を取得する
+ *
+ * @return int  論理 SPE 数
+ */
+int get_lspe_count(void)
+{
+	return lspe_count;
+}
+
+
+//====================================================================================================== get_lspe_data()
+/**
+ * get_lspe_data
+ * 確保・初期化された論理 SPE データを取得する
+ *
+ * Note: 引数 n に負数や確保した論理 SPE 以上のインデックスを指定した場合は NULL が返る。
+ *
+ * @param  int  n         SPE 番号 (0..x)
+ * @return lspe_data_t *  論理 SPE データへのポインタ
+ */
+lspe_data_t *get_lspe_data(const int n)
+{
+	return (n >= 0 && n < lspe_count) ? lspe_data + n : NULL;
+}
+
+
+//============================================================================================== finalize_logical_spes()
+/**
+ * finalize_logical_spes
+ * 論理 SPE の解放
+ *
+ * @return void
+ */
+void finalize_logical_spes(void)
+{
+	for (--lspe_count; lspe_count >= 0; lspe_count--)
+	{
+		finalize_logical_spe(lspe_count);
+	}
+}
+
+
+//=============================================================================================== finalize_logical_spe()
+/**
+ * finalize_logical_spe
+ * 論理 SPE の解放
+ *
+ * @param  int  n  SPE 番号 (0..x)
+ * @return void
+ * @static
+ */
+static void finalize_logical_spe(const int n)
+{
+	int i;
+
+
+	iounmap(lspe_data[n].ls);
+	iounmap(lspe_data[n].problem);
+	iounmap(lspe_data[n].priv2);
+
+	for (i = 0; i <= SPE_VIRQ_CLASS_MAX; i++)
+	{
+		free_irq(lspe_data[n].virq[i], NULL);
+		kfree(lspe_data[n].virq_dev_name[i]);
+		ps3_irq_plug_destroy(lspe_data[n].virq[i]);
+		// Note: SPE IRQ アウトレットは解放できない?
+	}
+
+	hvc_disable_logical_spe(lspe_data[n].spe_id);
+	hvc_destroy_logical_spe(lspe_data[n].spe_id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/lspe.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,52 @@
+/**
+ * lspe.h
+ * SPE プロセスマネージャ spe_manager
+ * 論理 SPE に関する設定情報とか
+ */
+
+#ifndef  SPE_MANAGER__SPE_H
+#define  SPE_MANAGER__SPE_H
+
+#include <linux/interrupt.h>     // request_irq, free_irq
+
+#include "../include/hvcalls/common.h"
+
+
+#define  SPE_COUNT_REQ         0         // SPE を確保する数 (0=as many as possible)
+#define  SPE_COUNT_MAX         6         // これ以上の数の SPE は確保しない
+#define  SPE_VIRQ_CLASS_MAX    2         // SPE 仮想割り込みクラス番号の最大値
+#define  SPE_LS_AREA_SIZE      0x40000   // LS エリアサイズ (256KB)
+#define  SPE_PRIV2_AREA_SIZE   0x20000   // 特権 2 レジスタエリアサイズ (128KB)
+#define  SPE_SHADOW_AREA_SIZE  0x1000    // シャドウレジスタエリアサイズ (4KB)
+
+/**
+ * lspe_data_t
+ * 論理 SPE データ
+ */
+typedef struct
+{
+	HVC_u64           spe_id;                                // 論理 SPE 識別子
+	void             *ls;                                    // マップされた LS エリアの先頭アドレス
+	void             *problem;                               // マップされたプロブレムステートレジスタエリアの先頭アドレス
+	void             *priv2;                                 // マップされた特権 2 レジスタエリアの先頭アドレス
+	void             *shadow;                                // マップされたシャドウレジスタエリアの先頭アドレス
+	unsigned int      virq[SPE_VIRQ_CLASS_MAX+1];            // 仮想割り込み番号
+	char             *virq_dev_name[SPE_VIRQ_CLASS_MAX+1];   // 割り込みの所有者 - spe_manager (spe0_class0) という形式
+
+	struct mm_struct *mm;  //debug
+	unsigned long     slb_index;  //debug
+}
+lspe_data_t;
+
+
+// 外部から参照される関数
+int initialize_logical_spes(const HVC_u64, const HVC_u64);
+int get_lspe_count(void);
+lspe_data_t *get_lspe_data(const int);
+void finalize_logical_spes(void);
+
+// 外部から参照されるグローバル変数
+extern const HVC_u64 spe_int_mask[SPE_VIRQ_CLASS_MAX+1];
+
+
+#endif /*SPE_MANAGER__SPE_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/main.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,513 @@
+/**
+ * main.c
+ * SPE プロセスマネージャ spe_manager
+ * spe_manager_init, spe_manager_exit
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/init.h>        // __init, __exit, module_init, module_exit
+#include <linux/kernel.h>      // printk
+#include <linux/fs.h>          // register_chrdev_region, unregister_chrdev_region
+#include <linux/cdev.h>        // cdev_init, cdev_add, cdev_del
+#include <linux/proc_fs.h>     // create_proc_entry, remove_proc_entry
+
+#include <asm/io.h>            // 暫定
+#include <asm/mmu-hash64.h>    // 暫定
+
+#include "../include/hvcalls/common.h"
+#include "../include/hvcalls/ppe.h"
+#include "../include/kernel.h"        // Note: SPE 向け軽量カーネルの make を必ず先に行うこと!!
+#include "main.h"
+#include "lspe.h"
+#include "cdev_handler.h"
+#include "procfs/hypervisor.h"
+#include "procfs/processes.h"
+#include "critical.h"
+#include "process_list.h"
+
+#include "../include/spe_process.h"   // 暫定
+
+MODULE_LICENSE("GPL");   // これがないと動かない… (^ω^#)ビキビキ
+
+
+// キャラクタデバイス用変数
+static struct cdev            spe_manager_cdev;
+static struct file_operations spe_manager_cdev_fopts = {
+	owner:   THIS_MODULE,
+	open:    spe_manager_open,
+	write:   spe_manager_write,
+	ioctl:   spe_manager_ioctl,
+	read:    spe_manager_read,
+	release: spe_manager_release
+};
+
+// procfs 用変数
+static struct proc_dir_entry *proc_base_dir, *proc_processes, *proc_hypervisor;
+
+
+// 内部で利用する関数
+static void transfer_spe_kernel(void);
+
+
+
+// 後で別ファイルに移す?
+void initialize_manager(void)
+{
+//	int i, lspe_count = get_lspe_count();
+
+
+
+	initialize_critical();
+//	initialize_spinlocks();
+	initialize_process_lists();
+
+	transfer_spe_kernel();
+
+
+/*
+	for (i = 0; i < lspe_count; i++)
+	{
+		lspe_data_t *lspe = get_lspe_data(i);
+
+		*(unsigned int *)(lspe->problem + 0x4034) = SPE_KERNEL_INITIAL_PC | 0x1;
+		asm volatile("eieio");
+		*(unsigned int *)(lspe->problem + 0x401c) = 1;
+	}
+	asm volatile("eieio");   // 一応(^^;
+*/
+}
+
+
+
+
+
+
+// 後で別ファイルに移す
+
+
+//===================================================================================== set_spu_channel_data_and_count()
+/**
+ * set_spu_channel_data_and_count
+ * SPU チャネル・データ・レジスタおよび SPU チャネル・カウント・レジスタを設定する
+ *
+ * @param  int            n      SPE 番号 (0..x)
+ * @param  unsigned long  index  SPU チャネル・インデックス
+ * @param  long           data   SPU チャネル・データの設定値 (負数の場合は設定しない)
+ * @param  long           count  SPU チャネル・カウントの設定値 (負数の場合は設定しない)
+ * @return void
+ */
+void set_spu_channel_data_and_count(const int n, const unsigned long index, const long data, const long count)
+{
+	lspe_data_t *lspe = get_lspe_data(n);
+
+	// SPU チャネル・インデックス・レジスタ
+	out_be64(lspe->priv2 + 0x4060, index);
+	asm volatile("eieio");
+
+	if (data >= 0)
+	{
+		// SPU チャネル・データ・レジスタ
+		out_be64(lspe->priv2 + 0x4070, (unsigned long)data);
+	}
+	if (count >= 0)
+	{
+		// SPU チャネル・カウント・レジスタ
+		out_be64(lspe->priv2 + 0x4068, (unsigned long)count);
+	}
+	asm volatile("eieio");
+}
+
+
+
+//================================================================================================== start_spe_process()
+/**
+ * start_spe_process
+ * SPE プロセスを開始する
+ *
+ * @param  int                           spe_no        論理 SPE 番号 (0..x)
+ * @param  spe_process_context_list_t *  this_process  開始するプロセスコンテキストへのポインタ
+ * @return void
+ */
+void start_spe_process(const int spe_no, spe_process_context_list_t *const this_process)
+{
+
+
+	unsigned long vsid_context, vsid_program;
+	struct task_struct *task;
+
+
+
+
+
+	lspe_data_t *lspe = get_lspe_data(spe_no);
+
+
+
+
+#if 0
+	// MFC コマンド・キュー・オペレーションを中断する
+	out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (0UL<<4 /*[Sm]*/ || 1UL<<0 /*[Sc]*/));
+	asm volatile ("eieio");
+	do
+	{
+		unsigned long in_cntl = in_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/);
+		if ((in_cntl & 3UL<<8 /*[Ss]*/) == 3UL<<8 /*11*/) break;
+	}
+	while(1);
+#endif
+
+	// MFC マルチソース同期レジスタをチェックする
+	out_be32(lspe->problem + 0x00000 /*MFC_MSSync*/, 1);
+	do
+	{
+		unsigned int in_mssync = in_be32(lspe->problem + 0x00000 /*MFC_MSSync*/);
+		if ((in_mssync & 1<<0 /*[S]*/) == 0) break;
+	}
+	while(1);
+
+#if 0
+	// MFC コマンドをパージ (除去) する
+	out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (1UL<<15 /*[Pc]*/ || 1UL<<4 /*[Sm]*/));
+	asm volatile ("eieio");
+	do
+	{
+		unsigned long in_cntl = in_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/);
+		if ((in_cntl & 3UL<<24 /*[Ps]*/) == 3UL<<24 /*11*/) break;
+	}
+	while(1);
+#endif
+
+	// SPU 特権制御レジスタを初期化 (SPU_PrivCntl[Le,A,S] = 0)
+	out_be64(lspe->priv2 + 0x04040 /*SPU_PrivCntl*/, 0UL);
+	asm volatile ("eieio");
+
+	// MFC ステート・レジスタ 1 (MFC_SR1) を初期化 (MFC_SR1[S,R,T,D] = 1)
+	lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0000UL /*MFC_SR1*/, 0x33UL);
+
+	// SPE SLB エントリを全て無効化
+	out_be64(lspe->priv2 + 0x01128 /*SLB_Invalidate_All*/, 0UL);
+
+	// SPU チャネル・データ・レジスタおよびチャネル・カウント・レジスタの初期化
+	set_spu_channel_data_and_count(spe_no,  0,  0,  0);
+	set_spu_channel_data_and_count(spe_no,  1,  0, -1);
+	set_spu_channel_data_and_count(spe_no,  3,  0,  0);
+	set_spu_channel_data_and_count(spe_no,  4,  0,  0);
+	set_spu_channel_data_and_count(spe_no, 21, -1, 16);
+	set_spu_channel_data_and_count(spe_no, 23, -1,  1);
+	set_spu_channel_data_and_count(spe_no, 24,  0,  0);
+	set_spu_channel_data_and_count(spe_no, 25,  0,  0);
+	set_spu_channel_data_and_count(spe_no, 27,  0,  0);
+	set_spu_channel_data_and_count(spe_no, 28, -1,  1);
+	set_spu_channel_data_and_count(spe_no, 29, -1,  0);
+	set_spu_channel_data_and_count(spe_no, 30, -1,  1);
+
+	// 特権 1 レジスタ MFC_TClass_ID の初期化
+	lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0820UL /*MFC_TClass_ID*/, 0x10000000UL);
+	asm volatile ("eieio");
+
+	// MFC コマンド・キュー・オペレーションを再開
+	out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (0UL<<4 /*[Sm]*/ || 0UL<<0 /*[Sc]*/));
+
+
+
+
+
+
+
+
+//	this_process->context.read.ret = 0xDEADBEEFDEADBEEF;
+//	asm volatile("sync");
+
+
+
+
+/*
+	unsigned long       vsid_process, vsid_program;//, vsid_data;
+	uint64_t            esid_data;
+	unsigned long       i;
+	HVC_u64 ret;
+*/
+
+
+
+	// SPE プロセスコンテキストのある実効アドレスに対応する仮想セグメント ID (vsid) を取得
+	vsid_context = get_kernel_vsid((unsigned long)(&(this_process->context)), 0);
+//	vsid_context = get_kernel_vsid((unsigned long)(&(this_process->context)), sizeof(spe_process_context_t));
+//	printk(KERN_INFO "[%s] ADDR(this_process->context) = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, (unsigned long)(&(this_process->context)));
+//	printk(KERN_INFO "[%s] vsid_context                = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_context);
+
+/*
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x00), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x08));
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x10), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x18));
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x20), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x28));
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x30), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x38));
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x40), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x48));
+	printk(KERN_INFO "%016lx %016lx\n",  *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x50), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x58));
+*/
+
+
+
+	// 登録側プロセスにある SPE プログラムの実効アドレスに対応する仮想セグメント ID (vsid) を取得
+	vsid_program = get_vsid(current->mm->context.id, this_process->context.write.pgm_start, 0);
+//	printk(KERN_INFO "[%s] pid                         = %d\n",       SPE_MANAGER_MODULE_NAME, current->pid);
+//	printk(KERN_INFO "[%s] context.write.pgm_start     = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, this_process->context.write.pgm_start);
+//	printk(KERN_INFO "[%s] vsid_program                = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_program);
+/*
+	for_each_process(task)
+	{
+		if (task->pid == this_process->context.write.pid)
+		{
+			vsid_program = get_vsid(task->mm->context.id, (unsigned long)(this_process->context.write.pgm_start), 0);
+//			vsid_program = get_vsid(task->mm->context.id, (unsigned long)(process->write.program_start), (size_t)(process->write.program_size));
+			printk(KERN_INFO "[%s] pid                         = %d\n",       SPE_MANAGER_MODULE_NAME, task->pid);
+			printk(KERN_INFO "[%s] current->pid                = %d\n",       SPE_MANAGER_MODULE_NAME, current->pid);
+			printk(KERN_INFO "[%s] vsid_program                = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_program);
+			break;
+		}
+	}
+*/
+
+
+
+	// SPE SLB エントリを全て無効化
+//	out_be64(lspe->priv2 + 0x01128 /*SLB_Invalidate_All*/, 0UL);
+
+	// vsid_context を SLB エントリに登録
+	out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, 0UL);
+	out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid_context << 12 | 0x400 /*Kp*/ | 0x000 /*L|LP*/);
+	out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, (unsigned long)(&(this_process->context)) & 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/);
+//	out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/);
+
+	// vsid_program を SLB エントリに登録
+	out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, 1UL);
+	out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid_program << 12 | 0xc00 /*Ks|Kp*/ | 0x80 /*C*/ | 0x000 /*L|LP*/);
+	out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, this_process->context.write.pgm_start & 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/);
+//	out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, 0xFFFFFFFFE0000000UL | 0x8000000UL /*V*/);
+
+	// Note: カーネル空間の vsid には Kp ビット、ユーザ空間の vsid には Ks, Kp, C ビットを付ける。
+	//       (cf. arch/powerpc/platforms/cell/spu_base.c の __spu_trap_data_seg 関数)
+
+
+
+	lspe->mm        = current->mm;
+	lspe->slb_index = 2;
+
+
+/*
+	// vsid_data 登録
+	esid_data = process->write.data_start;
+	for (i = 2UL; i < 16UL; i++, esid_data += 0x10000000UL)
+	{
+		vsid_data = get_vsid(task->mm->context.id, (unsigned long)esid_data);
+		if (vsid_data == vsid_program) continue;
+
+		*(unsigned long *)(spe_priv2[spe_no] + 0x01108UL) = i;                                // SLB_Index
+		*(unsigned long *)(spe_priv2[spe_no] + 0x01118UL) = vsid_data << 12;                  // SLB_VSID
+		*(unsigned long *)(spe_priv2[spe_no] + 0x01110UL) = esid_data & 0xfffffffff0000000UL | 0x8000000UL;
+	}
+*/
+
+
+
+	// SPE プロセスコンテキストのある実効アドレスは LS の所定の位置に格納
+	out_be64(lspe->ls + SPE_KERNEL_PROC_CONTEXT_OFFSET, (unsigned long)(&(this_process->context)));
+//	out_be32(lspe->ls + SPE_KERNEL_PROC_CONTEXT_OFFSET, (unsigned int)((unsigned long)(&(this_process->context)) & 0xFFFFFFFUL));
+
+/*
+	// 登録側プロセスにある SPE プログラムの実効アドレスの下位 28bit は LS の所定の位置に格納
+	out_be32(lspe->ls + SPE_KERNEL_PROGRAM_OFFSET, (unsigned int)((unsigned long)(this_process->context.write.pgm_start) & 0xFFFFFFFUL));
+*/
+
+	asm volatile ("eieio");
+
+
+	out_be32(lspe->problem + 0x0000 /*MFC_MSSync*/, 1);
+	do
+	{
+		unsigned int r = in_be32(lspe->problem + 0x0000 /*MFC_MSSync*/);
+		if (r == 0) break;
+	}
+	while(1);
+
+	// SPE の実行を開始
+	out_be32(lspe->problem + 0x4034 /*SPU_NPC*/, SPE_KERNEL_INITIAL_PC | 0x1);
+	out_be32(lspe->problem + 0x401c /*SPU_RunCntl*/, 1);
+}
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================== spe_manager_init()
+/**
+ * spe_manager_init
+ * デバイスの初期化
+ *
+ * Note: 以下に示す外部関数参照がある。
+ *         procfs_handler_processes_read (procfs_handler.c)
+ *         hvc_get_lpar_id
+ *         hvc_get_ppe_id
+ *         hvc_get_vas_id
+ *         initialize_logical_spes (lspe.c)
+ *         initialize_manager
+ *
+ * @return int
+ * @static
+ */
+static int __init spe_manager_init(void)
+{
+	HVC_u64 lpar_id, ppe_id, vas_id;
+	int     spes;
+
+
+	//-------------------- キャラクタデバイスの登録
+	if (register_chrdev_region(SPE_MANAGER_DEVICE_ID, 1, SPE_MANAGER_DEVICE_NAME))
+	{
+		printk(KERN_ERR "[%s] Error: register_chrdev_region() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		// デバイス番号の割り当てができない
+		return -ENODEV;
+	}
+	cdev_init(&spe_manager_cdev, &spe_manager_cdev_fopts);
+	spe_manager_cdev.owner = THIS_MODULE;
+	if (cdev_add(&spe_manager_cdev, SPE_MANAGER_DEVICE_ID, 1))
+	{
+		printk(KERN_ERR "[%s] Error: cdev_add() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// キャラクタデバイスを追加できない
+		return -ENODEV;
+	}
+
+
+	//-------------------- procfs エントリの生成 (デバッグ用途)
+	if (!(proc_base_dir = proc_mkdir(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL)))
+	{
+		printk(KERN_ERR "[%s] Error: proc_mkdir() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		cdev_del(&spe_manager_cdev);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// procfs ディレクトリを生成できない
+		return -ENODEV;
+	}
+
+	if (!(proc_hypervisor = create_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, 0444, proc_base_dir)))
+	{
+		printk(KERN_ERR "[%s] Error: create_proc_entry() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL);
+		cdev_del(&spe_manager_cdev);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// procfs エントリを生成できない
+		return -ENODEV;
+	}
+	proc_hypervisor->owner      = THIS_MODULE;
+	proc_hypervisor->read_proc  = procfs_hypervisor_read;
+	proc_hypervisor->write_proc = NULL;
+
+	if (!(proc_processes = create_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, 0444, proc_base_dir)))
+	{
+		printk(KERN_ERR "[%s] Error: create_proc_entry() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir);
+		remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL);
+		cdev_del(&spe_manager_cdev);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// procfs エントリを生成できない
+		return -ENODEV;
+	}
+	proc_processes->owner      = THIS_MODULE;
+	proc_processes->read_proc  = procfs_processes_read;
+	proc_processes->write_proc = NULL;
+
+
+
+	// 論理パーティション識別子, 論理 PPE 識別子, 仮想アドレス識別子 の取得
+	hvc_get_lpar_id(&lpar_id);
+	hvc_get_ppe_id(&ppe_id);
+	if (hvc_get_vas_id(ppe_id, &vas_id))
+	{
+		printk(KERN_ERR "[%s] Error: hvc_get_vas_id() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+		remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir);
+		remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir);
+		remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL);
+		cdev_del(&spe_manager_cdev);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// 仮想アドレス識別子を取得できない
+		return -ENODEV;
+	}
+
+	// 論理 SPE の確保と初期化
+	if ((spes = initialize_logical_spes(lpar_id, vas_id)) < 1)
+	{
+		printk(KERN_ERR "[%s] Error: initialize_logical_spes() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+//		finalize_logical_spes();   // 1 つも確保できていないから不要
+		remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir);
+		remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir);
+		remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL);
+		cdev_del(&spe_manager_cdev);
+		unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+		// 使用できる論理 SPE がない
+		return -ENOSPC;
+	}
+
+	// SPE プロセスマネージャの初期化
+	initialize_manager();
+
+
+	printk(KERN_INFO "[%s] The module is loaded.\n", SPE_MANAGER_MODULE_NAME);
+	return 0;
+}
+
+
+//=================================================================================================== spe_manager_exit()
+/**
+ * spe_manager_exit
+ * キャラクタデバイス解放
+ *
+ * Note: 以下に示す外部関数参照がある。
+ *         finalize_logical_spes (lspe.c)
+ *
+ * @return void
+ * @static
+ */
+static void __exit spe_manager_exit(void)
+{
+	// 論理 SPE の後始末
+	finalize_logical_spes();
+	// procfs エントリとディレクトリの解放
+	remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir);
+	remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir);
+	remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL);
+	// キャラクタデバイスの削除
+	cdev_del(&spe_manager_cdev);
+	unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1);
+
+
+	printk(KERN_INFO "[%s] The module is unloaded.\n", SPE_MANAGER_MODULE_NAME);
+}
+
+
+module_init(spe_manager_init);
+module_exit(spe_manager_exit);
+
+
+
+//================================================================================================ transfer_spe_kernel()
+/**
+ * transfer_spe_kernel
+ * SPE 向け軽量カーネルを論理 SPE へ転送する
+ *
+ * @return void
+ * @static
+ */
+static void transfer_spe_kernel(void)
+{
+	int i, lspe_count = get_lspe_count();
+	for (i = 0; i < lspe_count; i++)
+	{
+		lspe_data_t *lspe = get_lspe_data(i);
+		memcpy(lspe->ls, spe_kernel_raw, SPE_KERNEL_SIZE);
+	}
+	asm volatile("eieio");   // 一応(^^;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/main.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,29 @@
+/**
+ * main.h
+ * SPE プロセスマネージャ spe_manager
+ * 設定情報とか
+ */
+
+#ifndef  SPE_MANAGER__MAIN_H
+#define  SPE_MANAGER__MAIN_H
+
+#include "../include/spe_process.h"   // 暫定
+
+
+#define  SPE_MANAGER_MAJOR                         240
+#define  SPE_MANAGER_MINOR                         0
+#define  SPE_MANAGER_DEVICE_ID                     MKDEV(SPE_MANAGER_MAJOR, SPE_MANAGER_MINOR)
+
+#define  SPE_MANAGER_MODULE_NAME                   "spe_manager"
+#define  SPE_MANAGER_DEVICE_NAME                   "spe_manager"
+#define  SPE_MANAGER_PROCFS_BASE_DIR_NAME          "spe_manager"
+#define  SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME  "hypervisor"
+#define  SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME   "processes"
+//#define  SPE_MANAGER_ENTRY_NAME   "spe_manager"
+
+
+// 後でファイルに移す
+void start_spe_process(const int, spe_process_context_list_t *const);
+
+
+#endif /*SPE_MANAGER__MAIN_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/process_list.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,355 @@
+/**
+ * process_list.c
+ * SPE プロセスマネージャ spe_manager
+ * プロセスリストとそれを扱うインライン関数など
+ */
+
+#include <linux/module.h>     // カーネルモジュール全般
+
+#include "../include/spe_process.h"
+#include "process_list.h"
+#include "lspe.h"
+
+
+// プロセスの各状態ごとの番兵ノード
+//static spe_process_context_list_t sentry_opened;
+//static spe_process_context_list_t sentry_written;
+static spe_process_context_list_t sentry_waiting;
+//static spe_process_context_list_t sentry_not_released;
+
+// 各論理 SPE が実行しているプロセスのコンテキスト
+static spe_process_context_list_t *running_process[SPE_COUNT_MAX];
+
+// プロセスの各状態ごとのプロセス数
+// (running はその都度 running_process を確かめるので不要)
+static int count_opened       = 0;
+static int count_written      = 0;
+static int count_waiting      = 0;
+static int count_not_released = 0;
+static int count_released     = 0;
+
+
+
+//=========================================================================================== initialize_process_lists()
+/**
+ * initialize_process_lists
+ * プロセスリストの初期化
+ *
+ * @return void
+ */
+void initialize_process_lists(void)
+{
+	int i, lspe_count = get_lspe_count();
+
+
+	// 番兵初期化 (自分自身を指しておく)
+//	sentry_opened.prev_process       = sentry_opened.next_process       = &sentry_opened;
+//	sentry_written.prev_process      = sentry_written.next_process      = &sentry_written;
+	sentry_waiting.prev_process      = sentry_waiting.next_process      = &sentry_waiting;
+//	sentry_not_released.prev_process = sentry_not_released.next_process = &sentry_not_released;
+
+	// 各論理 SPE の実行プロセスポインタを初期化
+	for (i = 0; i < lspe_count; i++)
+		clear_running_process(i);
+}
+
+
+//=================================================================================================== increment_opened()
+/**
+ * increment_opened
+ * OPENED 状態のプロセス数を 1 加算する
+ *
+ * @return void
+ */
+void increment_opened(void)
+{
+	count_opened++;
+}
+
+
+//=================================================================================================== decrement_opened()
+/**
+ * decrement_opened
+ * OPENED 状態のプロセス数を 1 減算する
+ *
+ * @return void
+ */
+void decrement_opened(void)
+{
+	count_opened--;
+}
+
+
+
+//================================================================================================== increment_written()
+/**
+ * increment_written
+ * WRITTEN 状態のプロセス数を 1 加算する
+ *
+ * @return void
+ */
+void increment_written(void)
+{
+	count_written++;
+}
+
+
+//================================================================================================== decrement_written()
+/**
+ * decrement_written
+ * WRITTEN 状態のプロセス数を 1 減算する
+ *
+ * @return void
+ */
+void decrement_written(void)
+{
+	count_written--;
+}
+
+
+
+//============================================================================================= add_process_to_waiting()
+/**
+ * add_process_to_waiting
+ * WAITING 状態のプロセスリストに SPE プロセスを加える
+ *
+ * Note: これと同時に count_waiting が 1 加算される。
+ *
+ * @return void
+ */
+void add_process_to_waiting(spe_process_context_list_t *this_process)
+{
+	// リスト更新
+	this_process->prev_process                = sentry_waiting.prev_process;
+	this_process->next_process                = &sentry_waiting;
+	sentry_waiting.prev_process->next_process = this_process;
+	sentry_waiting.prev_process               = this_process;
+	// プロセス数加算
+	count_waiting++;
+}
+
+
+//=========================================================================================== get_next_waiting_process()
+/**
+ * get_next_waiting_process
+ * WAITING 状態のプロセスリストの先頭にあるプロセスを取得する
+ *
+ * Note: WAITING 状態のプロセスがない場合は NULL になる。
+ *
+ * Note: WAITING 状態のプロセスを返すだけで、他の処理は何も行わない。
+ *       適宜 remove_process_from_waiting 関数などを実行すること。
+ *
+ * @return spe_process_context_list_t *
+ */
+spe_process_context_list_t *get_next_waiting_process(void)
+{
+	spe_process_context_list_t *next_process = sentry_waiting.next_process;
+
+	return (next_process == &sentry_waiting) ? NULL : next_process;
+}
+
+
+//======================================================================================== remove_process_from_waiting()
+/**
+ * remove_process_from_waiting
+ * WAITING 状態のプロセスリストから SPE プロセスを取り除く
+ *
+ * Note: これと同時に count_waiting が 1 減算される。
+ *
+ * @return void
+ */
+void remove_process_from_waiting(spe_process_context_list_t *this_process)
+{
+	// リスト更新
+	this_process->prev_process->next_process = this_process->next_process;
+	this_process->next_process->prev_process = this_process->prev_process;
+	// プロセス数減算
+	count_waiting--;
+}
+
+
+
+//================================================================================================ get_running_process()
+/**
+ * get_running_process
+ * 論理 SPE が現在実行しているプロセスのコンテキストを取得する
+ *
+ * @param  int  n                        SPE 番号 (0..x)
+ * @return spe_process_context_list_t *  実行中プロセスコンテキストへのポインタ (実行していない場合は NULL)
+ */
+spe_process_context_list_t *get_running_process(const int n)
+{
+	return running_process[n];
+}
+
+
+//================================================================================================ set_running_process()
+/**
+ * set_running_process
+ * 論理 SPE が現在実行しているプロセスのコンテキストを設定する
+ *
+ * @param  int  n                               SPE 番号 (0..x)
+ * @param  spe_process_context_list_t *process  プロセスコンテキストへのポインタ
+ * @return void
+ */
+void set_running_process(const int n, const spe_process_context_list_t *const process)
+{
+	running_process[n] = process;
+}
+
+
+//============================================================================================== clear_running_process()
+/**
+ * clear_running_process
+ * 論理 SPE が現在実行しているプロセスを初期化する
+ *
+ * @param  int  n  SPE 番号 (0..x)
+ * @return void
+ */
+void clear_running_process(const int n)
+{
+	running_process[n] = NULL;
+}
+
+
+
+
+
+
+//============================================================================================= increment_not_released()
+/**
+ * increment_not_released
+ * NOT_RELEASED 状態のプロセス数を 1 加算する
+ *
+ * @return void
+ */
+void increment_not_released(void)
+{
+	count_not_released++;
+}
+
+
+//============================================================================================= decrement_not_released()
+/**
+ * decrement_not_released
+ * NOT_RELEASED 状態のプロセス数を 1 減算する
+ *
+ * @return void
+ */
+void decrement_not_released(void)
+{
+	count_not_released--;
+}
+
+
+
+//================================================================================================= increment_released()
+/**
+ * increment_released
+ * RELEASED 状態のプロセス数を 1 加算する
+ *
+ * @return void
+ */
+void increment_released(void)
+{
+	count_released++;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//=========================================================================================== get_process_count_opened()
+/**
+ * get_process_count_opened
+ * OPENED 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_opened(void)
+{
+	return count_opened;
+}
+
+
+//========================================================================================== get_process_count_written()
+/**
+ * get_process_count_written
+ * WRITTEN 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_written(void)
+{
+	return count_written;
+}
+
+
+//========================================================================================== get_process_count_waiting()
+/**
+ * get_process_count_waiting
+ * WAITING 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_waiting(void)
+{
+	return count_waiting;
+}
+
+
+//========================================================================================== get_process_count_running()
+/**
+ * get_process_count_running
+ * RUNNING 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_running(void)
+{
+	int i, lspe_count = get_lspe_count(), ret = 0;
+	for (i = 0; i < lspe_count; i++)
+	{
+		if (running_process[i] != NULL) ret++;
+	}
+	return ret;
+}
+
+
+//===================================================================================== get_process_count_not_released()
+/**
+ * get_process_count_not_released
+ * NOT_RELEASED 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_not_released(void)
+{
+	return count_not_released;
+}
+
+
+//========================================================================================= get_process_count_released()
+/**
+ * get_process_count_released
+ * RELEASED 状態のプロセス数を取得する
+ *
+ * @return int
+ */
+int get_process_count_released(void)
+{
+	return count_released;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/process_list.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,37 @@
+/**
+ * process_list.h
+ * SPE プロセスマネージャ spe_manager
+ * プロセスリストとそれを扱うインライン関数など
+ */
+
+#ifndef  SPE_MANAGER__PROCESS_LIST_H
+#define  SPE_MANAGER__PROCESS_LIST_H
+
+#include "../include/spe_process.h"
+
+
+// 外部から参照される関数
+void                        initialize_process_lists(void);
+void                        increment_opened(void);
+void                        decrement_opened(void);
+void                        increment_written(void);
+void                        decrement_written(void);
+void                        add_process_to_waiting(spe_process_context_list_t *);
+spe_process_context_list_t *get_next_waiting_process(void);
+void                        remove_process_from_waiting(spe_process_context_list_t *);
+spe_process_context_list_t *get_running_process(const int);
+void                        set_running_process(const int, const spe_process_context_list_t *const);
+void                        clear_running_process(const int);
+void                        increment_not_released(void);
+void                        decrement_not_released(void);
+void                        increment_released(void);
+
+int get_process_count_opened(void);
+int get_process_count_written(void);
+int get_process_count_waiting(void);
+int get_process_count_running(void);
+int get_process_count_not_released(void);
+int get_process_count_released(void);
+
+
+#endif /*SPE_MANAGER__PROCESS_LIST_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/procfs/hypervisor.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,85 @@
+/**
+ * hypervisor.c
+ * SPE プロセスマネージャ spe_manager
+ * procfs エントリ "hypervisor" のハンドラ
+ */
+
+#include <linux/module.h>     // カーネルモジュール全般
+#include <linux/kernel.h>     // printk
+#include <linux/spinlock.h>   // spin_lock, spin_unlock
+
+#include "../../include/hvcalls/common.h"
+#include "../../include/hvcalls/ppe.h"
+#include "../main.h"
+#include "../lspe.h"
+#include "hypervisor.h"
+
+
+
+//============================================================================================= procfs_hypervisor_read()
+/**
+ * procfs_hypervisor_read
+ * procfs エントリ "hypervisor" の read イベントハンドラ
+ *
+ * @param  char *   page
+ * @param  char **  start
+ * @param  off_t    off
+ * @param  int      count
+ * @param  int *    eof
+ * @param  void *   data
+ * @return int
+ */
+int procfs_hypervisor_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	HVC_u64 lpar_id, ppe_id, vas_id;
+	int     lspe;
+	int     i, length = 0;
+
+
+
+	//----- 論理パーティション識別子, 論理 PPE 識別子, 仮想アドレス識別子 --------------------------
+	hvc_get_lpar_id(&lpar_id);
+	hvc_get_ppe_id(&ppe_id);
+	if (hvc_get_vas_id(ppe_id, &vas_id))
+	{
+		printk(KERN_ERR "[%s] Error: hvc_get_vas_id() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__);
+	}
+	length += sprintf (
+		page + length,
+		"                           Value\n"
+		"---------------------------------\n"
+		" Logical Partition ID      %5lu\n"
+		" Logical PPE ID            %5lu\n"
+		" Virtual Address Space ID  %5lu\n"
+		"---------------------------------\n"
+		"\n",
+		lpar_id, ppe_id, vas_id
+	);
+
+	//----- 論理 SPE -------------------------------------------------------------------------------
+	length += sprintf (
+		page + length,
+		"Logical SPEs...\n"
+		"\n"
+		" No.  SPE ID  LS Addr             ProbStateReg Addr   Privilege2 Addr\n"
+		"-------------------------------------------------------------------------\n"
+	);
+	lspe = get_lspe_count();
+	for (i = 0; i < lspe; i++)
+	{
+		lspe_data_t *data = get_lspe_data(i);
+		length += sprintf (
+			page + length,
+			"  #%d  %6lu  0x%016lx  0x%016lx  0x%016lx\n",
+			i, data->spe_id, (unsigned long)(data->ls), (unsigned long)(data->problem), (unsigned long)(data->priv2)
+		);
+	}
+	length += sprintf (
+		page + length,
+		"-------------------------------------------------------------------------\n"
+	);
+
+
+	*eof = 1;
+	return length;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/procfs/hypervisor.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,17 @@
+/**
+ * hypervisor.h
+ * SPE プロセスマネージャ spe_manager
+ * procfs エントリ "hypervisor" のハンドラ
+ */
+
+#ifndef  SPE_MANAGER__PROCFS__HYPERVISOR_H
+#define  SPE_MANAGER__PROCFS__HYPERVISOR_H
+
+#include <linux/types.h>
+
+
+// 外部から参照される関数
+int procfs_hypervisor_read(char *, char **, off_t, int, int *, void *);
+
+
+#endif /*SPE_MANAGER__PROCFS__HYPERVISOR_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/procfs/processes.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,84 @@
+/**
+ * processes.c
+ * SPE プロセスマネージャ spe_manager
+ * procfs エントリ "processes" のハンドラ
+ */
+
+#include <linux/module.h>      // カーネルモジュール全般
+#include <linux/kernel.h>      // printk
+#include <linux/semaphore.h>   // down_interruptible, up
+#include <linux/spinlock.h>    // spin_lock, spin_unlock
+
+#include "../main.h"
+#include "../critical.h"
+#include "../process_list.h"
+#include "processes.h"
+
+
+
+//============================================================================================== procfs_processes_read()
+/**
+ * procfs_processes_read
+ * procfs エントリ "processes" の read イベントハンドラ
+ *
+ * @param  char *   page
+ * @param  char **  start
+ * @param  off_t    off
+ * @param  int      count
+ * @param  int *    eof
+ * @param  void *   data
+ * @return int
+ */
+int procfs_processes_read(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	int               opened, written, waiting, running, not_released, released;
+	struct semaphore *semaphore_for_process_list = get_semaphore_for_process_list();
+	spinlock_t       *spinlock_for_process_list  = get_spinlock_for_process_list();
+
+
+//	Critical Section (semaphore) >>>
+	if (down_interruptible(semaphore_for_process_list))
+		goto procfs_processes_read__error1;
+
+		// 各 SPE プロセス状態のプロセス数を取得 (セマフォをロックするだけで取得可能なもの)
+		opened   = get_process_count_opened();
+		written  = get_process_count_written();
+		released = get_process_count_released();
+
+//		Critical Section (spinlock) >>>
+		spin_lock(spinlock_for_process_list);
+		{
+			// 各 SPE プロセス状態のプロセス数を取得 (スピンロックも行わないと取得できないもの)
+			waiting      = get_process_count_waiting();
+			running      = get_process_count_running();
+			not_released = get_process_count_not_released();
+		}
+		spin_unlock(spinlock_for_process_list);
+//		<<< Critical Section (spinlock)
+
+	up(semaphore_for_process_list);
+//	<<< Critical Section (semaphore)
+
+
+	// プロセス数情報を出力する
+	*eof = 1;
+	return sprintf (
+		page,
+		"               Processes \n"
+		"-------------------------\n"
+		" Opened        %9d\n"
+		" Written       %9d\n"
+		" Waiting       %9d\n"
+		" Running       %9d\n"
+		" Not Released  %9d\n"
+		" Released      %9d\n"
+		"-------------------------\n"
+		" Total         %9d\n",
+		opened, written, waiting, running, not_released, released,
+		opened + written + waiting + running + not_released + released   // Total
+	);
+
+
+procfs_processes_read__error1:
+	return -ERESTARTSYS;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/driver/procfs/processes.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,17 @@
+/**
+ * processes.h
+ * SPE プロセスマネージャ spe_manager
+ * procfs エントリ "processes" のハンドラ
+ */
+
+#ifndef  SPE_MANAGER__PROCFS__PROCESSES_H
+#define  SPE_MANAGER__PROCFS__PROCESSES_H
+
+#include <linux/types.h>
+
+
+// 外部から参照される関数
+int procfs_processes_read(char *, char **, off_t, int, int *, void *);
+
+
+#endif /*SPE_MANAGER__PROCFS__PROCESSES_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/hvcalls/common.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,68 @@
+/**
+ * hvcalls/common.h
+ * ハイパーバイザコール詰め合わせの共通部分
+ */
+
+#ifndef HVCALLS__COMMON_H
+#define HVCALLS__COMMON_H
+
+#include <linux/kernel.h>
+#include <asm/types.h>
+
+
+// 64 ビット値のフォーマット指定子を定義
+#if   defined __powerpc64__
+#	define HVCALLS_S64DFMT "%ld"       //   signed
+#	define HVCALLS_U64UFMT "%lu"       // unsigned (dec)
+#	define HVCALLS_U64XFMT "%016lx"    // unsigned (hex)
+#elif defined __GNUC__
+#	define HVCALLS_S64DFMT "%lld"      //   signed
+#	define HVCALLS_U64UFMT "%llu"      // unsigned (dec)
+#	define HVCALLS_U64XFMT "%016llx"   // unsigned (hex)
+#else
+#	error Can't determine 64bit format string.
+#endif /*defined __GNUC__, defined __powerpc64__*/
+
+// 整数型のエイリアスを定義
+typedef __u64 HVC_u64;
+
+
+// IS_DEBUG_MODE が定義されている場合は
+// HVCALLS_DO_PRINT_INFO も定義されたものとする
+#ifdef IS_DEBUG_MODE
+#	ifndef HVCALLS_DO_PRINT_INFO
+#		define HVCALLS_DO_PRINT_INFO
+#	endif
+#endif /*IS_DEBUG_MODE*/
+
+#ifdef HVCALLS_DO_PRINT_INFO
+	// プリフィックス/サフィックスを定義
+#	ifdef MODULE_NAME
+#		define HVCALLS_PREFIX MODULE_NAME " [hvcall] "
+#	else
+#		define HVCALLS_PREFIX "[hvcall] "
+#	endif
+#	define     HVCALLS_SUFFIX   // お好みで...
+	// 情報出力用マクロの定義
+#	define HVCALLS_PRINT_INFO(str) \
+	         printk(KERN_INFO HVCALLS_PREFIX str HVCALLS_SUFFIX "\n")
+#	define HVCALLS_PRINT_VALUE_S64(str, value) \
+	         printk(KERN_INFO HVCALLS_PREFIX str " (" HVCALLS_S64DFMT ")" HVCALLS_SUFFIX "\n", value)
+#	define HVCALLS_PRINT_VALUE_U64(str, value) \
+	         printk(KERN_INFO HVCALLS_PREFIX str " (" HVCALLS_U64UFMT ")" HVCALLS_SUFFIX "\n", value)
+#	define HVCALLS_PRINT_VALUE_HEX(str, value) \
+	         printk(KERN_INFO HVCALLS_PREFIX str " (0x" HVCALLS_U64XFMT ")" HVCALLS_SUFFIX "\n", value)
+#else
+#	define HVCALLS_PRINT_INFO(str)
+#	define HVCALLS_PRINT_VALUE_S64(str, value)
+#	define HVCALLS_PRINT_VALUE_U64(str, value)
+#	define HVCALLS_PRINT_VALUE_HEX(str, value)
+#endif /*HVCALLS_DO_PRINT_INFO*/
+
+// エラー出力用マクロの定義
+#define HVCALLS_PRINT_ERR(str, value) \
+          printk(KERN_ERR "Error: %s\n\t[%s(%d) %s : value(" HVCALLS_S64DFMT ")]\n", \
+           str, __FILE__, __LINE__, __func__, (__s64)value)
+
+
+#endif /*HVCALLS__COMMON_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/hvcalls/ppe.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,69 @@
+/**
+ * hvcalls/ppe.h
+ * PPE 関連のハイパーバイザコール詰め合わせ
+ */
+
+#ifndef HVCALLS__PPE_H
+#define HVCALLS__PPE_H
+
+#include <asm/lv1call.h>
+#include "common.h"
+
+
+//---------------------------------------------------------------------------------------------------- hvc_get_lpar_id()
+/**
+ * hvc_get_lpar_id (74:lv1_get_logical_partition_id)
+ * 呼び出し元の論理 PPE が属する論理パーティション識別子を返す
+ *
+ * @param  HVC_u64 *lpar_id  [OUT] 論理パーティション識別子
+ * @return void
+ * @static
+ * @inline
+ */
+static inline void hvc_get_lpar_id(HVC_u64 *const lpar_id)
+{
+	lv1_get_logical_partition_id(lpar_id);
+	HVCALLS_PRINT_VALUE_U64("lv1_get_logical_partition_id", *lpar_id);
+}
+
+//----------------------------------------------------------------------------------------------------- hvc_get_ppe_id()
+/**
+ * hvc_get_ppe_id (69:lv1_get_logical_ppe_id)
+ * 呼び出し元の論理 PPE 識別子を返す
+ *
+ * @param  HVC_u64 *ppe_id  [OUT] 論理 PPE 識別子
+ * @return void
+ * @static
+ * @inline
+ */
+static inline void hvc_get_ppe_id(HVC_u64 *const ppe_id)
+{
+	lv1_get_logical_ppe_id(ppe_id);
+	HVCALLS_PRINT_VALUE_U64("lv1_get_logical_ppe_id", *ppe_id);
+}
+
+//----------------------------------------------------------------------------------------------------- hvc_get_vas_id()
+/**
+ * hvc_get_vas_id (4:lv1_get_virtual_address_space_id_of_ppe)
+ * 呼び出し元の論理 PPE に割り当てられている仮想アドレス空間識別子を返す
+ *
+ * vas_id = 0 の場合は論理 PPE に仮想アドレス空間が割り当てられていない。
+ * このときハイパーバイザコールは失敗とはならないが、
+ * この関数では vas_id = 0 の場合に !0 (失敗) を返すようになっている。
+ *
+ * @param  HVC_u64  ppe_id  [IN]  論理 PPE 識別子
+ * @param  HVC_u64 *vas_id  [OUT] 仮想アドレス空間識別子
+ * @return int                    0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_get_vas_id(const HVC_u64 ppe_id, HVC_u64 *const vas_id)
+{
+	lv1_get_virtual_address_space_id_of_ppe(ppe_id, vas_id);
+	HVCALLS_PRINT_VALUE_U64("lv1_get_virtual_address_space_id_of_ppe", *vas_id);
+	if (!(*vas_id)) HVCALLS_PRINT_ERR("lv1_get_virtual_address_space_id_of_ppe FAILED.", *vas_id);
+	return !(int)(*vas_id);
+}
+
+
+#endif /*HVCALLS__PPE_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/hvcalls/repository.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,109 @@
+/**
+ * hvcalls/repository.h
+ * リポジトリ関連のハイパーバイザコール詰め合わせ
+ */
+
+#ifndef HVCALLS__REPOSITORY_H
+#define HVCALLS__REPOSITORY_H
+
+#include <asm/lv1call.h>
+#include "common.h"
+
+
+//-------------------------------------------------------------------------------------- hvc_make_repository_first_key()
+/**
+ * hvc_make_repository_first_key
+ * リポジトリノードの第 1 レベルキーを生成する
+ *
+ * @param  char    *text   [IN] キーのテキスト部
+ * @param  HVC_u64  index  [IN] キーのインデックス部
+ * @return HVC_u64              第 1 レベルキー値
+ * @static
+ * @inline
+ */
+static inline HVC_u64 hvc_make_repository_first_key (
+	const char    *const text,
+	const HVC_u64        index
+)
+{
+	HVC_u64 ret;
+	strncpy((char *)&ret, text, 8);   // [Note] strncpy は text が 8 文字未満の場合は残りを 0 で埋めるらしい...
+	return (ret >> 32) + index;
+}
+
+//-------------------------------------------------------------------------------------------- hvc_make_repository_key()
+/**
+ * hvc_make_repository_key
+ * リポジトリノードのキーを生成する
+ *
+ * @param  char    *text   [IN] キーのテキスト部
+ * @param  HVC_u64  index  [IN] キーのインデックス部
+ * @return HVC_u64              キー値
+ * @static
+ * @inline
+ */
+static inline HVC_u64 hvc_make_repository_key (
+	const char    *const text,
+	const HVC_u64        index
+)
+{
+	HVC_u64 ret;
+	strncpy((char *)&ret, text, 8);
+	return ret + index;
+}
+
+//-------------------------------------------------------------------------------------------- hvc_get_repository_node()
+/**
+ * hvc_get_repository_node (91:lv1_get_repository_node_value)
+ * リポジトリノードの値を取得する
+ *
+ * @param  HVC_u64  lpar_id  [IN]  論理パーティション識別子
+ * @param  HVC_u64  key1     [IN]  第 1 レベルキー
+ * @param  HVC_u64  key2     [IN]  第 2 レベルキー
+ * @param  HVC_u64  key3     [IN]  第 3 レベルキー
+ * @param  HVC_u64  key4     [IN]  第 4 レベルキー
+ * @param  HVC_u64 *val1     [OUT] リポジトリノードの値 1
+ * @param  HVC_u64 *val2     [OUT] リポジトリノードの値 2
+ * @return int                     0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_get_repository_node (
+	const HVC_u64        lpar_id,
+	const HVC_u64        key1,
+	const HVC_u64        key2,
+	const HVC_u64        key3,
+	const HVC_u64        key4,
+	      HVC_u64 *const val1,
+	      HVC_u64 *const val2
+)
+{
+	HVC_u64 ret =
+		lv1_get_repository_node_value (
+			lpar_id,
+			key1,
+			key2,
+			key3,
+			key4,
+			val1,
+			val2
+		);
+	HVCALLS_PRINT_INFO("lv1_get_repository_node_value");
+	if (ret)
+	{
+		HVCALLS_PRINT_ERR("lv1_get_repository_node_value FAILED.", ret);
+	}
+	else
+	{
+		HVCALLS_PRINT_VALUE_HEX("  1st key",  key1);
+		HVCALLS_PRINT_VALUE_HEX("  2nd key",  key2);
+		HVCALLS_PRINT_VALUE_HEX("  3rd key",  key3);
+		HVCALLS_PRINT_VALUE_HEX("  4th key",  key4);
+		HVCALLS_PRINT_VALUE_HEX("  value 1", *val1);
+		HVCALLS_PRINT_VALUE_HEX("  value 2", *val2);
+	}
+	return (int)ret;
+}
+
+
+#endif /*HVCALLS__REPOSITORY_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/hvcalls/spe.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,259 @@
+/**
+ * hvcalls/spe.h
+ * SPE 関連のハイパーバイザコール詰め合わせ
+ */
+
+#ifndef HVCALLS__SPE_H
+#define HVCALLS__SPE_H
+
+#include <asm/lv1call.h>
+#include "common.h"
+
+
+//--------------------------------------------------------------------------------------------- hvc_create_logical_spe()
+/**
+ * hvc_create_logical_spe (57:lv1_construct_logical_spe)
+ * 論理 SPE を生成する
+ *
+ * @param  HVC_u64  vas_id        [IN]  仮想アドレス空間識別子
+ * @param  HVC_u64 *spe_id        [OUT] 論理 SPE 識別子
+ * @param  HVC_u64 *ls_addr       [OUT] LS がマップされた論理パーティションアドレス
+ * @param  HVC_u64 *problem_addr  [OUT] プロブレムステート MMIO レジスタがマップされた
+ *                                      論理パーティションアドレス
+ * @param  HVC_u64 *priv2_addr    [OUT] 特権 2 MMIO レジスタがマップされた論理パーティションアドレス
+ * @param  HVC_u64 *shadow_addr   [OUT] SPE レジスタシャドーエリアがマップされた
+ *                                      論理パーティションアドレス
+ * @return int                          0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_create_logical_spe (
+	const HVC_u64        vas_id,
+	      HVC_u64 *const spe_id,
+	      HVC_u64 *const ls_addr,
+	      HVC_u64 *const problem_addr,
+	      HVC_u64 *const priv2_addr,
+	      HVC_u64 *const shadow_addr
+)
+{
+	HVC_u64 unused;
+	const HVC_u64 ret =
+		lv1_construct_logical_spe (
+			PAGE_SHIFT,
+			PAGE_SHIFT,
+			PAGE_SHIFT,
+			PAGE_SHIFT,
+			PAGE_SHIFT,
+			vas_id,
+			0, //SPE_TYPE_LOGICAL
+			priv2_addr,
+			problem_addr,
+			ls_addr,
+			&unused,
+			shadow_addr,
+			spe_id
+		);
+	HVCALLS_PRINT_INFO("lv1_construct_logical_spe");
+	if (ret)
+	{
+		HVCALLS_PRINT_ERR("lv1_construct_logical_spe FAILED.", ret);
+	}
+	else
+	{
+		HVCALLS_PRINT_VALUE_U64("        spe_id", *spe_id);
+		HVCALLS_PRINT_VALUE_HEX("       ls_addr", *ls_addr);
+		HVCALLS_PRINT_VALUE_HEX("  problem_addr", *problem_addr);
+		HVCALLS_PRINT_VALUE_HEX("    priv2_addr", *priv2_addr);
+		HVCALLS_PRINT_VALUE_HEX("   shadow_addr", *shadow_addr);
+	}
+	return (int)ret;
+}
+
+//--------------------------------------------------------------------------------------------- hvc_enable_logical_spe()
+/**
+ * hvc_enable_logical_spe (207:lv1_enable_logical_spe)
+ * 論理 SPE を利用可能状態にする
+ *
+ * @param  HVC_u64 spe_id  [IN] 論理 SPE 識別子
+ * @param  HVC_u64 res_id  [IN] 論理 SPE 予約識別子
+ * @return int                  0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_enable_logical_spe(const HVC_u64 spe_id, const HVC_u64 res_id)
+{
+	const HVC_u64 ret = lv1_enable_logical_spe(spe_id, res_id);
+	HVCALLS_PRINT_INFO     ("lv1_enable_logical_spe");
+	HVCALLS_PRINT_VALUE_U64("  spe_id", spe_id);
+	HVCALLS_PRINT_VALUE_U64("  res_id", res_id);
+	if (ret) HVCALLS_PRINT_ERR("lv1_enable_logical_spe FAILED.", ret);
+	return (int)ret;
+}
+
+//-------------------------------------------------------------------------------------------- hvc_disable_logical_spe()
+/**
+ * hvc_disable_logical_spe (65:lv1_disable_logical_spe)
+ * 論理 SPE を利用不可能状態にする
+ *
+ * @param  HVC_u64 spe_id  [IN] 論理 SPE 識別子
+ * @return int                  0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_disable_logical_spe(const HVC_u64 spe_id)
+{
+	const HVC_u64 ret = lv1_disable_logical_spe(spe_id, 0);
+	HVCALLS_PRINT_INFO     ("lv1_disable_logical_spe");
+	HVCALLS_PRINT_VALUE_U64("  spe_id", spe_id);
+	if (ret) HVCALLS_PRINT_ERR("lv1_disable_logical_spe FAILED.", ret);
+	return (int)ret;
+}
+
+//-------------------------------------------------------------------------------------------- hvc_destroy_logical_spe()
+/**
+ * hvc_destroy_logical_spe (54:lv1_destruct_logical_spe)
+ * 論理 SPE を解放する
+ *
+ * @param  HVC_u64 spe_id  [IN] 論理 SPE 識別子
+ * @return int                  0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_destroy_logical_spe(const HVC_u64 spe_id)
+{
+	const HVC_u64 ret = lv1_destruct_logical_spe(spe_id);
+	HVCALLS_PRINT_INFO     ("lv1_destruct_logical_spe");
+	HVCALLS_PRINT_VALUE_U64("  spe_id", spe_id);
+	if (ret) HVCALLS_PRINT_ERR("lv1_destruct_logical_spe FAILED.", ret);
+	return (int)ret;
+}
+
+//------------------------------------------------------------------------------------------ hvc_create_spe_irq_outlet()
+/**
+ * hvc_create_spe_irq_outlet (78:lv1_get_spe_irq_outlet)
+ * 論理 SPE の IRQ アウトレットを生成する
+ *
+ * [Note] SPE IRQ アウトレットには解放するためのハイパーバイザコールがない。
+ *        論理 SPE を解放すれば再びアウトレットを生成することができる。
+ *
+ * @param  HVC_u64  spe_id     [IN]  論理 SPE 識別子
+ * @param  HVC_u64  irq_class  [IN]  割り込みクラス番号
+ * @param  HVC_u64 *outlet     [OUT] IRQ アウトレット識別子
+ * @return int                       0...成功, not 0...失敗
+ * @static
+ * @inline
+ */
+static inline int hvc_create_spe_irq_outlet (
+	const HVC_u64        spe_id,
+	const HVC_u64        irq_class,
+	      HVC_u64 *const outlet
+)
+{
+	const HVC_u64 ret = lv1_get_spe_irq_outlet(spe_id, irq_class, outlet);
+	HVCALLS_PRINT_INFO("lv1_get_spe_irq_outlet");
+	if (ret)
+	{
+		HVCALLS_PRINT_ERR("lv1_get_spe_irq_outlet FAILED.", ret);
+	}
+	else
+	{
+		HVCALLS_PRINT_VALUE_U64("     spe_id", spe_id);
+		HVCALLS_PRINT_VALUE_U64("  irq_class", irq_class);
+		HVCALLS_PRINT_VALUE_U64("     outlet", *outlet);
+	}
+	return (int)ret;
+}
+
+//----------------------------------------------------------------------------------------------- hvc_set_spe_int_mask()
+/**
+ * hvc_set_spe_int_mask (61:lv1_set_spe_interrupt_mask)
+ * 論理 SPE に割り込みマスクを設定する
+ *
+ * [Note] この関数内で用いているハイパーバイザコール lv1_set_spe_interrupt_mask は、
+ *        戻り値の詳細が不明であり、カーネルのソースコードでも戻り値は受け取っていない。
+ *        おそらく 0...成功, not 0...失敗 だと思われるが、この関数の戻り値は void としている。
+ *
+ * @param  HVC_u64 spe_id     [IN] 論理 SPE 識別子
+ * @param  HVC_u64 irq_class  [IN] 割り込みクラス番号
+ * @param  HVC_u64 mask       [IN] 割り込みマスク
+ * @return void
+ * @static
+ * @inline
+ */
+static inline void hvc_set_spe_int_mask (
+	const HVC_u64 spe_id,
+	const HVC_u64 irq_class,
+	const HVC_u64 mask
+)
+{
+	const HVC_u64 ret = lv1_set_spe_interrupt_mask(spe_id, irq_class, mask);
+	HVCALLS_PRINT_INFO     ("lv1_set_spe_interrupt_mask");
+	HVCALLS_PRINT_VALUE_U64("     spe_id", spe_id);
+	HVCALLS_PRINT_VALUE_U64("  irq_class", irq_class);
+	HVCALLS_PRINT_VALUE_HEX("       mask", mask);
+	HVCALLS_PRINT_VALUE_S64("   (return)", ret);
+}
+
+//----------------------------------------------------------------------------------------------- hvc_get_spe_int_stat()
+/**
+ * hvc_get_spe_int_stat (67:lv1_get_spe_interrupt_status)
+ * 論理 SPE の割り込み発生状況を取得する
+ *
+ * [Note] この関数内で用いているハイパーバイザコール lv1_get_spe_interrupt_status は、
+ *        戻り値の詳細が不明であり、カーネルのソースコードでも戻り値は受け取っていない。
+ *        動作結果から、おそらく 0...成功, not 0...失敗 だと思われるが、
+ *        この関数の戻り値は void としている。
+ *
+ * @param  HVC_u64  spe_id     [IN]  論理 SPE 識別子
+ * @param  HVC_u64  irq_class  [IN]  割り込みクラス番号
+ * @param  HVC_u64 *status     [OUT] 割り込み発生状況
+ * @return void
+ * @static
+ * @inline
+ */
+static inline void hvc_get_spe_int_stat (
+	const HVC_u64        spe_id,
+	const HVC_u64        irq_class,
+	      HVC_u64 *const status
+)
+{
+	const HVC_u64 ret = lv1_get_spe_interrupt_status(spe_id, irq_class, status);
+	HVCALLS_PRINT_INFO     ("lv1_get_spe_interrupt_status");
+	HVCALLS_PRINT_VALUE_U64("     spe_id", spe_id);
+	HVCALLS_PRINT_VALUE_U64("  irq_class", irq_class);
+	HVCALLS_PRINT_VALUE_HEX("     status", *status);
+	HVCALLS_PRINT_VALUE_S64("   (return)", ret);
+}
+
+//--------------------------------------------------------------------------------------------- hvc_clear_spe_int_stat()
+/**
+ * hvc_clear_spe_int_stat (66:lv1_clear_spe_interrupt_status)
+ * 論理 SPE の割り込みをクリアする (Acknowledge)
+ *
+ * [Note] この関数内で用いているハイパーバイザコール lv1_clear_spe_interrupt_status は、
+ *        戻り値の詳細が不明であり、カーネルのソースコードでも戻り値は受け取っていない。
+ *        おそらく 0...成功, not 0...失敗 だと思われるが、この関数の戻り値は void としている。
+ *
+ * @param  HVC_u64 spe_id     [IN] 論理 SPE 識別子
+ * @param  HVC_u64 irq_class  [IN] 割り込みクラス番号
+ * @param  HVC_u64 status     [IN] クリアする割り込み要因
+ * @return void
+ * @static
+ * @inline
+ */
+static inline void hvc_clear_spe_int_stat (
+	const HVC_u64 spe_id,
+	const HVC_u64 irq_class,
+	const HVC_u64 status
+)
+{
+	const HVC_u64 ret = lv1_clear_spe_interrupt_status(spe_id, irq_class, status, 0);
+	HVCALLS_PRINT_INFO     ("lv1_clear_spe_interrupt_status");
+	HVCALLS_PRINT_VALUE_U64("     spe_id", spe_id);
+	HVCALLS_PRINT_VALUE_U64("  irq_class", irq_class);
+	HVCALLS_PRINT_VALUE_HEX("     status", status);
+	HVCALLS_PRINT_VALUE_S64("   (return)", ret);
+}
+
+
+#endif /*HVCALLS__SPE_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/ioctl.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,33 @@
+/**
+ * ioctl.h
+ * SPE プロセスマネージャ spe_manager
+ * ioctl システムコール定義
+ */
+
+#ifndef  INCLUDE__IOCTL_H
+#define  INCLUDE__IOCTL_H
+
+#include <linux/ioctl.h>
+
+
+#define  SPE_MANAGER_IOCTL_MAGIC          'k'
+
+#define  SPE_MANAGER_IOCTL_START_PROCESS  _IO(SPE_MANAGER_IOCTL_MAGIC, 1)   // SPE プロセスを開始する
+
+
+/*
+#define  SPE_EXECUTER_IOCTL_SUSPEND_PROCESS  _IO(SPE_EXECUTER_IOCTL_MAGIC,   2)        // SPE プロセスを中断する (未実装)
+#define  SPE_EXECUTER_IOCTL_RESUME_PROCESS   _IO(SPE_EXECUTER_IOCTL_MAGIC,   3)        // SPE プロセスを再開する (未実装)
+#define  SPE_EXECUTER_IOCTL_KILL_PROCESS     _IO(SPE_EXECUTER_IOCTL_MAGIC,   4)        // SPE プロセスを強制終了する (未実装)
+*/
+// 以降はデバッグ用途
+/*
+#define  SPE_EXECUTER_IOCTL_GET_CURRENT_SPE  _IOR(SPE_EXECUTER_IOCTL_MAGIC, 11, int)   // 現在の SPE 番号を取得する (未実装)
+#define  SPE_EXECUTER_IOCTL_SET_CURRENT_SPE  _IOW(SPE_EXECUTER_IOCTL_MAGIC, 12, int)   // 現在の SPE 番号を設定する (未実装)
+#define  SPE_EXECUTER_IOCTL_SELECT_LS        _IO(SPE_EXECUTER_IOCTL_MAGIC,  13)        // LS エリアを選択する (未実装)
+#define  SPE_EXECUTER_IOCTL_SELECT_PROBLEM   _IO(SPE_EXECUTER_IOCTL_MAGIC,  14)        // プロブレムステートレジスタエリアを選択する (未実装)
+#define  SPE_EXECUTER_IOCTL_SELECT_PRIV2     _IO(SPE_EXECUTER_IOCTL_MAGIC,  15)        // 特権 2 レジスタエリアを選択する (未実装)
+*/
+
+
+#endif /*INCLUDE__IOCTL_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/spe_process.h	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,99 @@
+/**
+ * spe_process.h
+ * SPE プロセスマネージャ spe_manager
+ * SPE プロセスに関する定数や構造体
+ */
+
+#ifndef  INCLUDE__SPE_PROCESS_H
+#define  INCLUDE__SPE_PROCESS_H
+
+
+// SPE プロセスの状態
+#define  SPE_PROCESS_CONTEXT_STATUS_OPENED        0   // コンテキストを open した
+#define  SPE_PROCESS_CONTEXT_STATUS_WRITTEN       1   // コンテキストデータを書き込んだ
+#define  SPE_PROCESS_CONTEXT_STATUS_WAITING       2   // プロセスの実行を待っている
+#define  SPE_PROCESS_CONTEXT_STATUS_RUNNING       3   // プロセスが実行中である
+#define  SPE_PROCESS_CONTEXT_STATUS_FINISHED      4   // プロセスの実行が終了した
+#define  SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED  5   // 実行は終わったがコンテキストがまだ release されていない
+/*
+#define  SPE_PROCESS_STATUS_UNEXECUTED  0   // まだ SPE に実行されていない
+#define  SPE_PROCESS_STATUS_WAITING     1   // SPE が実行するのを待っている
+#define  SPE_PROCESS_STATUS_EXECUTED    2   // SPE がプロセスを実行中である
+#define  SPE_PROCESS_STATUS_SUSPENDED   3   // SPE プロセスが中断している (未実装)
+#define  SPE_PROCESS_STATUS_FINISHED    4   // SPE プロセスの実行が完了した
+*/
+
+
+
+
+
+
+
+/**
+ * spe_process_context_write_data_t
+ * SPE プロセスコンテキスト write ハンドラ構造体
+ */
+typedef struct
+{
+//[ 0]
+	uint64_t pgm_start;     // SPE プログラムの先頭アドレス (mmap 等を利用する)
+//( 8)
+	uint64_t arg;           // 引数
+//[16]
+	uint64_t dat_start;     // データの先頭アドレス (mmap 等を利用する)
+//(24)
+	 int32_t pid;           // 登録側プロセス ID
+	uint32_t pgm_size;      // SPE プログラムサイズ
+//[32]
+	uint32_t dat_size;      // データサイズ
+	 int32_t reserved[7];   // 予約済
+//[64]
+}
+spe_process_context_write_data_t;
+
+
+/**
+ * spe_process_context_read_data_t
+ * SPE プロセスコンテキスト read ハンドラ構造体
+ */
+typedef struct
+{
+//[ 0]
+	uint64_t ret;           // SPE プロセスの戻り値
+//( 8)
+	 int32_t spe_pid;       // SPE プロセス ID (登録側の pid ではない)
+	volatile int32_t status;        // SPE プロセスの状態
+//[16]
+	 int32_t spe_no;        // プロセスの実行を担当した SPE (暫定)
+	 int32_t reserved[3];   // 予約済
+//[32]
+}
+spe_process_context_read_data_t;
+
+
+/**
+ * spe_process_context_t
+ * SPE プロセスコンテキスト構造体
+ */
+typedef struct
+{
+	spe_process_context_write_data_t write;
+	spe_process_context_read_data_t  read;
+}
+spe_process_context_t;
+
+
+/**
+ * spe_process_context_list_t
+ * SPE プロセスコンテキストの双方向リスト
+ */
+typedef struct spe_process_context_list
+{
+	spe_process_context_t            context __attribute__((aligned(16)));
+	struct spe_process_context_list *prev_process;
+	struct spe_process_context_list *next_process;
+}
+spe_process_context_list_t;
+
+
+#endif /*INCLUDE__SPE_PROCESS_H*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/Makefile	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,71 @@
+##
+## Makefile
+## SPE 軽量カーネル構築用 Makefile
+##
+
+kernel       = kernel
+dump         = kernel.dump
+kernel_h     = ../include/kernel.h
+
+elf          = kernel.elf
+objs         = entry.o kernel.o
+ldscript     = kernel.ld
+
+ASFLAGS      = 
+CFLAGS       = -Wall -Wno-main
+LDFLAGS      = -T $(ldscript)
+OBJDUMPFLAGS = -D
+OBJCOPYFLAGS = -S -O binary
+
+
+AS           = spu-as
+CC           = spu-gcc
+LD           = spu-ld
+OBJDUMP      = spu-objdump
+OBJCOPY      = spu-objcopy
+CONVERT      = ./convert
+
+CLEANSTR     = "  CLEAN"
+ASSTR        = "  AS      "
+CCSTR        = "  CC      "
+LDSTR        = "  LD      "
+OBJDUMPSTR   = "  OBJDUMP "
+OBJCOPYSTR   = "  OBJCOPY "
+CONVERTSTR   = "  CONVERT "
+
+ifeq ($(VERBOSE), 1)
+	Q =
+else
+	Q = @
+endif
+
+
+.PHONY: all
+all: $(kernel_h) dump
+
+.PHONY: dump
+dump: $(dump)
+
+$(kernel_h): $(kernel)
+	@echo $(CONVERTSTR)$@
+	$(Q)$(CONVERT) $< $@
+$(kernel): $(elf)
+	@echo $(OBJCOPYSTR)$@
+	$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+$(dump): $(elf)
+	@echo $(OBJDUMPSTR)$@
+	$(Q)$(OBJDUMP) $(OBJDUMPFLAGS) $< > $@
+$(elf): $(objs)
+	@echo $(LDSTR)$@
+	$(Q)$(LD) $(LDFLAGS) -o $@ $^
+.s.o:
+	@echo $(ASSTR)$@
+	$(Q)$(AS) $(ASFLAGS) -o $@ $<
+.c.o:
+	@echo $(CCSTR)$@
+	$(Q)$(CC) $(CFLAGS) -c -o $@ $<
+
+.PHONY: clean
+clean:
+	@echo $(CLEANSTR)
+	$(Q)$(RM) $(kernel) $(dump) $(kernel_h) $(elf) $(objs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/convert	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,44 @@
+#!/usr/bin/php
+<?php
+$import_file_name = $argv[1];
+$export_file_name = $argv[2];
+$export_file_base = basename($export_file_name);
+
+
+// raw バイナリを読み込んで 4 バイトごとに unsigned int 化
+$content  = file_get_contents($import_file_name);
+$unpacked = unpack('N*', $content);
+foreach ($unpacked as $key => $val)
+{
+    $unpacked[$key] = sprintf('0x%08X', $val);
+}
+
+// 各データ準備
+$kernel_size  = strlen($content);
+$kernel_uints = $kernel_size / 4;
+$kernel_items = implode(', ', $unpacked);
+
+// C 言語のヘッダファイルを書き出す
+$fp = fopen($export_file_name, 'wb') or die("Can't open {$export_file_base}.");
+
+$content = <<<EOH
+/* [{$export_file_base}] This file has automatically generated by kernel/convert. So don't edit me. */
+
+#ifndef  KERNEL_H
+#define  KERNEL_H
+
+
+#define  SPE_KERNEL_SIZE                 {$kernel_size}
+#define  SPE_KERNEL_INITIAL_PC           0x10
+#define  SPE_KERNEL_PROC_CONTEXT_OFFSET  0x70
+//#define  SPE_KERNEL_PROGRAM_OFFSET       0x30
+
+uint32_t spe_kernel_raw[{$kernel_uints}] = { {$kernel_items} };
+
+
+#endif /*KERNEL_H*/
+
+EOH;
+
+fwrite($fp, $content);
+fclose($fp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/entry.s	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,45 @@
+/**
+ * entry.s
+ * SPE 軽量カーネル エントリポイント
+ */
+
+.file "entry.s"
+
+.text
+	.global _entry
+
+__SPE_LS_START__:  # 00h #
+
+	/**
+	 * ToDo: SPE で発生するイベントとかのハンドラをここに書く。
+	 *       現在はとりあえず SPE プロセスマネージャに対して割り込みを発生させる。
+	 */
+
+	stop  0x3FFE
+
+	.align 4
+
+_entry:            # 10h #
+
+	# スタックおよびスタックポインタの初期化
+	# (cf. SPU Application Binary Interface 仕様書 v1.6 p.20)
+	ila   $3, 0
+	ila   $4, 0x3FFF0
+	ila   $5, 0x3FFD0
+	stqd  $3, 0($4)
+	stqd  $4, 0($5)
+	or    $1, $5, $3   # sp = 0x3FFD0 (Initial Stack Pointer)
+
+	# SPU 割り込み機能をイネーブルにしつつ kernel.c へ
+	ila   $3, start
+	bisl  $0, $3
+#	bisle $0, $3
+
+	# SPE プロセスマネージャに対してプロセス終了を示す割り込みを発生させる
+	stop  0x3FFD
+
+	## stop 命令以降 SPE の実行は停止する。
+	## デバイスドライバの割り込みハンドラで再びプログラムカウンタが _entry (= 0x10) へ移され、
+	## 実行が再開される。
+
+	               # 34h #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/kernel.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,76 @@
+/**
+ * kernel.c
+ * SPE 軽量カーネル 本体
+ */
+
+#include <spu_mfcio.h>
+#include "../include/spe_process.h"
+
+#define  FLOOR_TO_BOUNDARY_BYTE(n,b) ( (n) & ~((b)-1) )           // b バイト境界への切り捨て
+#define  CEIL_TO_BOUNDARY_BYTE(n,b)  ( ((n)+(b)-1) & ~((b)-1) )   // b バイト境界への切り上げ
+
+
+// SPE プロセスコンテキストの読み書き領域
+volatile spe_process_context_t this_process __attribute__((aligned(16)));
+
+// SPE プロセスコンテキストの実効アドレス
+extern volatile unsigned long long __process_context_ea__;
+// SPE プロセスのプログラム転送開始地点
+extern volatile unsigned int       __spe_program_start__;
+
+
+
+void start(void)
+{
+	//----- SPE プロセスコンテキストの読み込み ------------------------------
+	mfc_get (
+		&this_process,
+		__process_context_ea__,
+		CEIL_TO_BOUNDARY_BYTE(sizeof(this_process), 16),
+		0,  // tag
+		0,  // tid
+		0   // rid
+	);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+	asm volatile ("dsync");  // プロセスコンテキストの読み込み完了を保証
+
+
+	//----- SPE プロセスとなるプログラムの読み込み ------------------------------
+	mfc_get (
+		&__spe_program_start__,
+		this_process.write.pgm_start,
+		CEIL_TO_BOUNDARY_BYTE(this_process.write.pgm_size, 16),
+		0,  // tag
+		0,  // tid
+		0   // rid
+	);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+	asm volatile ("sync");   // プログラムの読み込み完了とその後のプリフェッチを保証
+
+
+	//----- プログラム実行 ------------------------------
+	this_process.read.ret = ((unsigned long long (*)(unsigned long long))&__spe_program_start__)(this_process.write.arg);
+
+
+	//----- SPE プロセスコンテキストの書き出し ------------------------------
+	this_process.read.status = SPE_PROCESS_CONTEXT_STATUS_FINISHED;
+
+	asm volatile ("dsync");   // LS 内のデータ書き込み完了を保証
+
+	// Note: SPE プロセスのプログラム内で同一タグ ID の DMA 転送を行っている場合を考慮して、
+	//       コンテキストの書き出しではフェンス修飾を付けておく。
+
+	mfc_putf (
+		&this_process,
+		__process_context_ea__,
+		CEIL_TO_BOUNDARY_BYTE(sizeof(this_process), 16),
+		0,  // tag
+		0,  // tid
+		0   // rid
+	);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+	mfc_sync(0 /*tag*/);      // プロセスコンテキストの書き出し完了を保証
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/kernel.ld	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,44 @@
+/**
+ * kernel.ld
+ * SPE 軽量カーネル構築用リンカスクリプト
+ */
+
+/* objcopy してしまうので意味はないが */
+ENTRY(_entry)
+
+
+SECTIONS
+{
+	. = 0x0;
+
+	.text : {
+		entry.o (.text)                       /* 00h~34h */
+
+		/*
+		 * Note: 現在 34h~70h の領域は使用していない。
+		 */
+
+		. = 0x70;
+		/* SPE プロセスコンテキストの実効アドレス */
+		__process_context_ea__ = .; QUAD(0)   /* 70h~78h */
+
+		. = 0x80;
+		*(.text)                              /* 80h~    */
+	}
+
+	.data : { *(.data) }
+	.rodata : { *(.rodata) }
+	.bss  : { *(.bss) }
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.note.spu_name)
+	}
+
+	. = ALIGN(0x80);
+
+	.spe_program : {
+		/* SPE プログラム転送開始地点 */
+		__spe_program_start__ = .;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/001_overhead/Makefile	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,65 @@
+##
+## Makefile
+## SPE アプリケーション用 Makefile
+##
+
+spe          = spe
+dump         = spe.dump
+
+elf          = spe.elf
+objs         = spe.o
+ldscript     = spe.ld
+
+ASFLAGS      = 
+CFLAGS       = -Wall -Wno-main -std=c99
+LDFLAGS      = -T $(ldscript)
+OBJDUMPFLAGS = -D
+OBJCOPYFLAGS = -S -O binary
+
+
+AS           = spu-as
+CC           = spu-gcc
+LD           = spu-ld
+OBJDUMP      = spu-objdump
+OBJCOPY      = spu-objcopy
+
+CLEANSTR     = "  CLEAN"
+ASSTR        = "  AS      "
+CCSTR        = "  CC      "
+LDSTR        = "  LD      "
+OBJDUMPSTR   = "  OBJDUMP "
+OBJCOPYSTR   = "  OBJCOPY "
+
+ifeq ($(VERBOSE), 1)
+	Q =
+else
+	Q = @
+endif
+
+
+.PHONY: all
+all: $(spe) dump
+
+.PHONY: dump
+dump: $(dump)
+
+$(spe): $(elf)
+	@echo $(OBJCOPYSTR)$@
+	$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+$(dump): $(elf)
+	@echo $(OBJDUMPSTR)$@
+	$(Q)$(OBJDUMP) $(OBJDUMPFLAGS) $< > $@
+$(elf): $(objs)
+	@echo $(LDSTR)$@
+	$(Q)$(LD) $(LDFLAGS) -o $@ $^
+.s.o:
+	@echo $(ASSTR)$@
+	$(Q)$(AS) $(ASFLAGS) -o $@ $<
+.c.o:
+	@echo $(CCSTR)$@
+	$(Q)$(CC) $(CFLAGS) -c -o $@ $<
+
+.PHONY: clean
+clean:
+	@echo $(CLEANSTR)
+	$(Q)$(RM) $(spe) $(dump) $(elf) $(objs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/001_overhead/spe.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,9 @@
+/**
+ * spe.c
+ * SPE アプリケーション本体
+ */
+
+unsigned long long main(unsigned long long arg)
+{
+	return 0ULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/001_overhead/spe.ld	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,23 @@
+/**
+ * spe.ld
+ * SPE アプリケーション用リンカスクリプト
+ */
+
+/* objcopy してしまうので意味はないが */
+ENTRY(main)
+
+
+SECTIONS
+{
+	. = 0x480;
+
+	.text   : { *(.text) }
+	.data   : { *(.data) }
+	.rodata : { *(.rodata) }
+	.bss    : { *(.bss) }
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.note.spu_name)
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/002_qsort/Makefile	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,65 @@
+##
+## Makefile
+## SPE アプリケーション用 Makefile
+##
+
+spe          = spe
+dump         = spe.dump
+
+elf          = spe.elf
+objs         = spe.o
+ldscript     = spe.ld
+
+ASFLAGS      = 
+CFLAGS       = -Wall -Wno-main -std=c99
+LDFLAGS      = -T $(ldscript)
+OBJDUMPFLAGS = -D
+OBJCOPYFLAGS = -S -O binary
+
+
+AS           = spu-as
+CC           = spu-gcc
+LD           = spu-ld
+OBJDUMP      = spu-objdump
+OBJCOPY      = spu-objcopy
+
+CLEANSTR     = "  CLEAN"
+ASSTR        = "  AS      "
+CCSTR        = "  CC      "
+LDSTR        = "  LD      "
+OBJDUMPSTR   = "  OBJDUMP "
+OBJCOPYSTR   = "  OBJCOPY "
+
+ifeq ($(VERBOSE), 1)
+	Q =
+else
+	Q = @
+endif
+
+
+.PHONY: all
+all: $(spe) dump
+
+.PHONY: dump
+dump: $(dump)
+
+$(spe): $(elf)
+	@echo $(OBJCOPYSTR)$@
+	$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+$(dump): $(elf)
+	@echo $(OBJDUMPSTR)$@
+	$(Q)$(OBJDUMP) $(OBJDUMPFLAGS) $< > $@
+$(elf): $(objs)
+	@echo $(LDSTR)$@
+	$(Q)$(LD) $(LDFLAGS) -o $@ $^
+.s.o:
+	@echo $(ASSTR)$@
+	$(Q)$(AS) $(ASFLAGS) -o $@ $<
+.c.o:
+	@echo $(CCSTR)$@
+	$(Q)$(CC) $(CFLAGS) -c -o $@ $<
+
+.PHONY: clean
+clean:
+	@echo $(CLEANSTR)
+	$(Q)$(RM) $(spe) $(dump) $(elf) $(objs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/002_qsort/spe.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,85 @@
+/**
+ * spe.c
+ * SPE アプリケーション本体
+ */
+
+#include <spu_mfcio.h>
+
+typedef struct
+{
+	unsigned long long ea;
+	unsigned int count;
+	unsigned int pad;
+}
+qsort_info;
+
+typedef struct
+{
+	long long d;
+	unsigned long long pad;
+}
+qsort_data;
+
+
+
+volatile qsort_info info __attribute__((aligned(16)));
+
+volatile qsort_data data[1024] __attribute__((aligned(16)));
+
+
+unsigned long long main(unsigned long long arg)
+{
+	// qsort_info 読み込み
+	mfc_get(&info, arg, sizeof(qsort_info), 0, 0, 0);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+
+	// データ読み込み
+	mfc_get(&data, info.ea, 16 * info.count, 0, 0, 0);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+
+	if (info.count == 2)
+	{
+		if (data[0].d > data[1].d)
+		{
+			data[2] = data[0];
+			data[0] = data[1];
+			data[1] = data[2];
+
+			// データ書き出し
+			mfc_put(&data, info.ea, 32, 0, 0, 0);
+			spu_writech(MFC_WrTagMask, 1<<0);
+			spu_mfcstat(MFC_TAG_UPDATE_ALL);
+		}
+		return 0UL;   // これ以上ソートする必要なし
+	}
+
+	unsigned long long pivot = data[info.count / 2].d;
+	unsigned int i = 0, j = info.count - 1;
+
+	while (1)
+	{
+		while (data[i].d < pivot)
+			i++;
+
+		while (pivot < data[j].d)
+			j--;
+
+		if (i >= j) break;
+
+		qsort_data swap = data[i];
+		data[i] = data[j];
+		data[j] = swap;
+
+		i++;
+		j--;
+	}
+
+	// データ書き出し
+	mfc_put(&data, info.ea, 16 * info.count, 0, 0, 0);
+	spu_writech(MFC_WrTagMask, 1<<0);
+	spu_mfcstat(MFC_TAG_UPDATE_ALL);
+
+	return (unsigned long long)i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spe_programs/002_qsort/spe.ld	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,23 @@
+/**
+ * spe.ld
+ * SPE アプリケーション用リンカスクリプト
+ */
+
+/* objcopy してしまうので意味はないが */
+ENTRY(main)
+
+
+SECTIONS
+{
+	. = 0x480;
+
+	.text   : { *(.text) }
+	.data   : { *(.data) }
+	.rodata : { *(.rodata) }
+	.bss    : { *(.bss) }
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.note.spu_name)
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/001_090722/001.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	fd = open("/dev/spe_manager", O_RDWR);
+	printf("fd: %d\n", fd);
+
+	spe_process_context_write_data_t spe_write = { 0 };
+	spe_process_context_read_data_t  spe_read;
+
+	lseek(fd, 0, SEEK_SET);
+	write(fd, &spe_write, sizeof(spe_write));
+
+	ioctl(fd, SPE_MANAGER_IOCTL_START_PROCESS);
+
+	do
+	{
+		lseek(fd, 0, SEEK_SET);
+		read(fd, &spe_read, sizeof(spe_read));
+	}
+	while (spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+
+	close(fd);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/002_090722/002.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+#define  PROCESSES 100
+
+
+int main(int argc, char *argv[])
+{
+	int fd[PROCESSES];
+	spe_process_context_write_data_t spe_write = { 0 };
+	spe_process_context_read_data_t  spe_read;
+
+	int i;
+
+
+	for (i = 0; i < PROCESSES; i++)
+	{
+		fd[i] = open("/dev/spe_manager", O_RDWR);
+
+		lseek(fd[i], 0, SEEK_SET);
+		write(fd[i], &spe_write, sizeof(spe_write));
+		ioctl(fd[i], SPE_MANAGER_IOCTL_START_PROCESS);
+	}
+
+	for (i = 0; i < PROCESSES; i++)
+	{
+		do
+		{
+			lseek(fd[i], 0, SEEK_SET);
+			read(fd[i], &spe_read, sizeof(spe_read));
+		}
+		while (spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+
+		close(fd[i]);
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/003_090809/003.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+
+uint64_t hoge[4] __attribute__((aligned(128))) = { 0x5c812625b0c98a84UL, 0xb0589ae8e319ca7bUL, 0xc797c3af5d2807eaUL, 0x7df3ed18fa5dc081UL };
+
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	fd = open("/dev/spe_manager", O_RDWR);
+	printf("fd: %d\n", fd);
+
+	int fd_mmap;
+	fd_mmap = open("./003", O_RDONLY);
+	printf("fd_mmap: %d\n", fd_mmap);
+
+	volatile void *mapped = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd_mmap, 0);
+
+	unsigned char a[1024];
+
+	memcpy(a, mapped, 1024);
+
+
+
+
+
+
+	spe_process_context_write_data_t spe_write = { 0 };
+	spe_write.pid       =  (int32_t)getpid();
+	spe_write.pgm_start = (uint64_t)mapped;
+	spe_write.pgm_size  = 1024;
+	spe_process_context_read_data_t  spe_read;
+
+	printf("ADDR(mapped): %016lx\n", (uint64_t)mapped);
+
+	lseek(fd, 0, SEEK_SET);
+	write(fd, &spe_write, sizeof(spe_write));
+
+	ioctl(fd, SPE_MANAGER_IOCTL_START_PROCESS);
+
+	do
+	{
+		lseek(fd, 0, SEEK_SET);
+		read(fd, &spe_read, sizeof(spe_read));
+	}
+	while (spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+
+
+
+//	munmap(mapped, 1024);
+	close(fd_mmap);
+
+
+	close(fd);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/004_090809/004.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <memory.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+
+uint64_t hoge[4] __attribute__((aligned(128))) = { 0x5c812625b0c98a84UL, 0xb0589ae8e319ca7bUL, 0xc797c3af5d2807eaUL, 0x7df3ed18fa5dc081UL };
+
+volatile unsigned char a[1024] __attribute__((aligned(128)));
+
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	fd = open("/dev/spe_manager", O_RDWR);
+	printf("fd: %d\n", fd);
+
+	int fd_mmap;
+	fd_mmap = open("./004", O_RDONLY);
+	printf("fd_mmap: %d\n", fd_mmap);
+	volatile void *mapped = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd_mmap, 0);
+	printf("ADDR(mapped): 0x%016lx\n", (uint64_t)mapped);
+	printf("ADDR(mapped): 0x%016lx\n", (uint64_t)a);
+
+	memcpy(a, mapped, 1024);
+
+	spe_process_context_write_data_t spe_write = { 0 };
+//	spe_write.pid       =  (int32_t)getpid();
+	spe_write.pgm_start = (uint64_t)a;
+	spe_write.pgm_size  = 1024;
+	spe_write.arg       = 0x5c812625b0c98a84UL;
+
+	spe_process_context_read_data_t  spe_read;
+
+
+	lseek(fd, 0, SEEK_SET);
+	write(fd, &spe_write, sizeof(spe_write));
+
+	ioctl(fd, SPE_MANAGER_IOCTL_START_PROCESS);
+
+	do
+	{
+		lseek(fd, 0, SEEK_SET);
+		read(fd, &spe_read, sizeof(spe_read));
+	}
+	while (spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+
+	printf("spe_read.ret: 0x%016lx\n", spe_read.ret);
+
+
+	close(fd_mmap);
+	close(fd);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/005_forJSASS_1/005.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <memory.h>
+#include <sys/time.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+
+#define  PROGRAM_SIZE  40
+#define  PROCESSES     10
+
+
+volatile unsigned char buffer[1024] __attribute__((aligned(128)));
+
+
+int main(int argc, char *argv[])
+{
+	int fd_mmap;
+	if ((fd_mmap = open("../../spe_programs/001_overhead/spe", O_RDONLY)) == -1)
+	{
+		printf("Can't open spe program.\n");
+		return -1;
+	}
+	printf("fd_mmap: %d\n", fd_mmap);
+
+/*
+	volatile void *mapped;
+	if ((mapped = mmap(NULL, 1024, PROT_READ, MAP_SHARED, fd_mmap, 0)) == MAP_FAILED)
+	{
+		printf("mmap() failed.\n");
+		return -1;
+	}
+	memcpy(buffer, mapped, 1024);
+*/
+	read(fd_mmap, buffer, PROGRAM_SIZE);
+
+//------------------------------------------------
+//	ここから時間を計測する
+
+	struct timeval tv1, tv2, tv3;
+	int fd[PROCESSES];
+
+	gettimeofday(&tv1, NULL);
+	gettimeofday(&tv2, NULL);
+
+	spe_process_context_write_data_t spe_write = { 0 };
+	spe_process_context_read_data_t  spe_read;
+
+	spe_write.pgm_start = (uint64_t)buffer;
+	spe_write.pgm_size  = PROGRAM_SIZE;
+
+
+	for (int i = 0; i < PROCESSES; i++)
+	{
+		if ((fd[i] = open("/dev/spe_manager", O_RDWR)) == -1)
+		{
+			printf("Can't open /dev/spe_manager. (i = %d)\n", i);
+			return -1;
+		}
+
+		lseek(fd[i], 0, SEEK_SET);
+		write(fd[i], &spe_write, sizeof(spe_write));
+	}
+
+	for (int i = 0; i < PROCESSES; i++)
+	{
+		ioctl(fd[i], SPE_MANAGER_IOCTL_START_PROCESS);
+	}
+
+	for (int i = 0; i < PROCESSES; i++)
+	{
+		do
+		{
+			lseek(fd[i], 0, SEEK_SET);
+			read(fd[i], &spe_read, sizeof(spe_read));
+		}
+		while (spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+		close(fd[i]);
+	}
+
+	gettimeofday(&tv3, NULL);
+
+//	時間計測終了
+//------------------------------------------------
+
+	printf("%lu.%06lu\n", tv1.tv_sec, tv1.tv_usec);
+	printf("%lu.%06lu\n", tv2.tv_sec, tv2.tv_usec);
+	printf("%lu.%06lu\n", tv3.tv_sec, tv3.tv_usec);
+	fprintf(stderr, "Done.\n");
+
+	close(fd_mmap);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/005_forJSASS_1/005.exec	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+i=1
+while [ $i -le 100 ]; do
+./005
+sleep 1
+i=`expr $i + 1`
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/006_qsort/006.c	Tue Sep 08 13:44:18 2009 +0900
@@ -0,0 +1,199 @@
+#define _XOPEN_SOURCE 600
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <memory.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <alloca.h>
+
+#include "../../include/ioctl.h"
+#include "../../include/spe_process.h"
+
+
+#define SORT 1024
+
+typedef struct
+{
+	uint64_t ea;
+	uint32_t count;
+}
+qsort_info;
+
+
+typedef struct
+{
+	 int64_t d;
+	uint64_t pad;
+}
+qsort_data;
+
+
+volatile qsort_data data[SORT] __attribute__((aligned(16)));
+
+volatile qsort_info info __attribute__((aligned(16)));
+
+volatile unsigned char buffer[4096] __attribute__((aligned(128))) = { 0 };
+
+
+typedef struct
+{
+	qsort_info info __attribute__((aligned(16)));
+	spe_process_context_write_data_t spe_write;
+	spe_process_context_read_data_t  spe_read;
+}
+myqsort_pthread;
+
+
+
+
+
+void *my_qsort(void *arg)
+{
+	myqsort_pthread *pthread_arg = (myqsort_pthread *)arg;
+
+	int fd;
+	if ((fd = open("/dev/spe_manager", O_RDWR)) == -1)
+	{
+		printf("Can't open /dev/spe_manager.\n");
+		return (void *)-1;
+	}
+	lseek(fd, 0, SEEK_SET);
+	write(fd, &(pthread_arg->spe_write), sizeof(pthread_arg->spe_write));
+	ioctl(fd, SPE_MANAGER_IOCTL_START_PROCESS);
+
+	do
+	{
+		lseek(fd, 0, SEEK_SET);
+		read(fd, &(pthread_arg->spe_read), sizeof(pthread_arg->spe_read));
+	}
+	while (pthread_arg->spe_read.status != SPE_PROCESS_CONTEXT_STATUS_NOT_RELEASED);
+	close(fd);
+
+	unsigned int ret = (unsigned int)(pthread_arg->spe_read.ret);
+
+	if (ret > 0)
+	{
+		myqsort_pthread *left, *right;
+		if (posix_memalign((void **)&left, 16, sizeof(myqsort_pthread)) != 0)
+			return (void *)-1;
+		if (posix_memalign((void **)&right, 16, sizeof(myqsort_pthread)) != 0)
+			return (void *)-1;
+
+		pthread_t p_left, p_right;
+
+		left->info.ea             = pthread_arg->info.ea;
+		left->info.count          = ret;
+		left->spe_write.pgm_start = (uint64_t)buffer;
+		left->spe_write.pgm_size  = 1448;
+		left->spe_write.arg       = (uint64_t)&(left->info);
+
+		pthread_create(&p_left, NULL, my_qsort, (void *)left);
+
+		right->info.ea             = pthread_arg->info.ea + 16 * ret;
+		right->info.count          = pthread_arg->info.count - ret;
+		right->spe_write.pgm_start = (uint64_t)buffer;
+		right->spe_write.pgm_size  = 1448;
+		right->spe_write.arg       = (uint64_t)&(right->info);
+
+		pthread_create(&p_right, NULL, my_qsort, (void *)right);
+
+
+		pthread_join(p_left, NULL);
+		pthread_join(p_right, NULL);
+	}
+
+	return (void *)0;
+}
+
+
+
+
+
+
+int main(int argc, char *argv[])
+{
+	int fd_mmap;
+	if ((fd_mmap = open("../../spe_programs/002_qsort/spe", O_RDONLY)) == -1)
+	{
+		printf("Can't open spe program.\n");
+		return -1;
+	}
+	printf("fd_mmap: %d\n", fd_mmap);
+
+	read(fd_mmap, buffer, 1600);
+
+	close(fd_mmap);
+
+
+	printf("buffer = 0x%016lx\n", (uint64_t)buffer);
+	printf("info   = 0x%016lx\n", (uint64_t)(&info));
+	printf("data   = 0x%016lx\n", (uint64_t)data);
+
+
+	srand(0);
+	int i;
+	for (i = 0; i < SORT; i++)
+	{
+		data[i].d = (int64_t)rand();
+		printf("[%d] %ld\n", i, data[i].d);
+	}
+
+
+//------------------------------------------------
+//	ここから時間を計測する
+
+	struct timeval tv1, tv2, tv3;
+	int fd;
+
+	gettimeofday(&tv1, NULL);
+	gettimeofday(&tv2, NULL);
+/*
+	spe_write.pgm_start = (uint64_t)buffer;
+	spe_write.pgm_size  = 1448;
+	spe_write.arg       = (uint64_t)(&info);
+*/
+
+	myqsort_pthread *root;
+	if (posix_memalign((void **)&root, 16, sizeof(myqsort_pthread)) != 0)
+		return -1;
+
+	pthread_t p_root;
+
+	root->info.ea             = (uint64_t)data;
+	root->info.count          = SORT;
+	root->spe_write.pgm_start = (uint64_t)buffer;
+	root->spe_write.pgm_size  = 1448;
+	root->spe_write.arg       = (uint64_t)&(root->info);
+
+	pthread_create(&p_root, NULL, my_qsort, (void *)root);
+
+	pthread_join(p_root, NULL);
+
+//	my_qsort(0, SORT);
+
+	gettimeofday(&tv3, NULL);
+
+//	時間計測終了
+//------------------------------------------------
+
+	close(fd);
+	printf("%lu.%06lu\n", tv1.tv_sec, tv1.tv_usec);
+	printf("%lu.%06lu\n", tv2.tv_sec, tv2.tv_usec);
+	printf("%lu.%06lu\n", tv3.tv_sec, tv3.tv_usec);
+	fprintf(stderr, "Done.\n");
+
+	for (i = 0; i < SORT; i++)
+	{
+		printf("[%d] %ld\n", i, data[i].d);
+	}
+//	printf("ret: %lu\n", spe_read.ret);
+
+	return 0;
+}