- Published on
I/O
- Authors

- Name
- valery
1. I/O Hardware(물리적으로 어떻게 구성되어있는지)
device controller, device register
1. Bus 구조
2. Device Controller (host adapter)
1. 장치의 두 구성요소
- Mechanical component (기계부)
- Electronic component (= controller 들어있음)
2. Controller가 하는일
- 직렬 비트 스트림 → 바이트 블록 변환
- 메인 메모리에 전달
- 필요시 에러 정정
- 여러 장치 동시 핸들 가능
3. Device Registers
- 종류: data-in / data-out / status / control (1~4 byte 또는 FIFO)
- 보통 1~4 byte, 또는 FIFO 버퍼
2. 레지스터에 읽거나 쓰는 방법 2가지 ← ※ #2.2와 동일 개념(중복)
- Direct I/O / Memory-mapped
3. 예시: Simple Printer
- status register: done bit(출력 완료) / error bit(종이 걸림·종이 없음)
- data register: 출력할 데이터
- CPU 동작: done bit 셋 될 때까지 대기 + 반드시 error bit 확인
2. I/O Device(동작을 5가지 관점으로 분류)
1. 데이터를 무슨 단위로 주고 받냐?
1. Block(고정 블록)
- 정의: 고정 크기 블록 단위로 정보 저장, 각 블록마다 고유 주소가 있음
- 특징: 블록 크기 512B~32KB / 블록 단위로 독립 read·write / 고유 주소가 있어서 → seek 가능 (랜덤 접근(순차 접근과 반대의 개념, 랜덤으로 접근한다는 말이 아니라 건너 뛰어서 원하는 위치를 딱 찾을 수 있다.))
- 예시: 디스크, 테이프
2. Character(문자 스트림)
- 정의: 문자 스트림을 한 글자씩 주고받음
- 특징: 주소 없음(not addressable) / seek 불가 (순차적)
- 예시: 프린터, 모뎀, 마우스, 키보드
2. CPU가 장치 레지스터에 어떻게 접근하냐?
1. Direct I/O(전용 명령어)
CPU 입장에서 주소공간이 두 개 있다 — 하나는 메모리 주소공간(RAM 읽고 쓰는 곳), 또 하나는 I/O 포트 주소공간(장치 레지스터 있는 곳).
이 둘이 완전히 분리돼 있어서, 메모리 접근하는 명령어로는 장치에 못 가고 in/out 같은 전용 명령어를 따로 써야한다
2. Memory-mapped(메모리 주소)
- 정의: 장치 제어 레지스터를 프로세서의 메모리 주소공간 안에 매핑 → 레지스터를 그냥 메모리 주소처럼 취급
- 특징: 별도 I/O 명령어 없이 표준 데이터 전송 명령어(load/store)로 접근
- 장점:
- 드라이버를 순수 C로 작성 가능 (어셈블리 in/out 불필요)
- 별도 보호 메커니즘 불필요 → 기존 페이지 테이블(PTE)로 보호, 원하는 페이지를 페이지 테이블에 넣어 특정 사용자에게 특정 장치 제어권까지 줄 수 있음
- 레지스터 읽고 값 테스트를 단일 명령어로 처리
3. CPU가 I/O 처리됐는지 어떻게 아나?
1. Polling(계속 확인)
- 정의: CPU가 장치한테 "관심 필요해?"를 직접 반복해서 물어봄(poll)
- 명령 받을 준비됐는지 / 명령 상태가 어떤지 등을 확인
- 장점:
- 단순함 (status register 확인 루프만 돌면 됨)
- 소프트웨어가 제어권을 쥠 (언제 확인할지 CPU가 결정)
- 장치가 곧바로 준비되면 오히려 효율적
- 단점:
- 복잡한 시스템에선 비효율 → CPU 사용률만 높아짐 (busy-wait)
- 낮은 우선순위 장치는 영영 서비스 못 받을 수도
2. Interrupt(신호 받기)
- 정의: 장치가 관심 필요할 때 CPU한테 인터럽트를 요청 → CPU가 알려줄 때까지 기다림
- 특징:
- 장치별 전용 ISR(인터럽트 서비스 루틴)이 호출됨
- 여러 장치가 인터럽트를 공유할 수 있음
- 장점:
- CPU는 진짜 필요할 때만 장치에 개입 (평소엔 다른 일 함)
- 일반적으로 폴링보다 효율적
- 단점:
- 인터럽트가 과도하면 본 프로그램 실행이 느려지거나 막힘
- 오버헤드 (전송 바이트당 인터럽트 1번 필요할 수도) ← 1.4 DMA 등장 이유
- 처리 흐름(7단계):
- 드라이버가 I/O 시작
- 컨트롤러가 I/O 수행
- 완료/에러 시 인터럽트 신호 발생(wait queue -> ready queue로 갈 때 )
- CPU가 인터럽트 받고 핸들러로 제어 넘김
- 핸들러가 데이터 처리 후 복귀
- CPU가 원래 작업 재개 (CPU는 매 명령어 사이마다 인터럽트 들어왔나 확인)
4. 데이터를 실제로 누가 옮기나?
1. Programmed I/O(CPU가 옮기기)
- 정의: CPU가 장치 ↔ 메모리 데이터 이동에 직접 관여 (한 워드씩 CPU 손을 거침)
- 특징: 전용 I/O 명령어 또는 memory-mapped 방식으로 옮김
- 단점: 대용량 전송 시 CPU가 바이트마다 매달려야 함 → CPU 낭비
2. DMA (컨트롤러가 옮기기)
- 정의: DMA 컨트롤러가 CPU를 거치지 않고 장치 ↔ 메모리를 직접 전송
- 특징:
- 메모리 속도에 가깝게 쏟아내는 고속 장치용
- 블록 단위로 버퍼 → 메인 메모리 직접 전송 (CPU 개입 없음)
- 블록당 인터럽트 1번만 발생 ← 1.3.2 "바이트당 인터럽트" 단점 해결
- 처리 흐름(4단계):
- CPU가 DMA 컨트롤러 세팅 (Address/Count/Control 레지스터)
- DMA가 메모리로 전송 요청 → 3. 데이터 직접 전송 → 4. 완료 시 Ack + 인터럽트
5. 호출한 프로세스를 어떻게 기다리나? (프로세스/시스템콜 레벨)
1. Blocking (대기)
- 정의: I/O 끝날 때까지 프로세스가 suspend됨(잠듦)
- 특징: 쓰기 쉽고 이해 쉬움 (코드가 위→아래 순서대로 흐름)
- 예시: read(), write()
- ※ 프로세스 상태도의 run→wait 전환 원인 = 바로 이 blocking I/O
2. Non-blocking (즉시 반환)
- 정의: I/O 콜이 즉시 반환, 지금까지 전송된 바이트 수를 반환값으로 알려줌
- 특징:
- 데이터 없어도 안 기다리고 바로 다음 일 진행
- 멀티스레딩으로 구현
- select()로 데이터 준비됐는지 확인
- 예시: select()
3. I/O Software(커널이 어떻게 추상화 하는지)
1. 목표
장치 독립성, 통일된 이름, 에러처리, 동기/비동기, 버퍼링, 공유/전용
2. Layer
1. User-level I/O Software
- 대부분 라이브러리로 제공 (커널 밖, 유저 공간에서 돎)
- C 표준 I/O 라이브러리: fopen(), fgets(), fscanf() 등 / 직접 만들어도 됨(myopen)
- 핵심 구분 fopen() vs open():
- open() = 시스템콜 (커널 직접 진입)
- fopen() = open()을 감싼 라이브러리 함수 (버퍼링 등 추가)
- 하는 일: I/O 호출 / 포맷팅(printf의 %d) / 스풀링(spooling)
2. Device-independent I/O Software
- 역할: 모든 드라이버 위에 공통으로 얹히는 계층. 3.1 목표(통일된 이름·보호·버퍼링·할당·에러처리)가 실제로 구현되는 곳
- (1) 통일된 인터페이스 (uniform interfacing):
- 파일 보호 규칙이 장치에도 그대로 적용
- (2) 에러 보고 (error reporting):
- 많은 에러가 장치별 특수 → 해당 드라이버가 처리, 프로그래밍 에러 vs 실제 I/O 에러 구분
- 처리 방법 5가지: 에러코드 반환 / 재시도 / 무시 / 호출 프로세스 kill / 시스템 종료
3. Device Drivers
- 정의: 각 I/O 장치를 제어하는 장치별 전용 코드
- 역할/위치:
- 위로는 device-independent I/O 소프트웨어 + 인터럽트 핸들러와 소통, 아래로는 실제 하드웨어 제어
- OS 나머지와 잘 정의된 모델·표준 인터페이스로 연결 → 장치 독립성(3.1)의 실제 구현 담당
- 구현(로드) 방식 3가지:
- 커널에 정적 링크 (박아넣음)
- 부팅 시 선택적 로드
- 실행 중 동적 로드 (핫플러그용 — USB 꽂으면 그때 로드)
- 신뢰성 문제:
- 드라이버가 OS 실패의 주원인 → Windows XP 크래시의 85%가 드라이버
- Linux 커널 코드의 70%가 드라이버, 커널보다 7배 더 버그 많음
- 이유: 경험 적은 개발자가 작성 + 종류 폭발 (XP에 35,000개 드라이버·120,000개 버전)
4. Interrupt Handlers
- I/O 완료 시 드라이버를 깨움 (wake up driver)
5. Hardware
- 실제 I/O 연산 수행