안녕하세요!!  이번주도 어김 없이 석사(과정)중인 이우영 입니다.


저번주는 감기에 걸려 한주간 고생했습니다 (ㅠ,ㅜ)


오늘은 저번주에 이어 /dev/mem의 memory_lseek, mmap_mem을 알아 보도옥 하겠습니다.



 

먼저 memory_lseek 부터 알아 보겠습니다.


linux/drivers/cahr/mem.c 766 라인 을 보시면


 766static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
 767{
 768        loff_t ret;
 769
 770        mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
 771        switch (orig) {
 772                case 0:
 773                        file->f_pos = offset;
 774                        ret = file->f_pos;
 775                        force_successful_syscall_return();
 776                        break;
 777                case 1:
 778                        file->f_pos += offset;
 779                        ret = file->f_pos;
 780                        force_successful_syscall_return();
 781                        break;
 782                default:
 783                        ret = -EINVAL;
 784        }
 785        mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
 786        return ret;
 787}

파일의 읽고 쓰기는 위치를 지정하는 offset의 위치를 변경하는 함수를 일반적으로 lseek라고 부릅니다.

여기서는 메모리의 읽고 쓸 위치를 변경해 주겠죠?

file의 f_pos 변수가 현재 읽고쓰는 위치를 가지고 있습니다. 이 값을 변경 함으로써 

다음에 읽고 쓰는 위치를 변경 할 수 있습니다.

file->f_ops값을 변경 하기 전에 mutex_lock을 이용하여 임계영역을 보호해 줍니다.

lseek는 orig 값을통해 switch문으로 여러 동작을 정의 합니다.

0 값은 지정한 위치로 file->fops 값을 변경하고,

1 값은 현재 위치에서 offset 값 많큼 더해 준다.

그 외의 값은 에러를 발생 시킨다.


다음으로 


 336static int mmap_mem(struct file * file, struct vm_area_struct * vma)
 337{
 338        size_t size = vma->vm_end - vma->vm_start;
 339
 340        if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
 341                return -EINVAL;
 342
 343        if (!private_mapping_ok(vma))
 344                return -ENOSYS;
 345
 346        if (!range_is_allowed(vma->vm_pgoff, size))
 347                return -EPERM;
 348
 349        if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size,
 350                                                &vma->vm_page_prot))
 351                return -EINVAL;
 352
 353        vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
 354                                                 size,
 355                                                 vma->vm_page_prot);
 356
 357        vma->vm_ops = &mmap_mem_ops;
 358
 359        /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
 360        if (remap_pfn_range(vma,
 361                            vma->vm_start,
 362                            vma->vm_pgoff,
 363                            size,
 364                            vma->vm_page_prot)) {
 365                unmap_devmem(vma->vm_pgoff, size, vma->vm_page_prot);
 366                return -EAGAIN;
 367        }
 368        return 0;
 369}


353라인에서 phys_mem_access_prot 함수를 통해 mem에 접근 권한을 얻어 옵니다.

357라인 에서 mmap_mem_ops주소를 등록 합니다

mmap_mem_ops는 mem.c의 다음 위치에 정의 되어 있습니다.

 328static struct vm_operations_struct mmap_mem_ops = {
 329        .open  = mmap_mem_open,
 330        .close = mmap_mem_close,
 331#ifdef CONFIG_HAVE_IOREMAP_PROT
 332        .access = generic_access_phys
 333#endif
 334};

360라인에서는 remap_pfn_range 함수를 통해 유저공간에 커널 메모리를 매핑한다.

리턴 값이 0일 경우 에러이다. 다시 unmap_devmem을 해주고 에러를 반환한다.

정상일경우 0을 리턴 해줍니다.



오늘도 간단하게만 알아 보았습니다.

다음주는 미리미리 공부해서 실습을 할 수 있도록 준비를 해보겠습니다.

그럼 다음시간에 만나요~