본문 바로가기

VEDA 복습/리눅스, 리눅스 프로그래밍

VEDA 50일차 - 리눅스 드라이버

반응형

 

fops > driver call back function

 

지금까지 한 것 : 모듈을 만들고, printk, gpio etc

드라이버 제작을 위해서 알아야하는 기본적인 사항들 :

 

메모리 할당 : 힙(큰 용량 - 큰 변수들 할당, 메모리 할당은 여기를 이야기함)과 스택(작음 - 작은 변수들 할당, 아껴야 함)

    glibc(유저 영역에서 할당자, malloc), slab 할당자(kernel, data < page, kmeme_cache에 정의한 cache 단위로 할당, 페이지      보다 작음, kmalloc(<4mb), kfree, vmalloc(물리적 비연속 공간 메모리 할당, kmalloc보다 느리다.)), buddy 할당자(kernel,     

    data > page, 2^N 단위로 페이지 할당), 프로세스 컨택스트에서 사용

    페이지(page) : 메모리 매핑의 최소 단위, physical(frame) > virtual(page), usually 4KB

    PAGEOFFSET : 유저 영역과 커널 영역을 분리하는 경계

    피지컬 영역에서의 할당(비연속적)과 다르게 가상 영역에서 할당은 연속적

 

buddy system

 정의

buddy 시스템은 연속된 페이지 프레임을 할당/해제하기 위한 메모리 할당 방식입니다.
리눅스에서는 **페이지 단위(보통 4KB)**로 관리하는 물리 메모리 할당을 위해 사용됩니다.

동작 원리

기본 단위 2^n 크기의 블록 (예: 1 페이지, 2 페이지, 4 페이지, 8 페이지, ...)
할당 방식 요청 크기에 맞는 최소한의 블록을 찾아 할당, 없으면 상위 블록을 절반으로 나눔
병합 (해제 시) 해제된 블록의 buddy(짝) 블록이 같은 상태(free)라면 자동으로 병합하여 상위 블록으로 올라감
목적 큰 메모리 블록을 빠르게 할당, 조각화(fragmentation) 문제 완화
예시 페이지 할당 (alloc_pages()), kmalloc()에서 페이지 단위 메모리 확보 시 내부적으로 사용

예제 동작

총 1024KB(1MB) 메모리 → 1KB 요청:

  • 1MB → 512KB → 256KB → 128KB → 64KB → 32KB → 16KB → 8KB → 4KB → 2KB → 1KB

요청 크기에 맞게 재귀적으로 쪼갬.

1KB 블록 해제:

  • buddy 블록도 free 상태라면 2KB로 병합 → 반복적으로 상위까지 병합

장점 / 단점

빠른 분할 및 병합 2^n 단위로만 할당 → 내부 단편화 발생
큰 블록 할당에 적합 작은 크기 요청 시 과도한 낭비 가능 (예: 1바이트 요청에도 최소 1 페이지 할당)
메모리 상태 관리가 비교적 단순 작은 객체 관리에는 부적합

slab

정의

slab 할당자는 작은 크기의 커널 객체들을 효율적으로 관리하기 위한 메모리 관리 기법입니다.
특히:

  • struct inode
  • struct dentry
  • task_struct

같은 자주 할당되고 해제되는 작은 객체들을 대상으로 최적화되었습니다.

동작 원리

용어설명
slab 동일한 크기의 객체들이 미리 할당되어 들어가는 메모리 덩어리(캐시 풀)
cache 특정 타입의 slab 풀 (예: inode 캐시, dentry 캐시)
object slab 안에 들어가는 실제 커널 객체
slab page slab은 결국 페이지 단위로 할당되며, 내부적으로 buddy 시스템에서 확보한 연속 페이지를 사용

 작동 과정

커널은 자주 쓰이는 구조체 타입별로 slab 캐시(kmem_cache) 생성
요청이 들어오면:

  • 기존 slab에 free object가 있으면 할당
  • 없으면 새 slab(page 단위)를 buddy system에서 확보 후 채워 넣음

객체가 해제되면 slab 내에서 free 상태로 표시 (메모리는 slab에 남음)

장점 / 단점

작은 객체 반복 할당/해제에서 빠른 성능 slab 관리용 메타데이터 필요
캐싱/미리 초기화로 캐시 적중 시 오버헤드 최소화 slab 사용량이 늘어나면 페이지 단편화 발생 가능
내부 프리 리스트로 락 경쟁 최소화 (per-CPU 캐시 활용 등) slab 사이즈는 고정, 가변 크기 객체 관리에는 부적합
객체 정렬, 캐시 라인 최적화, 버퍼 오버플로 탐지 같은 추가 기능 지원 관리 복잡성 증가

buddy system vs slab

주요 용도 페이지 단위 큰 메모리 블록 관리 커널 객체/작은 크기 메모리 관리
최소 단위 1 페이지 (보통 4KB) 객체 크기에 맞춘 캐시 풀
내부 동작 alloc_pages(), __get_free_pages() 등 kmalloc(), kmem_cache_alloc() 등
기반 관계 slab이 페이지 단위 메모리를 확보할 때 내부적으로 buddy system 사용 slab은 buddy system에서 가져온 페이지를 작은 객체 관리용으로 쪼개서 사용

 

커널과 DMA(Direct Memory Access - CPU와 독립되어 메모리 입출력 담당, 메모리 전송 완료시 인터럽트 발생, INTReq와 DMAreq로 구분됨, DMA는 단순함 - 어디에서, 무엇을(바이트 수), 어디로만 알면됨, DMA 전송을 위해서는 메모리가 비연속적이면 안됨, 만약 비연속적이면 DMA 기능을 사용하지 못한다.)

 

memory pool(상비 메모리)

1. reserve memory : 예약되지 않은 메모리를 사용하다가, kmalloc이 not ok면 reserved된 메모리를 꺼내서 사용한다.

 

인터럽트 처리 : 메모리 동기화 이슈, 인터럽트 처리는 대기 불가(GFP_ATOMIC), 유저 프로세스는 대기 가능(GFP_KERNEL)

인터럽트 처리는 아키텍처마다 다를 수 있다. => 특정 버전 ARM 기준이다.

핀 설정 => 인터럽트 활성화 => 인터럽트 벡터에 함수 등록 => 사용 => 인터럽트 해제

인터럽트 처리 : top half, bottom half(인터럽트 내부에서도 우선 순위가 높은 작업만 우선 수행, 타 인터럽트 수행)

softirq(비추, 쓰지는 말아야 하지만 기존의 네트워크들이 쓰고 있음, 커널 소스 수정 필요), tasklet, workqueue

 

하드웨어 통신, 커널과 쓰레드, 세마포어 경쟁, 블로킹 입출력, 작업의 딜레이

반응형