Я пишу системный вызов в ядре Linux, который дает виртуальный адрес и длинный указатель без знака, находит соответствующую запись таблицы страниц и затем копирует ее содержимое в длинный указатель без знака. Вот системный вызов:
SYSCALL_DEFINE2(readMMU, unsigned long, vaddr, unsigned long*, pte) {
unsigned long* kernel_pte;
unsigned char* page_table;
struct task_struct *pid_task;
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *page_te;
unsigned long n;
kernel_pte = kmalloc(sizeof(unsigned long), GFP_KERNEL);
if (copy_from_user(kernel_pte, pte, sizeof(unsigned long)) > 0) {
printk("Error: copy from user returned more than 0\n");
return -1;
}
//System call implementation in between here
printk("Getting Task\n");
pid_task = get_pid_task(find_get_pid(current->pid), PIDTYPE_PID);
printk("Getting pgd\n");
pgd = pgd_offset(pid_task->mm, vaddr);
printk("Getting pud\n");
pud = pud_offset(pgd, vaddr);
printk("Getting pmd\n");
pmd = pmd_offset(pud, vaddr);
printk("Getting pte\n");
page_te = pte_offset_kernel(pmd, vaddr);
*kernel_pte = pte_val(*page_te);
printk("Can we access pte?: %d\n", access_ok(VERIFY_WRITE, pte, sizeof(unsigned long)));
printk("Can we acces kernel_pte?: %d\n", access_ok(VERIFY_READ, kernel_pte, sizeof(unsigned long)));
if ((n = copy_to_user(pte, kernel_pte, sizeof pte)) > 0) {
printk("Error: copy to user returned more than 0\n");
printk("copy to user failed to copy this many bits: %ld\n", n);
return -1;
}
kfree(kernel_pte);
return 0;
}
Вот тестовая программа, вызывающая системный вызов:
int
main (int argc, char ** argv) {
unsigned long vaddr;
unsigned long *pte;
vaddr = (size_t) malloc(sizeof(unsigned long));
/* Print a friendly message */
printf ("Hello from User Space!\n");
/* Call our new system call */
syscall (181, vaddr, pte);
/* Exit the program */
return 0;
}
В настоящее время вызов copy_to_user завершается ошибкой с возвращаемым значением 8, что означает, что он не скопировал ни один элемент kernel_pte в pte. Я проверил pte с помощью access_ok для VERIFY_WRITE, и он возвращается с 1. Однако acces_ok, вызванный kernel_pte с VERIFY_READ, возвращается с 0. Я не уверен, что именно это вызывает сбой copy_to_user, но смотрю на исходный код для copy_to_user похоже, он снова проверяет только указатель пользователя. Так что я немного не понимаю, почему звонок не работает.
access_ok
проверяет только то, что адрес не является адресом ядра. Для успеха copy_to_user адрес должен принадлежать адресному пространству текущего процесса. Вам необходимо проверить программу пользовательского пространства, которая передает адрес системному вызову. - person Tsyvarev   schedule 05.12.2015pte
должно быть правильным, потому что оно было передано в системный вызов из тестовой программы. - person idavison   schedule 05.12.2015pte
в тестовой программе. Или вы должны объявить егоunsigned long
и передать его адрес системному вызову, - person Tsyvarev   schedule 05.12.2015