안녕하세요~ 호서대학교 석사(과정) 이우영 입니다.

 

점점 루즈해져 가는것 같습니다 ㅎㅎ.

 

오늘은 다시 잼있게 해봅시다!

 

/dev/mem


 /dev/mem 은 메모리를 컨트롤 하는 디바이스라고 했습니다.

 

그럼 어떻게 제어하는지 알아 볼까요?

 

mem의 file_operations 는 다음과 같이 구성되어 있습니다.

 

802 static const struct file_operations mem_fops = {
803        .llseek         = memory_lseek,
804        .read           = read_mem,
805        .write          = write_mem,
806        .mmap           = mmap_mem,
807        .open           = open_mem,
808        .get_unmapped_area = get_unmapped_area_mem,
809};

먼전 open_mem 부터 보면 다음과 같이 define 되어 실제로는 open_port 함수를 봐야 합니다.

 

 798#define open_mem        open_port

open_port 함수는 다음과 같습니다.

 

789static int open_port(struct inode * inode, struct file * filp)
790{
791        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
792}

capable 이라는 함수를 사용하는데요 이건 실제로 연산을 수행 할 수 있는지 검사하는 루틴입니다.

 

이 함수의 리터 값을 받아 0 이나 에러 코드를 리턴 해 줍니다.

 

다음은 read_mem 입니다. 주석을 보면 물리적 메모리에서 읽어 들인다고 나와 있습니다.

 

 113/*
114 * This funcion reads the *physical* memory. The f_pos points directly to the
115 * memory location.
116 */
117static ssize_t read_mem(struct file * file, char __user * buf,
118                        size_t count, loff_t *ppos)
119{
120        unsigned long p = *ppos;
121        ssize_t read, sz;
122        char *ptr;
123
124        if (!valid_phys_addr_range(p, count))
125                return -EFAULT;
126        read = 0;
127#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
128        /* we don't have page 0 mapped on sparc and m68k.. */
129        if (p < PAGE_SIZE) {
130                sz = PAGE_SIZE - p;
131                if (sz > count)
132                        sz = count;
133                if (sz > 0) {
134                        if (clear_user(buf, sz))
135                                return -EFAULT;
136                        buf += sz;
137                        p += sz;
138                        count -= sz;
139                        read += sz;
140                }
141        }
142#endif
143
144        while (count > 0) {
145                /*
146 * Handle first page in case it's not aligned
147 */
148                if (-p & (PAGE_SIZE - 1))
149                        sz = -p & (PAGE_SIZE - 1);
150                else
151                        sz = PAGE_SIZE;
152
153                sz = min_t(unsigned long, sz, count);
154
155                if (!range_is_allowed(p >> PAGE_SHIFT, count))
156                        return -EPERM;
157
158                /*
159 * On ia64 if a page has been mapped somewhere as
160 * uncached, then it must also be accessed uncached
161 * by the kernel or data corruption may occur
162 */
163                ptr = xlate_dev_mem_ptr(p);
164                if (!ptr)
165                        return -EFAULT;
166
167                if (copy_to_user(buf, ptr, sz)) {
168                        unxlate_dev_mem_ptr(p, ptr);
169                        return -EFAULT;
170                }
171
172                unxlate_dev_mem_ptr(p, ptr);
173
174                buf += sz;
175                p += sz;
176                count -= sz;
177                read += sz;
178        }
179
180        *ppos += read;
181        return read;
182}

일단 valid_phys_addr_range 를 통해 읽고 쓰기에 문제가 없는지 확인 합니다.

(127~142 라인은 m68k 아키텍터에 따른 소스이기 때문에 보실 필요는 없습니다.)

 

기본적으로 while 문을 돌면서 count 값이 0이 될때 까지 읽기 작업을 합니다.

 

163라인에서 xlate_dev_mem_ptr을 통해 가상주소를 물리주소로 변환해 옵니다.

 

167라인에서 buf로 PAGE_SIZE 만큼 읽어 오고

 

다음에 읽은 data를 쓸수 있도록 buf의 주소공간을 읽어 들인 만큼 더해줍니다.

 

p(파일의 읽는 위치) 도 증가 시키고 read(읽어들인 총 크기) 도 증가 시킵니다.

 

count (읽어야 하는 남은 크기)값은 반대로 감소 시켜줍니다.

 

count 값이 0이 되면 ppos의 값을 읽어 들인 크기 만큼 증가시키고

 

read를 리턴해 얼마만큼 읽어 들였는지 알려 줍니다.

(원리는 생각 보다 간단하죠? 하지만 구현하라고 하면 못합니다 ㅎㅎ)

 

weite_mem도 형식은 read_mem과 같습니다.

 

그저 copy_to_user 에서 copy_from_user로 변했습니다.

(써야 하니까요 ㅎㅎ)

 

소스코드는 다음과 같습니다.

 

 184static ssize_t write_mem(struct file * file, const char __user * buf,
185                         size_t count, loff_t *ppos)
186{
187        unsigned long p = *ppos;
188        ssize_t written, sz;
189        unsigned long copied;
190        void *ptr;
191
192        if (!valid_phys_addr_range(p, count))
193                return -EFAULT;
194
195        written = 0;
196
197#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
198        /* we don't have page 0 mapped on sparc and m68k.. */
199        if (p < PAGE_SIZE) {
200                unsigned long sz = PAGE_SIZE - p;
201                if (sz > count)
202                        sz = count;
203                /* Hmm. Do something? */
204                buf += sz;
205                p += sz;
206                count -= sz;
207                written += sz;
208        }
209#endif
210
211        while (count > 0) {
212                /*
213 * Handle first page in case it's not aligned
214 */
215                if (-p & (PAGE_SIZE - 1))
216                        sz = -p & (PAGE_SIZE - 1);
217                else
218                        sz = PAGE_SIZE;
219
220                sz = min_t(unsigned long, sz, count);
221
222                if (!range_is_allowed(p >> PAGE_SHIFT, sz))
223                        return -EPERM;
224
225                /*
226 * On ia64 if a page has been mapped somewhere as
227 * uncached, then it must also be accessed uncached
228 * by the kernel or data corruption may occur
229 */
230                ptr = xlate_dev_mem_ptr(p);
231                if (!ptr) {
232                        if (written)
233                                break;
234                        return -EFAULT;
235                }
236
237                copied = copy_from_user(ptr, buf, sz);
238                if (copied) {
239                        written += sz - copied;
240                        unxlate_dev_mem_ptr(p, ptr);
241                        if (written)
242                                break;
243                        return -EFAULT;
244                }
245
246                unxlate_dev_mem_ptr(p, ptr);
247
248                buf += sz;
249                p += sz;
250                count -= sz;
251                written += sz;
252        }
253
254        *ppos += written;
255        return written;
256}

오늘은 /dev/mem의 읽기와 쓰기 그리고 open에 대해서 알아 보았습니다.

 

다음은 남은 부분을 해보도록 하겠습니다.

(실습도 만들어 봐야 하는대..; 음 고민입니다 ㅎㅎ)

 

그럼 다음시간에 만나겠습니다.

 

http://ms-osek.org/ <- 쫌더 빨리 보고 싶으신분은 여기로 오세요~