Mercurial > hg > Game > Atoc
view driver/main.c @ 1:b4285b887e18 default tip
add document
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Sep 2009 17:33:34 +0900 |
parents | 42f240cc4bc6 |
children |
line wrap: on
line source
/** * main.c * SPE プロセスマネージャ spe_manager * spe_manager_init, spe_manager_exit */ #include <linux/module.h> // カーネルモジュール全般 #include <linux/init.h> // __init, __exit, module_init, module_exit #include <linux/kernel.h> // printk #include <linux/fs.h> // register_chrdev_region, unregister_chrdev_region #include <linux/cdev.h> // cdev_init, cdev_add, cdev_del #include <linux/proc_fs.h> // create_proc_entry, remove_proc_entry #include <asm/io.h> // 暫定 #include <asm/mmu-hash64.h> // 暫定 #include "../include/hvcalls/common.h" #include "../include/hvcalls/ppe.h" #include "../include/kernel.h" // Note: SPE 向け軽量カーネルの make を必ず先に行うこと!! #include "main.h" #include "lspe.h" #include "cdev_handler.h" #include "procfs/hypervisor.h" #include "procfs/processes.h" #include "critical.h" #include "process_list.h" #include "../include/spe_process.h" // 暫定 MODULE_LICENSE("GPL"); // これがないと動かない… (^ω^#)ビキビキ // キャラクタデバイス用変数 static struct cdev spe_manager_cdev; static struct file_operations spe_manager_cdev_fopts = { owner: THIS_MODULE, open: spe_manager_open, write: spe_manager_write, ioctl: spe_manager_ioctl, read: spe_manager_read, release: spe_manager_release }; // procfs 用変数 static struct proc_dir_entry *proc_base_dir, *proc_processes, *proc_hypervisor; // 内部で利用する関数 static void transfer_spe_kernel(void); // 後で別ファイルに移す? void initialize_manager(void) { // int i, lspe_count = get_lspe_count(); initialize_critical(); // initialize_spinlocks(); initialize_process_lists(); transfer_spe_kernel(); /* for (i = 0; i < lspe_count; i++) { lspe_data_t *lspe = get_lspe_data(i); *(unsigned int *)(lspe->problem + 0x4034) = SPE_KERNEL_INITIAL_PC | 0x1; asm volatile("eieio"); *(unsigned int *)(lspe->problem + 0x401c) = 1; } asm volatile("eieio"); // 一応(^^; */ } // 後で別ファイルに移す //===================================================================================== set_spu_channel_data_and_count() /** * set_spu_channel_data_and_count * SPU チャネル・データ・レジスタおよび SPU チャネル・カウント・レジスタを設定する * * @param int n SPE 番号 (0..x) * @param unsigned long index SPU チャネル・インデックス * @param long data SPU チャネル・データの設定値 (負数の場合は設定しない) * @param long count SPU チャネル・カウントの設定値 (負数の場合は設定しない) * @return void */ void set_spu_channel_data_and_count(const int n, const unsigned long index, const long data, const long count) { lspe_data_t *lspe = get_lspe_data(n); // SPU チャネル・インデックス・レジスタ out_be64(lspe->priv2 + 0x4060, index); asm volatile("eieio"); if (data >= 0) { // SPU チャネル・データ・レジスタ out_be64(lspe->priv2 + 0x4070, (unsigned long)data); } if (count >= 0) { // SPU チャネル・カウント・レジスタ out_be64(lspe->priv2 + 0x4068, (unsigned long)count); } asm volatile("eieio"); } //================================================================================================== start_spe_process() /** * start_spe_process * SPE プロセスを開始する * * @param int spe_no 論理 SPE 番号 (0..x) * @param spe_process_context_list_t * this_process 開始するプロセスコンテキストへのポインタ * @return void */ void start_spe_process(const int spe_no, spe_process_context_list_t *const this_process) { unsigned long vsid_context, vsid_program; struct task_struct *task; lspe_data_t *lspe = get_lspe_data(spe_no); #if 0 // MFC コマンド・キュー・オペレーションを中断する out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (0UL<<4 /*[Sm]*/ || 1UL<<0 /*[Sc]*/)); asm volatile ("eieio"); do { unsigned long in_cntl = in_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/); if ((in_cntl & 3UL<<8 /*[Ss]*/) == 3UL<<8 /*11*/) break; } while(1); #endif // MFC マルチソース同期レジスタをチェックする out_be32(lspe->problem + 0x00000 /*MFC_MSSync*/, 1); do { unsigned int in_mssync = in_be32(lspe->problem + 0x00000 /*MFC_MSSync*/); if ((in_mssync & 1<<0 /*[S]*/) == 0) break; } while(1); #if 0 // MFC コマンドをパージ (除去) する out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (1UL<<15 /*[Pc]*/ || 1UL<<4 /*[Sm]*/)); asm volatile ("eieio"); do { unsigned long in_cntl = in_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/); if ((in_cntl & 3UL<<24 /*[Ps]*/) == 3UL<<24 /*11*/) break; } while(1); #endif // SPU 特権制御レジスタを初期化 (SPU_PrivCntl[Le,A,S] = 0) out_be64(lspe->priv2 + 0x04040 /*SPU_PrivCntl*/, 0UL); asm volatile ("eieio"); // MFC ステート・レジスタ 1 (MFC_SR1) を初期化 (MFC_SR1[S,R,T,D] = 1) lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0000UL /*MFC_SR1*/, 0x33UL); // SPE SLB エントリを全て無効化 out_be64(lspe->priv2 + 0x01128 /*SLB_Invalidate_All*/, 0UL); // SPU チャネル・データ・レジスタおよびチャネル・カウント・レジスタの初期化 set_spu_channel_data_and_count(spe_no, 0, 0, 0); set_spu_channel_data_and_count(spe_no, 1, 0, -1); set_spu_channel_data_and_count(spe_no, 3, 0, 0); set_spu_channel_data_and_count(spe_no, 4, 0, 0); set_spu_channel_data_and_count(spe_no, 21, -1, 16); set_spu_channel_data_and_count(spe_no, 23, -1, 1); set_spu_channel_data_and_count(spe_no, 24, 0, 0); set_spu_channel_data_and_count(spe_no, 25, 0, 0); set_spu_channel_data_and_count(spe_no, 27, 0, 0); set_spu_channel_data_and_count(spe_no, 28, -1, 1); set_spu_channel_data_and_count(spe_no, 29, -1, 0); set_spu_channel_data_and_count(spe_no, 30, -1, 1); // 特権 1 レジスタ MFC_TClass_ID の初期化 lv1_set_spe_privilege_state_area_1_register(lspe->spe_id, 0x0820UL /*MFC_TClass_ID*/, 0x10000000UL); asm volatile ("eieio"); // MFC コマンド・キュー・オペレーションを再開 out_be64(lspe->priv2 + 0x03000 /*MFC_Cntl*/, (0UL<<4 /*[Sm]*/ || 0UL<<0 /*[Sc]*/)); // this_process->context.read.ret = 0xDEADBEEFDEADBEEF; // asm volatile("sync"); /* unsigned long vsid_process, vsid_program;//, vsid_data; uint64_t esid_data; unsigned long i; HVC_u64 ret; */ // SPE プロセスコンテキストのある実効アドレスに対応する仮想セグメント ID (vsid) を取得 vsid_context = get_kernel_vsid((unsigned long)(&(this_process->context)), 0); // vsid_context = get_kernel_vsid((unsigned long)(&(this_process->context)), sizeof(spe_process_context_t)); // printk(KERN_INFO "[%s] ADDR(this_process->context) = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, (unsigned long)(&(this_process->context))); // printk(KERN_INFO "[%s] vsid_context = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_context); /* printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x00), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x08)); printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x10), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x18)); printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x20), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x28)); printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x30), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x38)); printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x40), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x48)); printk(KERN_INFO "%016lx %016lx\n", *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x50), *(unsigned long *)((unsigned long)(&(this_process->context)) + 0x58)); */ // 登録側プロセスにある SPE プログラムの実効アドレスに対応する仮想セグメント ID (vsid) を取得 vsid_program = get_vsid(current->mm->context.id, this_process->context.write.pgm_start, 0); // printk(KERN_INFO "[%s] pid = %d\n", SPE_MANAGER_MODULE_NAME, current->pid); // printk(KERN_INFO "[%s] context.write.pgm_start = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, this_process->context.write.pgm_start); // printk(KERN_INFO "[%s] vsid_program = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_program); /* for_each_process(task) { if (task->pid == this_process->context.write.pid) { vsid_program = get_vsid(task->mm->context.id, (unsigned long)(this_process->context.write.pgm_start), 0); // vsid_program = get_vsid(task->mm->context.id, (unsigned long)(process->write.program_start), (size_t)(process->write.program_size)); printk(KERN_INFO "[%s] pid = %d\n", SPE_MANAGER_MODULE_NAME, task->pid); printk(KERN_INFO "[%s] current->pid = %d\n", SPE_MANAGER_MODULE_NAME, current->pid); printk(KERN_INFO "[%s] vsid_program = 0x%016lx\n", SPE_MANAGER_MODULE_NAME, vsid_program); break; } } */ // SPE SLB エントリを全て無効化 // out_be64(lspe->priv2 + 0x01128 /*SLB_Invalidate_All*/, 0UL); // vsid_context を SLB エントリに登録 out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, 0UL); out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid_context << 12 | 0x400 /*Kp*/ | 0x000 /*L|LP*/); out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, (unsigned long)(&(this_process->context)) & 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/); // out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/); // vsid_program を SLB エントリに登録 out_be64(lspe->priv2 + 0x01108 /*SLB_Index*/, 1UL); out_be64(lspe->priv2 + 0x01118 /*SLB_VSID*/, vsid_program << 12 | 0xc00 /*Ks|Kp*/ | 0x80 /*C*/ | 0x000 /*L|LP*/); out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, this_process->context.write.pgm_start & 0xFFFFFFFFF0000000UL | 0x8000000UL /*V*/); // out_be64(lspe->priv2 + 0x01110 /*SLB_ESID*/, 0xFFFFFFFFE0000000UL | 0x8000000UL /*V*/); // Note: カーネル空間の vsid には Kp ビット、ユーザ空間の vsid には Ks, Kp, C ビットを付ける。 // (cf. arch/powerpc/platforms/cell/spu_base.c の __spu_trap_data_seg 関数) lspe->mm = current->mm; lspe->slb_index = 2; /* // vsid_data 登録 esid_data = process->write.data_start; for (i = 2UL; i < 16UL; i++, esid_data += 0x10000000UL) { vsid_data = get_vsid(task->mm->context.id, (unsigned long)esid_data); if (vsid_data == vsid_program) continue; *(unsigned long *)(spe_priv2[spe_no] + 0x01108UL) = i; // SLB_Index *(unsigned long *)(spe_priv2[spe_no] + 0x01118UL) = vsid_data << 12; // SLB_VSID *(unsigned long *)(spe_priv2[spe_no] + 0x01110UL) = esid_data & 0xfffffffff0000000UL | 0x8000000UL; } */ // SPE プロセスコンテキストのある実効アドレスは LS の所定の位置に格納 out_be64(lspe->ls + SPE_KERNEL_PROC_CONTEXT_OFFSET, (unsigned long)(&(this_process->context))); // out_be32(lspe->ls + SPE_KERNEL_PROC_CONTEXT_OFFSET, (unsigned int)((unsigned long)(&(this_process->context)) & 0xFFFFFFFUL)); /* // 登録側プロセスにある SPE プログラムの実効アドレスの下位 28bit は LS の所定の位置に格納 out_be32(lspe->ls + SPE_KERNEL_PROGRAM_OFFSET, (unsigned int)((unsigned long)(this_process->context.write.pgm_start) & 0xFFFFFFFUL)); */ asm volatile ("eieio"); out_be32(lspe->problem + 0x0000 /*MFC_MSSync*/, 1); do { unsigned int r = in_be32(lspe->problem + 0x0000 /*MFC_MSSync*/); if (r == 0) break; } while(1); // SPE の実行を開始 out_be32(lspe->problem + 0x4034 /*SPU_NPC*/, SPE_KERNEL_INITIAL_PC | 0x1); out_be32(lspe->problem + 0x401c /*SPU_RunCntl*/, 1); } //=================================================================================================== spe_manager_init() /** * spe_manager_init * デバイスの初期化 * * Note: 以下に示す外部関数参照がある。 * procfs_handler_processes_read (procfs_handler.c) * hvc_get_lpar_id * hvc_get_ppe_id * hvc_get_vas_id * initialize_logical_spes (lspe.c) * initialize_manager * * @return int * @static */ static int __init spe_manager_init(void) { HVC_u64 lpar_id, ppe_id, vas_id; int spes; //-------------------- キャラクタデバイスの登録 if (register_chrdev_region(SPE_MANAGER_DEVICE_ID, 1, SPE_MANAGER_DEVICE_NAME)) { printk(KERN_ERR "[%s] Error: register_chrdev_region() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); // デバイス番号の割り当てができない return -ENODEV; } cdev_init(&spe_manager_cdev, &spe_manager_cdev_fopts); spe_manager_cdev.owner = THIS_MODULE; if (cdev_add(&spe_manager_cdev, SPE_MANAGER_DEVICE_ID, 1)) { printk(KERN_ERR "[%s] Error: cdev_add() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // キャラクタデバイスを追加できない return -ENODEV; } //-------------------- procfs エントリの生成 (デバッグ用途) if (!(proc_base_dir = proc_mkdir(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL))) { printk(KERN_ERR "[%s] Error: proc_mkdir() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // procfs ディレクトリを生成できない return -ENODEV; } if (!(proc_hypervisor = create_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, 0444, proc_base_dir))) { printk(KERN_ERR "[%s] Error: create_proc_entry() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL); cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // procfs エントリを生成できない return -ENODEV; } proc_hypervisor->owner = THIS_MODULE; proc_hypervisor->read_proc = procfs_hypervisor_read; proc_hypervisor->write_proc = NULL; if (!(proc_processes = create_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, 0444, proc_base_dir))) { printk(KERN_ERR "[%s] Error: create_proc_entry() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL); cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // procfs エントリを生成できない return -ENODEV; } proc_processes->owner = THIS_MODULE; proc_processes->read_proc = procfs_processes_read; proc_processes->write_proc = NULL; // 論理パーティション識別子, 論理 PPE 識別子, 仮想アドレス識別子 の取得 hvc_get_lpar_id(&lpar_id); hvc_get_ppe_id(&ppe_id); if (hvc_get_vas_id(ppe_id, &vas_id)) { printk(KERN_ERR "[%s] Error: hvc_get_vas_id() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL); cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // 仮想アドレス識別子を取得できない return -ENODEV; } // 論理 SPE の確保と初期化 if ((spes = initialize_logical_spes(lpar_id, vas_id)) < 1) { printk(KERN_ERR "[%s] Error: initialize_logical_spes() (%s:%u)\n", SPE_MANAGER_MODULE_NAME, __FILE__, __LINE__); // finalize_logical_spes(); // 1 つも確保できていないから不要 remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL); cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); // 使用できる論理 SPE がない return -ENOSPC; } // SPE プロセスマネージャの初期化 initialize_manager(); printk(KERN_INFO "[%s] The module is loaded.\n", SPE_MANAGER_MODULE_NAME); return 0; } //=================================================================================================== spe_manager_exit() /** * spe_manager_exit * キャラクタデバイス解放 * * Note: 以下に示す外部関数参照がある。 * finalize_logical_spes (lspe.c) * * @return void * @static */ static void __exit spe_manager_exit(void) { // 論理 SPE の後始末 finalize_logical_spes(); // procfs エントリとディレクトリの解放 remove_proc_entry(SPE_MANAGER_PROCFS_HYPERVISOR_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_PROCESSES_ENTRY_NAME, proc_base_dir); remove_proc_entry(SPE_MANAGER_PROCFS_BASE_DIR_NAME, NULL); // キャラクタデバイスの削除 cdev_del(&spe_manager_cdev); unregister_chrdev_region(SPE_MANAGER_DEVICE_ID, 1); printk(KERN_INFO "[%s] The module is unloaded.\n", SPE_MANAGER_MODULE_NAME); } module_init(spe_manager_init); module_exit(spe_manager_exit); //================================================================================================ transfer_spe_kernel() /** * transfer_spe_kernel * SPE 向け軽量カーネルを論理 SPE へ転送する * * @return void * @static */ static void transfer_spe_kernel(void) { int i, lspe_count = get_lspe_count(); for (i = 0; i < lspe_count; i++) { lspe_data_t *lspe = get_lspe_data(i); memcpy(lspe->ls, spe_kernel_raw, SPE_KERNEL_SIZE); } asm volatile("eieio"); // 一応(^^; }