システムコール下の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);
動作結果1DS=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のプロテクトモードわかっておりません。
カーネルスレッドはどうなのかな?




