システムコール下のDSは?
Rev.1を表示中。最新版はこちら。
ユーザプロセスが、システムコールでカーネルモードに入ってとき、CS/DSはカーネルの__KERNEL_CS/__KERNEL_DSで動作しているものとばっかし思っていた。システムコールがコールされると、アセンブラで記述されたsystem_callへ処理が移る。そこでaxにセットされたシステムコールNOから、その処理へとコールされるが、その前にSAVE_ALLマクロで、レジスタをpush。でその後DSセレクタに__USER_DSを設定してる・・・。と言うことは、システムコール下のカーネルパスは、__USER_DSで動作しているってわけ?
.macro SAVE_ALL cld PUSH_GS pushl_cfi %fs pushl_cfi %es pushl_cfi %ds pushl_cfi %eax CFI_REL_OFFSET eax, 0 pushl_cfi %ebp CFI_REL_OFFSET ebp, 0 pushl_cfi %edi CFI_REL_OFFSET edi, 0 pushl_cfi %esi CFI_REL_OFFSET esi, 0 pushl_cfi %edx CFI_REL_OFFSET edx, 0 pushl_cfi %ecx CFI_REL_OFFSET ecx, 0 pushl_cfi %ebx CFI_REL_OFFSET ebx, 0 movl $(__USER_DS), %edx movl %edx, %ds movl %edx, %es movl $(__KERNEL_PERCPU), %edx movl %edx, %fs SET_KERNEL_GS %edx .endmとりあえず、実際どうなのか見てみるのが一番ってことで、/proc/hogehogeのwrite時のDSを確認するサンプル。
#include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> #define PROC_NAME "hogehoge" static void myget_ds(const char* msg); static void myset_ds(void); static size_t proc_write( struct file *filp, char __user *buff, unsigned long len, void *data ); static struct proc_dir_entry *dirp; char *k_buff = "abc"; static int proc_init_module(void) { printk("kernel[%x] user[%x]\n", __KERNEL_DS, __USER_DS); dirp = (struct proc_dir_entry *) create_proc_entry(PROC_NAME, 0666, (struct proc_dir_entry *) 0); if (dirp == 0) return(-EINVAL); dirp->write_proc = (write_proc_t *) proc_write; return 0; } static void proc_cleanup_module(void) { remove_proc_entry(PROC_NAME, (struct proc_dir_entry *) 0); } static size_t proc_write( struct file *filp, char __user *u_buff, unsigned long len, void *data ) { int i = 0; myget_ds("proc_write start");
while (1) { if (u_buff[i] == 0x0a) { u_buff[i] = 0x00; break; } i++; } printk("kbuff:[%p]:[%s]\n", k_buff, k_buff); printk("ubuff:[%p]:[%s]\n", u_buff, u_buff); myget_ds("proc_write end"); return len; } static void myset_ds(void) { asm ("movw $0x68, %ax;" "movw %ax, %ds;"); } static void myget_ds(const char* msg) { short int ds;
asm ("movw %%ds, %%ax;" "movw %%ax, %0;" :"=r"(ds) : :"%ax"); printk("ds %s:%x\n", msg, ds); } module_init(proc_init_module); module_exit(proc_cleanup_module);動作結果1
DS=7bの__USER_DS下で動作している。
[76758.013174] kernel[68] user[7b] <-__KERNEL_DS=0x68/__USER_DS=0x7b [76770.346988] ds proc_write start:7b [76770.346998] kbuff:[e0aa608e]:[abc] [76770.347002] ubuff:[b7477000]:[123] [76770.347005] ds proc_write end:7b <-__USER_DS動作結果2(proc_write()のmyset_ds()を有効にして__KERNEL_DSで動作)
DS=68の__KERNEL_DSにしても問題なさそう。
[77591.594712] ds proc_write start:7b [77591.594712] kbuff:[e0a6e08e]:[abc] [77591.594712] ubuff:[b7477000]:[123] [77591.594712] ds proc_write end:68 <-__KERNEL_DS確か__USER_DS/__KERNEL_DSとも、DPLのみの違いで、ペース=0/リミット=0xfffffのはず。カーネルモードでのアクセスには支障はないんだろうけど・・・? でもなんで、わざわざSAVE_ALLマクロで__USER_DSに設定するのかな? セキュリィティ上の理由? X86のプロテクトモードわかっておりません。
カーネルスレッドはどうなのかな?