# HG changeset patch # User Shinji KONO # Date 1252385058 -32400 # Node ID 42f240cc4bc6d23aaa852024367ec875857e0474 From: 太田 篤志 diff -r 000000000000 -r 42f240cc4bc6 driver/Makefile --- /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 diff -r 000000000000 -r 42f240cc4bc6 driver/cdev_handler.c --- /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 // カーネルモジュール全般 +#include // struct inode, struct file +#include // printk +//#include // kmalloc, kfree +#include // vmalloc, vfree +#include // down_interruptible, up +#include // spin_lock, spin_unlock +#include // 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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/cdev_handler.h --- /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 + + +// 外部から参照される関数 +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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/critical.c --- /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 // カーネルモジュール全般 +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/critical.h --- /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 +#include + + +// 外部から参照される関数 +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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/interrupt.c --- /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 // カーネルモジュール全般 +#include // printk +#include // kmalloc, kfree +#include // request_irq, free_irq +#include // ps3_irq_plug_setup, ps3_irq_plug_destroy +#include // ioremap, iounmap, in_xx, out_xx + +#include // 暫定 +#include // 暫定 + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/interrupt.h --- /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 + + +// 以下のストップコード定数は 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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/lspe.c --- /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 // カーネルモジュール全般 +#include // printk +#include // kmalloc, kfree +#include // request_irq, free_irq +#include // ps3_irq_plug_setup, ps3_irq_plug_destroy +#include // ioremap, iounmap + +#include // 暫定 + +#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); +} diff -r 000000000000 -r 42f240cc4bc6 driver/lspe.h --- /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 // 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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/main.c --- /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 // カーネルモジュール全般 +#include // __init, __exit, module_init, module_exit +#include // printk +#include // register_chrdev_region, unregister_chrdev_region +#include // cdev_init, cdev_add, cdev_del +#include // create_proc_entry, remove_proc_entry + +#include // 暫定 +#include // 暫定 + +#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"); // 一応(^^; +} diff -r 000000000000 -r 42f240cc4bc6 driver/main.h --- /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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/process_list.c --- /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 // カーネルモジュール全般 + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/process_list.h --- /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*/ diff -r 000000000000 -r 42f240cc4bc6 driver/procfs/hypervisor.c --- /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 // カーネルモジュール全般 +#include // printk +#include // 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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/procfs/hypervisor.h --- /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 + + +// 外部から参照される関数 +int procfs_hypervisor_read(char *, char **, off_t, int, int *, void *); + + +#endif /*SPE_MANAGER__PROCFS__HYPERVISOR_H*/ diff -r 000000000000 -r 42f240cc4bc6 driver/procfs/processes.c --- /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 // カーネルモジュール全般 +#include // printk +#include // down_interruptible, up +#include // 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; +} diff -r 000000000000 -r 42f240cc4bc6 driver/procfs/processes.h --- /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 + + +// 外部から参照される関数 +int procfs_processes_read(char *, char **, off_t, int, int *, void *); + + +#endif /*SPE_MANAGER__PROCFS__PROCESSES_H*/ diff -r 000000000000 -r 42f240cc4bc6 include/hvcalls/common.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 +#include + + +// 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*/ diff -r 000000000000 -r 42f240cc4bc6 include/hvcalls/ppe.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 +#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*/ diff -r 000000000000 -r 42f240cc4bc6 include/hvcalls/repository.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 +#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*/ diff -r 000000000000 -r 42f240cc4bc6 include/hvcalls/spe.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 +#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*/ diff -r 000000000000 -r 42f240cc4bc6 include/ioctl.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 + + +#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*/ diff -r 000000000000 -r 42f240cc4bc6 include/spe_process.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*/ diff -r 000000000000 -r 42f240cc4bc6 kernel/Makefile --- /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) diff -r 000000000000 -r 42f240cc4bc6 kernel/convert --- /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 + $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 = << +#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*/); // プロセスコンテキストの書き出し完了を保証 +} diff -r 000000000000 -r 42f240cc4bc6 kernel/kernel.ld --- /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__ = .; + } +} diff -r 000000000000 -r 42f240cc4bc6 spe_programs/001_overhead/Makefile --- /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) diff -r 000000000000 -r 42f240cc4bc6 spe_programs/001_overhead/spe.c --- /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; +} diff -r 000000000000 -r 42f240cc4bc6 spe_programs/001_overhead/spe.ld --- /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) + } +} diff -r 000000000000 -r 42f240cc4bc6 spe_programs/002_qsort/Makefile --- /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) diff -r 000000000000 -r 42f240cc4bc6 spe_programs/002_qsort/spe.c --- /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 + +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; +} diff -r 000000000000 -r 42f240cc4bc6 spe_programs/002_qsort/spe.ld --- /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) + } +} diff -r 000000000000 -r 42f240cc4bc6 tests/001_090722/001.c --- /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 +#include +#include +#include +#include +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 tests/002_090722/002.c --- /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 +#include +#include +#include +#include +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 tests/003_090809/003.c --- /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 +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 tests/004_090809/004.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 tests/005_forJSASS_1/005.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff -r 000000000000 -r 42f240cc4bc6 tests/005_forJSASS_1/005.exec --- /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 diff -r 000000000000 -r 42f240cc4bc6 tests/006_qsort/006.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}