캐릭터 장치 또는 캐릭터 특수 파일은 어떻게 작동합니까?


22

문자 특수 파일을 이해하려고합니다. 에서 위키 피 디아 , 나는이 파일이 장치에 대한 "인터페이스를 제공한다"고 이해를 한 번에 전송 데이터를 하나 개의 문자가. 내 이해는 시스템이 장치 드라이버를 직접 호출하는 대신 어떻게 든 문자 장치를 호출한다는 것입니다. 그러나 파일은 어떻게이 인터페이스를 제공합니까? 시스템 호출을 번역하는 실행 파일입니까? 누군가 무슨 일인지 설명 할 수 있습니까?

답변:


19

그들은 실제로 인터페이스입니다. "major"와 "minor"번호로 인코딩되어 커널에 연결됩니다.

문자 장치와 블록 장치라는 두 가지 맛이 있습니다 (물론 세 가지이지만 명명 된 파이프는이 설명의 범위를 벗어났습니다).

블록 장치는 출력을 버퍼링하고 나중에 검색하기 위해 데이터를 저장할 수있는 저장 장치 인 경향이 있습니다.

문자 장치는 오디오 또는 그래픽 카드 또는 키보드 및 마우스와 같은 입력 장치입니다.

각각의 경우 커널이 올바른 드라이버를로드 할 때 (부팅시 또는 udev 와 같은 프로그램을 통해 ) 다양한 버스를 스캔하여 해당 드라이버가 처리하는 장치가 실제로 시스템에 있는지 확인합니다. 그렇다면 적절한 주 / 부 번호를 '듣는'장치를 설정합니다.

(예를 들어, 시스템에서 찾은 첫 번째 오디오 카드의 디지털 신호 프로세서는 14/3의 주 / 부 숫자 쌍을 받고, 두 번째는 14,35 등을 얻습니다.)

major 14 minor 3으로 표시된 문자 장치로 /dev이름이 지정된 항목을 작성하는 것은 udev에 달려 있습니다 dsp.

Linux의 이전 또는 최소 설치 공간 버전에서는 /dev/동적으로로드되지 않고 가능한 모든 장치 파일이 정적으로 포함되어있을 수 있습니다.

그런 다음 사용자 공간 프로그램이 적절한 주 / 부 번호를 가진 '특수 문자 파일'로 표시된 파일에 액세스하려고하면 (예 : 오디오 플레이어가 디지털 오디오를 보내려고하는 /dev/dsp경우) 커널은이 데이터가 메이저 / 마이너 번호가 첨부 된 드라이버를 통해 전송되고; 아마도 운전자는 그와 함께 무엇을해야할지 알고있을 것입니다.


1
1. 메이저 / 마이너 숫자가 포트와 유사합니까?
bernie2436

2. 프로그램이 파일에 액세스 할 때 커널은이 특수 인터페이스를 읽어 프로그램이 특정 장치에서 인터럽트를 받아야하는지 여부를 알 수 있습니까? 예 : 프로그램이 단어 파일을 열면 프로그램이 키보드 입력에 응답해야한다는 것을 알기 위해 문자 장치 특수 파일을 읽습니까?
bernie2436

1) 다소 . 가난한 사람의 비유이지만 그렇게 할 것입니다.
Shadur

2
2) 추상화의 3 ~ 4 층이 누락되었습니다. 텍스트 파일을 여는 프로그램은 키보드 장치가 무엇인지 모르거나 신경 쓰지 않습니다. 기본 하드웨어와의 통신은 터미널 에뮬레이터 (콘솔 모드에있는 경우) 또는 X 이벤트 레이어 (그래픽 모드에있는 경우)를 통해 이루어지며, 둘 중 하나는 키보드와 다른 드라이브를 듣고 무엇을 결정합니다 혹시라도 프로그램에 전달해야합니다. 여기서는 상당히 복잡한 다층 시스템을 요약하고 있습니다. 일반적으로 X Window System을 읽는 것이 좋습니다.
Shadur

1
UN * X의 일부 특징에는 저장 장치를위한 문자 특수 파일이 있습니다. 특수 파일에 대한 읽기 또는 쓰기는 장치의 일련의 블록에 대한 읽기 또는 쓰기로 바뀝니다. (최근 버전의 FreeBSD에서는 저장 장치를위한 유일한 특수 파일입니다 . 블록 특수 파일 없습니다.)

10

모든 파일, 장치 등은 VFS 내에서 6 가지 기본 작업을 지원합니다.

  1. 열다
  2. 닫기
  3. 독서
  4. 쓰다
  5. 목표물 탐색

또한 장치 파일은 I / O 제어를 지원하여 처음 6에서 다루지 않은 기타 기타 작업을 허용합니다.

캐릭터 스페셜의 경우, 시크 앤텔은 스트리밍 인터페이스 를 지원하므로 구현되지 않습니다 . 즉, 쉘에서 리디렉션과 같이 직접 읽거나 쓰는 것은 다음과 같습니다.

echo 'foo' > /dev/some/char
sed ... < /dev/some/char

6

최소 실행 가능 file_operations

최소한의 예를 보면 모두 분명해집니다.

핵심 아이디어는 다음과 같습니다.

  • file_operations 각 파일 관련 syscall에 대한 콜백을 포함합니다.
  • mknod <path> c <major> <minor> 그것들을 사용하는 캐릭터 장치를 만듭니다 file_operations
  • 장치 번호를 동적으로 할당하는 문자 장치 (충돌을 피하기위한 표준)의 경우 cat /proc/devices

character_device.ko 커널 모듈 :

#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <uapi/linux/stat.h> /* S_IRUSR */

#define NAME "lkmc_character_device"

MODULE_LICENSE("GPL");

static int major;

static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
    size_t ret;
    char kbuf[] = {'a', 'b', 'c', 'd'};

    ret = 0;
    if (*off == 0) {
        if (copy_to_user(buf, kbuf, sizeof(kbuf))) {
            ret = -EFAULT;
        } else {
            ret = sizeof(kbuf);
            *off = 1;
        }
    }
    return ret;
}

static const struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = read,
};

static int myinit(void)
{
    major = register_chrdev(0, NAME, &fops);
    return 0;
}

static void myexit(void)
{
    unregister_chrdev(major, NAME);
}

module_init(myinit)
module_exit(myexit)

유저 랜드 테스트 프로그램 :

insmod /character_device.ko
dev="lkmc_character_device"
major="$(grep "$dev" /proc/devices | cut -d ' ' -f 1)"
mknod "/dev/$dev" c "$major" 0
cat /dev/lkmc_character_device
# => abcd
rm /dev/lkmc_character_device
rmmod character_device

GitHub QEMU + 보일러 플레이트가있는 Buildroot 업스트림 :

더 복잡한 예 :


정말 도움이되었습니다! 단 하나의 질문, 이것이 정확히 무엇을 *off = 1;하며 왜 설정되어 1있습니까?
SilverSlash

1
@SilverSlash 해당 값은 여러 파일 read호출에서 동일한 open(파일 설명 자로 전달 됩니다. 운전자는 원하는대로 무엇이든 할 수 있습니다. 일반적인 의미는 읽은 바이트 수를 포함하는 것입니다. 그러나이 예제에서는 0첫 번째 읽기 1후 첫 번째 읽기에 대해 더 간단한 의미를 갖 습니다. 그것을 실행하고 printk 또는 GDB 단계를 디버깅하십시오.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

4

"한 번에 캐릭터"는 잘못된 이름입니다 (캐릭터 장치가 찾기와 말하기를 반드시 지원하지 않는다는 생각과 마찬가지로). 실제로 "한 번에 차단"(즉, 테이프 드라이브와 같은 레코드 지향 *) 장치 문자 장치 여야 합니다. 캐릭터 장치는 반드시 보이지 않아야한다는 생각입니다. 캐릭터 장치 드라이버 file_operations는 장치가 작업을 지원하는지 여부에 따라 무료로 정의 할 수 있는 전체 구조를 정의합니다. 대부분의 사람들이 예로 생각하는 문자 장치는 null, urandom, TTY 장치, 사운드 카드, 마우스 등입니다.이 장치의 특성으로 인해 모두 사용할 수는 없지만 / dev / vcs, / dev / fb0 및 / dev / kmem도 문자 장치이며 모두 검색 가능합니다.

앞에서 언급했듯이 문자 장치 드라이버는 파일에서 검색, 읽기, 쓰기, ioctl 등 모든 파일에 대해 호출하려는 모든 작업에 대한 함수 포인터가있는 file_operations 구조를 정의하며 해당 시스템 호출시 각각 한 번 호출됩니다. 이 장치 파일을 연 상태에서 실행됩니다. 따라서 읽기와 쓰기는 논증으로 원하는 모든 것을 할 수 있습니다. 너무 큰 쓰기를 받아들이기를 거부하거나 적합한 것을 쓰기 만 할 수 있습니다. 요청 된 전체 바이트 수가 아니라 하나의 레코드에 해당하는 데이터 만 읽을 수 있습니다.

그렇다면 블록 장치 란 무엇입니까? 기본적으로 블록 장치는 디스크 드라이브입니다. 다른 종류의 장치 ( 램 디스크 및 루프백과 같은 가상 디스크 드라이브 제외 )는 블록 장치가 아닙니다 . 사용자 프로세스에서 / dev / sda에 액세스하는 경우에도 문자 장치가없는 방식으로 I / O 요청 시스템, 파일 시스템 계층, 버퍼 / 캐시 시스템 및 가상 메모리 시스템에 통합 됩니다. . 페이지에서 예외 언급 한 "원시 장치"조차도 문자 장치 입니다.

* 일부 UNIX 시스템은 현재 "고정 블록 모드"를 구현했습니다.이를 통해 커널 그룹 및 분할 I / O 요청이 디스크 드라이브와 거의 동일한 방식으로 구성된 블록 경계에 맞게 블록으로 구성됩니다. 장치. "변수 블록 모드"에는 문자 장치가 필요합니다.이 변수 블록은 단일 write (2) 호출이 하나의 블록을 쓰고 단일 read (2) 호출이 하나의 블록을 반환하므로 사용자 프로그램의 블록 경계를 유지합니다. 모드 전환은 이제 별도의 장치 파일이 아닌 ioctl로 구현되므로 문자 장치가 사용됩니다. 가변 레코드 테이프 드라이브는 탐색에 여러 바이트가 아닌 여러 레코드의 수를 포함하고 기본 탐색 조작이 ioctl로 구현되기 때문에 대부분 "검색 할 수없는"것입니다.


1

문자 장치는 커널 모듈 (또는 커널 자체)로 만들 수 있습니다. 장치를 만들 때 작성자는 open, read 등과 같은 표준 처리를 구현하는 함수에 대한 포인터를 제공합니다. 그런 다음 Linux 커널은 이러한 기능을 문자 장치와 연결합니다. 예를 들어 사용자 모드 응용 프로그램이 read () 문자 장치 파일에서 함수를 호출하면 syscall이 발생하고 커널은이 호출을 드라이버 작성시 지정된 읽기 함수로 라우팅합니다. 문자 장치를 만드는 방법에 대한 단계별 튜토리얼있다 여기가 , 당신은 샘플 프로젝트와 핸들러를 호출하는 방법과 장치 개체가 생성되고 때 이해하기 디버거를 사용하여 그것을 통해 단계를 만들 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.