부팅

  1. 모든 초기화 작업을 마치고 펌웨어가 대기 상태가 될때 까지 상태
  2. ARM 코어가 리셋 익셉션 핸들러를 모두 처리한 다음 C언어 코드로 넘어가기 직전까지

실행 파일은 메모리를 크게 세 가지로 나누어 사용한다.

  1. text 영역
    • 코드가 있는 공간
    • 임의로 변경하면 안됨
  2. data 영역
    • 초기화한 전역 변수가 있는 공간
    • 전역 변수 선언시 초기 값을 할당해서 선언하면 해당 전역 변수가 점유 하는 공간이 할당된됨
  3. BSS영역
    • 초기화하지 않은 전역 변수가 있음
    • 초기화 하지 않은 전역 변수이므로 빈드 완료되어 생성된 바이너리 파일에는 심벌과 크기만 들어 있음

해당 프로젝트에서는 text 영역의 크기를 1MB (0x00000000 ~ 0x000FFFFF), data영역과 bss영역의 할당은 각 모드별로 1MB씩 그냥 할당한다. (크기를 그렇게 신경 안쓰고 일단 할당) RTOS의 위에서 동작할 task stack 영역도 필요하다. 총 64개의 task를 지원할 것이고 task마다 1MB씩 stack 영역을 할당하므로 총 64MB 할당한다. 그 다음 전역 변수용으로 1MB를 할당한다. 남은 공간은 heap으로 사용한다.

영역 주소 (총 128MB)
동적 할당 영역  0x04900000 ~ 0x07FFFFFF (55MB)
전역 변수 영역 0x04800000 ~ 0x48FFFFF (1MB)
태스크 스택 영역 0x00800000 ~ 0x047FFFFF (64MB)
UND 모드 스택 0x00100000 ~ 0x007FFFFF (7MB)
ABT 모드 스택
FIQ 모드 스택
IRQ 모드 스택
SVC 모드 스택
USY/SYS 모드 스택
text 영역  0x00000000 ~ 0x000FFFFF (1MB)

 

.text
    .code 32

    .global vector_start
    .global vector_end

    vector_start:
    	//exception vector table이 작성됨
        LDR PC, reset_handler_addr
        LDR PC, undef_handler_addr
        LDR PC, svc_handler_addr
        LDR PC, pftch_abt_handler_addr
        LDR PC, data_abt_handler_addr
        B .
        LDR PC, irq_handler_addr
        LDR PC, fiq_handler_addr
		
        //변수를 선언해 놓았고 이 변수를 exception vector table에서 사용함
        reset_handler_addr:     .word reset_handler
        undef_handler_addr:     .word dummy_handler
        svc_handler_addr:       .word dummy_handler
        pftch_abt_handler_addr: .word dummy_handler
        data_abt_handler_addr:  .word dummy_handler
        irq_handler_addr:       .word dummy_handler
        fiq_handler_addr:       .word dummy_handler
    vector_end:

    reset_handler:
    	//reset exception handler이다.
        LDR R0, =0x10000000
        LDR R1, [R0]

	//dummy로 해놓은 것이고 무한 루프를 돌게끔 구현함
    dummy_handler:
        B .
.end

부팅 초기시 exeption handler로 처리되며 해당 부분을 위해 Entry.S를 위와 같이 수정하자. 코드는 exception vector table에 각 handler로 jump 하는 코드만 작성되었다. 각 handler의 동작은 구현되지 않고 무한루프로 동작된다. 

$ cd project_directory
$ make clean && make all
$ make debug
$ (다른 console에서) make gdb
(gdb) target remote:1234
(gdb) continue
컨트롤 + C로 정지
(gdb) info registers

handler 처리 결과

2020/01/11 - [Engineering/운영체제] - [임베디드OS개발프로젝트] 3장. 일단 시작하기

지난 글 마지막 결과에서 확인할 수 있던 것 처럼 동일한 동작을 수행 했으므로 R1에 0x1780500값이 들어가 있음을 확인할 수 있다. 

보드가 부팅하면서 가장 먼저 수행되어야 할 것은 reset exception handler이다. 이 reset exception handler는 메모리 맵을 설정하는 작업을 수행해줘야 한다. SP 레지스터에 정해진 값을 넣는 작업을 수행하며 초기화를 수행한다.

$ cd project_directory
$ mkdir include
$ vim MemoryMap.h
$ vim ARMv7AR.h
<Memory.h 내용>
#define INST_ADDR_START         0
#define USRSYS_STACK_START      0x00100000
#define SVC_STACK_START         0x00300000
#define IRQ_STACK_START         0x00400000
#define FIQ_STACK_START         0x00500000
#define ABT_STACK_START         0x00600000
#define UND_STACK_START         0x00700000
#define TASK_STACK_START        0x00800000
#define GLOBAL_ADDR_START       0x04800000
#define DALLOC_ADDR_START       0x04900000

#define INST_MEM_SIZE           (USRSYS_STACK_START-INST_ADDR_START)
#define USRSYS_STACK_SIZE       (SVC_STACK_START-USRSYS_STACK_START)
#define SVC_STACK_SIZE         (IRQ_STACK_START-SVC_STACK_START)
#define IRQ_STACK_SIZE         (FIQ_STACK_START-IRQ_STACK_START)
#define FIQ_STACK_SIZE         (ABT_STACK_START-FIQ_STACK_START)
#define ABT_STACK_SIZE         (UND_STACK_START-ABT_STACK_START)
#define UND_STACK_SIZE         (TASK_STACK_START-UND_STACK_START)
#define TASK_STACK_SIZE        (GLOBAL_ADDR_START-TASK_STACK_START)
#define GLOBAL_ADDR_SIZE       (DALLOC_ADDR_START-GLOBAL_ADDR_START)
#define DALLOC_ADDR_SIZE       (55*1024*1024)

#define USRSYS_STACK_TOP        (USRSYS_STACK_START+USRSYS_STACK_SIZE-4)
#define SVC_STACK_TOP           (SVC_STACK_START+SVC_STACK_SIZE-4)
#define IRQ_STACK_TOP           (IRQ_STACK_START+IRQ_STACK_SIZE-4)
#define FIQ_STACK_TOP           (FIQ_STACK_START+FIQ_STACK_SIZE-4)
#define ABT_STACK_TOP           (ABT_STACK_START+ABT_STACK_SIZE-4)
#define UND_STACK_TOP           (UND_STACK_START+UND_STACK_SIZE-4)
<ARMv7AR.h내용>
#define ARM_MODE_BIT_USR 0x10
#define ARM_MODE_BIT_FIQ 0x11
#define ARM_MODE_BIT_IRQ 0x12
#define ARM_MODE_BIT_SVC 0x13
#define ARM_MODE_BIT_ABT 0x17
#define ARM_MODE_BIT_UND 0x1B
#define ARM_MODE_BIT_SYS 0x1F
#define ARM_MODE_BIT_MON 0x16

MemoryMap.h와 ARMv7AR.h는 C언어 헤더 파일이다. GCC로 컴파일 할 경우 asm 파일에서도 사용할 수 있다. Entry.S에서 사용하기 위해 헤더를 추가해 준다.

#include "ARMv7AR.h"
#include "MemoryMap.h"

.text
    .code 32

    .global vector_start
    .global vector_end

    vector_start:
        LDR PC, reset_handler_addr
        LDR PC, undef_handler_addr
        LDR PC, svc_handler_addr
        LDR PC, pftch_abt_handler_addr
        LDR PC, data_abt_handler_addr
        B .
        LDR PC, irq_handler_addr
        LDR PC, fiq_handler_addr

        reset_handler_addr:     .word reset_handler
        undef_handler_addr:     .word dummy_handler
        svc_handler_addr:       .word dummy_handler
        pftch_abt_handler_addr: .word dummy_handler
        data_abt_handler_addr:  .word dummy_handler
        irq_handler_addr:       .word dummy_handler
        fiq_handler_addr:       .word dummy_handler
    vector_end:

    reset_handler:
        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_SVC
        MSR CPSR, R1
        LDR SP, =SVC_STACK_TOP
        
        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_IRQ
        MSR CPSR, R1
        LDR SP, =IRQ_STACK_TOP

        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_FIQ
        MSR CPSR, R1
        LDR SP, =FIQ_STACK_TOP

        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_ABT
        MSR CPSR, R1
        LDR SP, =ABT_STACK_TOP

        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_UND
        MSR CPSR, R1
        LDR SP, =UND_STACK_TOP

        MRS R0, CPSR
        BIC R1, R0, #0x1F
        ORR R1, R1, #ARM_MODE_BIT_SYS
        MSR CPSR, R1
        LDR SP, =USRSYS_STACK_TOP

    dummy_handler:
        B .
.end

위의 코드는 .h 파일 두개를 추가 후 SP 설정 및 초기화를 위해 reset_handler 부분을 수정한 것이다. 모든 동작 모드를 한 번씩 순회하면서 스택 꼭대기 메모리 주소를 SP에 설정하는 코드이다. SP에 해당모드의 시작 주소를 넣는 것이 아닌 TOP의 주소를 넣는 것은 스택이 높은 주소에서 낮은 주소로 자라는 특징을 가지고 있기 때문이다.( 하지만 이것은 설계자 마음이다. 꼭 Stack이 위에서 아래로 heap은 밑에서 위로 자라는 방향은 아니다.) 

<Makefile 내용>
ARCH = armv7-a
MCPU = cortex-a8

CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OC = arm-none-eabi-objcopy

LINK_SCRIPT = ./navilos.ld

ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.o, $(ASM_SRCS))

INC_DIRS = include

navilos = build/navilos.axf
navilos_bin = build/navilos.bin

.PHONY: all clean run debug gdb

all: $(navilos)

clean:
	@rm -fr build

run: $(nvailos)
	@qemu-system-arm -M realview-pb-a8 -kernel $(navilos)

debug: $(nvailos)
	@qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4

gdb:
	arm-none-eabi-gdb

$(navilos): $(ASM_OBJS) $(LINK_SCRIPT)
	$(LD) -n -T $(LINK_SCRIPT) -o $(navilos) $(ASM_OBJS)
	$(OC) -O binary $(navilos) $(navilos_bin)

build/%.o: boot/%.S
	mkdir -p $(shell dirname $@)
	$(CC) -march=$(ARCH) -mcpu=$(MCPU) -I $(INC_DIRS) -c -g -o $@ $<

ASM 컴파일러를 산용해서 컴파일 할 경우 전처리기가 없기 때문에 .h파일을 읽어올 수 없다. 따라서, 컴파일러를 gcc로 변경한다. 추가적으로 .h 파일들이 존재하는 include 디렉토리도 추가한다. 위의 makefile 내용으로 수정한다.

make all을 수행한 결과이다. 이후 QEMU <-> gdb를 이용해 sp의 메모리 위치를 확인해 보자.

 

34번째 라인까지 실행되고 첫번째 SVC 동작 모드 스택이 설정된다. SVC 모드 스택은 0x00300000 ~ 0x003FFFFF까지 메모리 주소 영역이다. 스택과 스택 경계에 4B를 비워두도록 크기를 설정 했으므로 0x003FFFFC여야 한다. 위 그림의 info register 결과에서 볼수 있듯이 sp의 값이 해당 값을 가리키고 있음을 알수 있다.

CPSR을 보면 마지막 바이트가 0xd3이다. 이것은 11010011(2)이며, 마지막 하위 5비트만 보면 10011이다. 이것은 16진수로 0x13을 나타낸다. SVC 동작 모드를 설정하는 값이다. 

ARM의 CPSR 레지스터의 bit 필드를 나타낸다. 하위 5bit는 해당 모드의 동작 상태를 나타내며 0b10011은 SVC를 나타낸다.  이렇게 모든 모드들에 대해서 sp를 정해 준다. 실제 보드에서는 sp뿐만이 아닌 하드웨어 시스템 클럭 설정, 메모리 컨트롤러 초기화 같은 일들도 필요하다. 이것은 추후에 Cortex-M3를 공부하며 진행하도록 하겠다.

 

<Entry.S 부분>
...

MRS R0, CPSR
BIC R1, R0, #0x1F
ORR R1, R1, #ARM_MODE_BIT_SYS
MSR CPSR, R1
LDR SP, =USRSYS_STACK_TOP

BL main

BL main을 추가해준다. 이것을 통해 asm의 동작이 끝난후 C언어의 main문으로 함수가 점프하게 된다. 

build/Mainc.C를 생성 후 아래 내용 입력

#include "stdint.h"

void main(void)
{
    uint32_t* dummyAddr = (uint32_t*)(1024*1024*100);
    *dummyAddr =  sizeof(long);
}

BL 브랜치 명령으로 점프 하려면 점프 대상 레이블이 같은 파일 안에 있어야 한다. 다른 파일에 있다면 링커가 링킹할 수 있도록 레이블을 .global로 선언해야 한다. 컴파일러는 C언어 함수 이름을 링커가 자동으로 접근할 수 있는 전역 심벌로 만든다. 전역 심볼은 어셈블리로 사용할떄 .global 지시어로 선언하고 C언어로 할때는 extern으로 사용한다.  반대로 어셈블리에서 .global로 선언한 이름은 c언어에서 함수 호출로 진입할 수 있다.

 

새롭게 Make 파일을 수정해 준다.

ARCH = armv7-a
MCPU = cortex-a8

CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OC = arm-none-eabi-objcopy

LINKER_SCRIPT = ./navilos.ld
MAP_FILE = build/navilos.map

ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))

C_SRCS = $(wildcard boot/*.c)
C_OBJS = $(patsubst boot/%.c, build/%.o, $(C_SRCS))

INC_DIRS  = -I include

navilos = build/navilos.axf
navilos_bin = build/navilos.bin

.PHONY: all clean run debug gdb

all: $(navilos)

clean:
	@rm -fr build
	
run: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos)
	
debug: $(navilos)
	qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
	
gdb:
	arm-none-eabi-gdb
	
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
	$(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
	$(OC) -O binary $(navilos) $(navilos_bin)
	
build/%.os: $(ASM_SRCS)
	mkdir -p $(shell dirname $@)
	$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
    
build/%.o: $(C_SRCS)
	mkdir -p $(shell dirname $@)
	$(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<

make all 수행후 gdb를 통해 실행파일을 run한 후 정지 시키자. 그럼 펌웨어가 main() 함수를 실행하고 나면 다시 reset handler로 돌아가서 무한루프는 도는 것을 확인할 수 있다. 그래서 '컨트롤+c' 명령을 입력하기 전까진 종료되지 않는다. 이후 x/8wx 메모리 주소 명령을 입력한다. 이 명령은 입력된 메모리 주소부터 8개를 4바이트씩 16진수로 값을 출력하라는 명령이다. 그래서 0x6400000 메모리 주소의 값을 4바이트씩 8개 출력을한다. 출력 값은 4가 나온다. 

3.1 Reset Vector

ARM 코어에 전원이 들어온 후 첫 수행되는 동작은 reset vector에 있는 명령을 실행하는 것

32bit기준으로 Reset vector의 주소는 0x00000000이다. (이것은 Core에 dependency하다.)

따라서, 부팅후 첫 동작을 위해 0x00000000에서 동작할 코드를 작성한다.

$sudo apt install gcc-arm-none-eabi //arm용 cross 컴파일러 설치
$sudo apt install qemu-system-arm //arm아키텍처를 가상화해서 사용하기 위한 qemu 설치
$mkdir os_project
$cd os_project
$mkdir boot
$cd boot​

OS프로젝트 디렉토리를 하나 생성후 boot에 필요한 코드들을 포함하기 위해 boot 디렉토리를 생성한다.

boot 디렉토리 내에서 Entry.S를 생성한다.

 

.text //text ~ end까지는 text section을 의미함
    .code 32 //명령어의 크기가 32bit임을 뜻함

    //.global은 C언어에서 extern과 같은 역할
    .global vector_start //vector_start의 주소와 vector_end의 주소를 외부 파일에서 심볼로 읽을수 있게 설정
    .global vector_end

    vector_start:
        MOV R0, R1 //동작 수행
    vector_end:
        .space 1024,0 //해당 위치부터 104바이트를 0으로 채우기
.end //text section 끝​

 

실행파일 구조

하나의 executable file이 완성되면 linking 등 여러가지 작업에 의해 파일이 생성된다. 이떄 .text, .data, .bss 등 다양한 section이 존재하게 되며 Entry.S의 .text ~ .end 까지를 text section이라 한다. .text 섹션에는 code들이 존재한다.

$cd ~/os_project/boot
$arm-none-eabi-as -march=armv7-a -mcpu=cortex-a9 -o Entry.o //어셈블리 컴파일
$arm-none-eabi-objcopy -O binary Entry.o Entry.bin //object파일에서 binary 추출
$hexdump Entry.bin

hexdump Entry.bin 결과

Entry.S 컴파일 후 바이너리 파일을 덤프한 결과를 나타낸다.

arm-none-eabi-as: arm용 어셈블리 소스 파일 에셈블러

arm-none-eabi-object: object파일에서 바이너리 파일만 추출한다. object 파일에는 심볼 정보 등이 포함되어 있다.

1) 0001 e1a0 : MOV R0, R1를 의미

2) * 계속 반속 되는 것을 의미

3) 4B align이므로 0000404가 보여짐

 

실행파일을 만들기 위해서는 다수의 object 파일들을 묶어야 한다. 이 역할을 링커가 하게 되며 링커가 어떤 정보를 바탕으로 해당 동작을 수행하게 되는데 이때 정보들을 모은 파일을 링커 스크립터라고 한다. 하드웨어 환경에 맞춰 section(text, data, rodata 등)을 배치해야 한다. 

$ cd ~/os_project/
$ vi navilos.ld

링커 스크립터를 만들자.

ENTRY(vector_start) //시작 위치의 심벌을 저장
SECTIONS //3 ~ 19줄 까지의 블록이 섹션 배치 설정 정보를 가짐
{
   . = 0x0; //첫 번째 섹션이 메모리 주소 0x00000000에 위치 한다는 것을 나타냄

    .text : //text 섹션의 배치 순서를 지정
    {
        *(vector_start) //0x000000000에 reset_vector가 위치해야 함
        *(.text .rodata)
    }
    .data :
    {
        *(.data)
    }
    .bss :
    {
        *(.bss)
    }
}​

이후에 컴파일을 수행하자.

$ arm-none-eabi-ld -n -T navilos.ld -nostdlib -o navilos.axf boot/Entry.o
$ arm-none-eabi-objdump -D navilos.axf

-n : 링커에 섹션의 정렬을 자동으로 맞추지 말라고 지시

-T : 링커 스크립트의 파일명을 알려 주는 옵션

-nostdlib : 링커가 자동으로 표준 라이브러리를 링킹하지 못하도록 지시

컴파일 완료 후 navilos.axf 파일이 생성됨

-D : disassemble 해서 어떻게 구성되어 있는지 보자

disassemble 한 결과

 

vector_start가 0x00000000에 배치되어 있고 명령이 MOV R0, R1인 것을 확인 가능하다. 기계어로는 0XE1A00001

실행파일을 실행 시켜 보면 "bash: ./navilos.axf: cannot execute binary file: Exec format error" 에러 발생한다.

이것은 cross compile된 것이기 떄문에 x86_64 아키텍처에서는 실행이 되지 않는다.

해당 파일을 실행 하는 방법은 크게 두 가지이다.

1. ARM 기반 보드에서 직접 실행

2. QEMU에서 ARM 에뮬레이트를 통해 실행

$ qemu-system-arm -M realview-pb-a8 -kernel navilos.axf -S -gdb tcp::1234,ipv4​

QEMU 실행 결과

해당 명령을 실행했을때 QEMU의 화면이 실행되며 멈춘 상태의 결과를 확인할 수 있다.

-M : 머신 지정

-S : QEMU가 동작하자마자 정지

-gdb tcp::1234, ipv4 : gdb와 연결하는 소켓 포트를 지정

$ arm-none-eabi-gdb
(gdb) target remote:1234
(gdb) x/4x 0

target remote:1234 : 1234 포트를 통해 qemu에 접속

x/4x 0 : 0x00000000주소에서 4바이트를 출력

ARCH = armv7-a
MCPU = cortex-a8

CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-ld
OC = arm-none-eabi-objcopy

LINK_SCRIPT = ./navilos.ld

ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.o, $(ASM_SRCS))

navilos = build/navilos.axf
navilos_bin = build/navilos.bin

.PHONY: all clean run debug gdb

all: $(navilos)

clean:
    @rm -fr build

run: $(nvailos)
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos)

debug: $(nvailos)
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S gdb tcp::1234, ipv4

gdb:
    arm-none-eabi-gdb

$(navilos): $(ASM_OBJS) $(LINK_SCRIPT)
    $(LD) -n -T $(LINK_SCRIPT) -o $(navilos) $(ASM_OBJS)
    $(OC) -O binary $(navilos) $(navilos_bin)

build/%.o: boot/%.S
    mkdir -p $(shell dirname $@)
    $(AS) -march=$(ARCH) -mcpu=$(MCPU) -g -o $@ $<
 

빌드를 자동으로 해주기 위한 Makefile을 작성한 것이다.

11번째 줄은 boot 디렉토리에 있는 asm파일은 모두 ASM_SRCS 변수에 값으로 넣으라는 의미

12번째 줄은 boot디렉토리에 있는 asm파일 이름을 찾아서 확장자를 .o로 바꾼 다음 디렉토리로 build로 바꿔 ASM_OBJS변수에 값으로 넣으라는 의미

33~35번째 줄은 링커로 navilos.axf 파일을 생성. 추가로 navilos.bin도 생성

37~39번째 줄은 *.S -> *.o로 변환

 

make all 결과

vector_start부분을 아래 코드를 바꿔 보자

vector_start:
    MOV R0, R1
//아래 코드로 변경
vector_start:
    LDR R0, =0x10000000
    LDR R1, [R0]​

5~6 R0에 저장된 메모리 주소의 데이터 값을 R1 레지스터에 저장

재 컴파일 이후 GDB를 통해 QEMU에 접속하자.

$ make gdb
(gdb) target remote:1234
(gdb) file build/navilos.axf

list를 통한 navilos.axf 정보 읽기

 

list 입력시 Entry.S 파일 심볼에 대해 확인이 가능하다.

초기 부팅 register 정보 상태

코드가 현재 실행되지 않았기 때문에 레지스터에는 아무런 정보가 존재하지 않아야 한다.

1 step 실행 이후 register 정보 상태

gdb) s : 1 step 실행. 즉, r0에 0x1000000주소값을 대입 하는 과정을 실행한 결과를 나타낸다.

LDR R1, [R0] 실행 후 register 정보 상태

(decimal)24642816은 0x1780500을 나타낸다.

책을 좀 더 참조 하자.

SYS_ID 레지스터 값을 분석하자.

[31:28] REV   보드버전           0x0 

[27:16] HBI    HBI 보드 번호    0x178

[15:12] BUILD 보드 빌드 변형   0x0

[11:08] ARCH 버스 아키텍처    0x5

[07:00] FPGA  FPGA 빌드        0x0

해당 결과를 해석하면 보드 리비전은 Rev A, 버스 아키텍처는 AXI를 사용한다.

Ice Breaking PCIe interface (not included in spec)

2장이 시작되기 전 PCI 및 PCIe에 대한 기본적 지식이 필요함을 느껴 진행 한다. 

참조 자료:

    1. mindshare에서 나온 PCIe pdf

    2. PCIe 관련 블로그1 - 문c 블로그 - PCI subsytem

    3. PCIe driver development for Exynos SoC by Samsung

    4. Linux PCI drivers - Free Electrons

    5. Overview of PCIe subsystem - Texas Instruments

    6. PCI system architecture, Local Bus, Tutorial - Porto University

    7. PCIe 관련 블로그2

    8. http://egloos.zum.com/nimphaplz/v/5314763
    9. https://wiki.qemu.org/images/f/f6/PCIvsPCIe.pdf
    10. https://pcisig.com/sites/default/files/files/PCI_Express_Basics_Background.pdf#page=26
    11. https://slidesplayer.org/slide/14669145/
    12. https://wiki.osdev.org/PCI
    13. https://static.lwn.net/images/pdf/LDD3/ch12.pdf
    14. https://wiki.qemu.org/images/f/f6/PCIvsPCIe.pdf

Peripheral Component Interconnect Bus (PCI)

위키백과
PCI 버스는 컴퓨터 메인보드에 주변 장치를 장착하는 데 쓰이는 컴퓨터 버스의 일종이다.
이 장치는 다음과 같이 두 가지 형태로 나뉜다.
 1. 주기판 위에 바로 붙는 IC 형태 - PCI 스펙에서는 이러한 형태를 평면 장치(planar device)라고 부른다.
 2. 소켓에 꽂아 쓰는 확장 카드 형태 - 사용자 입장에서 흔히 눈에 띄는 형태이다.내가 본 PCI의 경우 2번의 형태가 많았다. 주로 sound card, ethernet card 등을 꽂아 사용한다.

PCI 특징

PCI는 이전의 ISA, MCA, EISA, VESA 버스를 대체하기 위해 설계 되었다. 

PCI는 아래의 특징을 가진다.

      1. 빠른 전송 속도

        • 기존 bus들은 낮은 clock cycle (ISA: 4.7MHz, MCA: 10MHz, EISA: 8.3MHz, VESA: 33MHz)을 가진다.

        • PCI는 33MHz부터 266MHz 이상의 clock cycle을 가져 데이터의 빠른 전송이 가능하다.

      2. 단일화된 인터페이스

        • CPU와 PCI bus 사이에 system/PCI bus bridge를 설치해 여러 프로세서를 위한 설계가 가능하다.

        • PCI bus에 PCI/Expansion bus bridge를 설치해 기존의 버스를 사용할 수 있다.

      3. 동시에 여러개의 function을 지원 

        • 같은 PCI bus상에 여러 bus master가 존재할 수 있다.

        • 하나의 디바이스에 동시에 여러개의 function을 지원할 수 있다. 

PCI Express (PCIe)

위키백과
PCIe는 앞서 언급한 버스 표준들과 비교하여 높은 시스템 버스 대역폭, 적은 I/O 핀 수, 적은 물리적 면적, 버스 장치들에게 더 뛰어난 성능 확장성, 상세한 오류 검출 및 보고 구조(Advanced Error Reporting (AER), 핫-플러그 기능등 여러 장점을 가지고 있다. 최근에는 하드웨어 I/O 가상화도 지원한다\

PCIe 특징

PCIe는 기본적으로 PCI가 가지는 성능적 한계 및 신호 왜곡 등을 개선하기 위해 기존의 병렬 bus로 구성된 PCI의 bus를 serial bus로 바꿔 설계했다. PCIe는 PCI 슬롯을 그대로 사용하며 여러개의 슬롯을 공유하지 않고 1:1로 연결해 사용한다. 따라서, 여러 장치를 붙일 경우 PCIe switch를 사용해 다수의 End device를 연결할 수 있도록 한다.

PCIe의 장점은 아래와 같다.

  1. Bandwidth의 증가
  2. Bus clock cycle의 증가
  3. Bus width의 감소
  4. 회로의 단순화
  5. PCI 디바이스 SW 호환성 유지

기본적으로 PCI는 병렬 bus를 이용하기 때문에 신호 왜곡에 취약하기 대문에 bus의 clock cycle을 올리기 어렵다. 이를 dual-simplex 방식의 serial bus로 바꿈으로써 bus width의 감소, clock cycle의 증가, 회로의 단순화 등의 장점을 가진다.

(참조: http://www.technoa.co.kr/news/articleView.html?idxno=38092)

PCIe Lane

Link

x1 ~ x32 lane을 하나로 묶어 사용할 수 있다. 

1개의 Lane은 TX와 RX로 dual-simplex 구성으로 되어 있으며, 1개의link는 End-to-End Device간 1:1로 통신이 가능하다.

Lane과 Link 구분

Dual-simplex

단 방향으로의 데이터 bus가 2개 1개 set로 구성되어, 하나의 bus는 데이터를 보내고 다른 하나의 bus는 데이터를 받는 것에만 사용된다. PCIe는 기본적으로 2개의 데이터 전달 통로(lane)을 갖는다. 

*Full duplex도 존재 한다. 여러가지 방법이 존재 함.

Dual-simplex

PCIe Topology

PCIe topology architecture

위 그림은 PCIe를 통해 데이터를 전송하고자 하는 architecture의 topology를 나타낸다.

PCIe로 port를 연결하기 위해서는 기본적으로 Root Complex (RC)가 필요하다. 

RC는 CPU와 PCIe bus들 사이의 interface를 말하며 CPU interface, DRAM interface 등 여러가지 구성요소와 여러 개의 칩들을 포함한다. RC의 위치는 CPU내 (구글링 검색 결과), 메인보드 Chipset 내에 존재 한다.

전체 fabric의 instance들은 다음 구성요소이다.

    1. Root Complex
    2. Multiple endpoints (I/O devices)
    3. Switch
    4. PCIe to PCI/PCI-X bridge

PCIe switch를 통한 PCIe 확장 port

Switch의 경우 위 그림 처럼 PCIe slot을 여러개 확장해서 사용할수 있도록 한다.

PCIe Root Complex (RC)

Root Complex 구조

RC는 Host CPU와 연결하기 위한 host bridge device와 secondary device 연결을 위한 PCIe port가 존재 한다. 

Switch

Switch 구조

    1. Switch는 하나의 RC에 여러 디바이스를 붙일 수 있도록 만든 장치이다.
    2. Swtich는 여러개의 Down-stream ports를 가지고 있지만 up-stream port는 하나만 존재 한다. 
    3. 모든 활성화된 switch port는 flow control을 지원해야 한다. (Packet router처럼 동작하며, 해당 packet의 주소와 다른 routing 정보를 통해 어떤 경로로 packet이 가야하는지 인식한다.)

Endpoint Device

    1. Endpoint device는 아래의 3가지 종류가 존재한다.
    2. Legacy PCI endpoint
      • Type 0 configuration header를 제공하는 function이여야 함
      • I/O 요청 제공 및 발생 가능
      • 4GB (32bit 주소 register일때) 주소를 초과하는 memory transaction 불가
      • MSI/MSI-X를 지원
    3. PCIe Endpoint
      • Type 0 configuration space를 제공하는 function이여야 함
      • I/O 요청 불가
      • 4GB 주소 범위를 넘는 memory transaction 가능 (64bit addressing 가능)
      • MSI/MSI-X 지원
    4. Root Complex integrated endpoint

PCIe 계층 구조 및 데이터 전송

PCIe 5개 Layer

PCI 전송에는 3개(Transaction layer, Data link layer, Physical layer)의 layer가 필요하다. 

PCI -> PCIe 변화 (paralle bus -> serial bus)로 변경되는 부분은 Transaction, Data Link, Physical 계층이다.

Packet의 생성과 Data의 전달

 

아래는 데이터의 전송 과정을 요약했다.

    1. Transaction layer에서는 packet 단위의 전송을 위해 데이터 packet을 형성하고 이를 Link layer로 전달한다.
    2. Link layer에서 데이터의 신뢰도를 위한 CRC 코드를 전달 받은 데이터에 삽입한다.
    3. Physical layer에서 frame 붙여 데이터를 추가 후 8b/10b 인코딩을 해 데이터를 전송하기 위해 serialized data로 변환한다.

 

Transaction layer에서 생성된 데이터 packet은 header와 data로 구성되어 있다. 해당 packet이 Data link layer로 전달되고 Data link layer에서 packet의 순서를 정한 번호와 CRC코드가 앞뒤로 붙게 된다. 그리고 Physical layer로 도착한 데이터에 대해 앞뒤로 frame을 붙이고 해당 packet을 serialize하며 이때 8b/10b 인코딩 시키면 PCIe bus를 통해 데이터를 전달하게 된다. 하지만 이것은 PCIe Gen 1 기준으로 나타냈다. Gen 3만 보더라도 encoding scheme이 128b/130b로 늘어났기 때문이다. 전송되는 packet의 구성과 크기는 아래와 같다.

전달되는 packet의 구성

    1. Physical Layer
      • Framing
        • Start (1B)
        • End (1B)
    2. Data Link Layer
      • Sequence Number (2B)
      • LCRC (1DW)
    3.  Transaction Layer
      • Header (3~4DW)
      • Data (0~1024DW)
      • ECRC (1DW)

Transaction Layer

Ttransaction layer에 발생되는 packet을 Transaction Layer Packets (TLP)라 부른다. TLP는 routing mechanism 및 규칙에 따라 하나의 링크에서 다른 링크로 전달된다. 아래는 TLP가 접근하는 4개의 address spcae를 말한다. 즉, PCIe 디바이스에서 packets이 전달될때 아래의 분리된 주소 공간이 사용된다. (TLP header를 통해 구분한다)

    1. Memory
      • Transaction types: Read, Write 
      • Purpose: transfter data to or from a location in the system memory map
    2. I/O
      • Transaction types: Read, Write
      • Purpose: Transfer data to or from a location in the system IO map
    3. Configuration
      • Transaction types: Read, Write
      • Purpose: Transfer data to or from a location in the configuration space of a PIC-compatible device
    4. Message
      • Transaction types: baseline, vendor-specific
      • Purpose: general in-band messaging and even reporting without consuming memory or IO address resoures

TLP Header

 

Data Link Layer

  • 링크 트레이닝
    • 링크 폭
    • 링크 데이터 rate
    • Lane reversal (Lane 역 방향 순서 지원)
    • Polarity inversion (극성 반대 지원)
    • 멀티 레인에서 레인 to 레인 de‐skew
  • 전원 관리
    • 트랜잭션 게층에서 요청한 전원 상태를 수락하고 물리 계층으로 전달한다.
    • 활성/재설정/연결 해제/전원 관리 상태를 트랜잭션 계층으로 전달한다.
  • 데이터 프로텍션, 에러 체킹
    • CRC 생성
    • 에러 체킹
    • 재전송 메시리지대한 TLP 응답
    • 에러 리포팅 및 로깅을 위한 에러 인디케이션

Physical Layer

  • 인터페이스 초기화, 메인트넌스 제어 및 스테이터스 트래킹
    • 리셋/핫플러그 컨트롤
    • 전원 관리 인터커넥트
    • width & lane 매핑 협상
    • lane 극성 반전
  • 심볼 및 오더
    • 8b/10b 엔코딩 및 디코딩
    • 임베디드 클럭 튜닝 및 정렬
  • 심볼 전송 및 정렬
    • 전송 회로
    • 리셉션 회로
    • 수신 측 Elastic 버퍼
    • 수신 측 멀티 lane de-skew

1.1 Overview

NVMe interface는 host software가 non-volatile memory subsystem와 통신할 수 있도록 해준다.

NVMe는 PCIe interface를 사용하는 enterprise와 client SSD에 최적화되어 있다.

1.2 Scope

해당 spec은 NVM subsystem의 controller와 register interface를 정의한다.

세 종류의 Controller가 존재한다.

  1. I/O controllers

  2. Discovery controllers

  3. Administrative controllers

1.3 Outside of scope

1.4 Theory of Operation

NVMe Interface는 최적화된 command submission과 completion paths를 제공한다.

Key attributes

  • command submission 또는 completion path에서 uncacheable/MMIO register read가 필요하지 않다.

  • command submmision path에서 최대 하나의 MMIO register wrtie가 필요하다.

  • 최대 64K I/O queue 지원과 각 I/O queue는 64K개의 outstanding commands가 가능하다.

  • 각 I/O queue와 관련된 priority는 well-defined arbitration mechanism으로 조정 된다.

  • 4KB read 요청을 완료하기 위한 모든 정보는 64B command에 포함된다.

  • 효율적이고 streamlined command set을 가진다.

  • MSI / MSI-X와 interrupt 지원한다.

  • Multiple namespaces 지원한다.

  • SR-IOV처럼 효율적인 I/O virtualization을 지원한다.

  • Robust error reporting과 management capabilities

  • Multi path I/O와 namespace sharing을 지원한다.

NVMe controller는 single PCI function과 연관된다.

전체 controller에 적용되는 capabilities와 설정들은 Controller Capabilities (CAP) 레지스터와 Identify Controller data structure를 나타낸다.

하나의 namespace는 logical block으로 format된 non-volatile memory의 quantity이다.

NVMe controller는 namespace ID를 가지는 multiple namspaces를 지원한다.

Namspaces는 Namespace Management와 Namespace Attachment commands로 생성과 삭제가 된다.

Identify Namespace data structure는 특정 namespace의 capabilities와 설정을 나타낸다.

NVMe interface는 submission과 completion queue의 pair 형태를 기반으로 한다.

Commands는 host software에 의해 submission queue에 issue 된다.

Completions는 controller에 의해 completion queue에 issue 된다.

Multiple submiision queues는 동일한 completion queue를 이용한다.

Submission과 complition queues는 메모리에 할당 된다.

Admin submission과 이와 관련된 completion queeu는 controller 관리, I/O submission과 completion queues들의 생성과 삭제 및 aborting commands 등 control 목적을 위해 존재한다.

I/O command set은 I./O queue pair로 사용된다.

해당 spec에서는 I/O command set을 NVM command set으로 명시한다.

Queue pair

  • Host software는 controller가 지원하는 최대 개수의 queue를 생성한다.

  • queue 생성은 system configuration과 anticipated workload에 기반한다.

  • queue 생성의 종류는 1:1 mapping, n:1 mapping이 존재 한다.

Submission Queue와 Completion Queue를 이용한 I/O 처리 과정

  • Submission Queue (SQ)는 host software가 controller에 의해 실행되기 위한 commands를 전달하기 위한 고정된 크기의 circular buffer이다

  • 실행되어야 할 1~n개의 새로운 commands이 있다면 host software는 적절한 SQ Tail doorbell 레지스터를 업데이트 한다. 

  • 새로운 doorbell resister write가 있을때 이전의 SQ tail 값을 덮어 쓰기한다.

  • Controller는 SQ entries을 SQ에서 순차적으로 fetch하고 어떤 순서로(알고리즘에 기반) 실행한다.

  • 각 SQ entry는 command이고 64B의 크기를 가진다.

  • 메모리내 Physical 메모리는 data 전송을 위해 사용되며, Phsical Region Page (PRP) entries 또는 Scatter Gather Lists가 나타낸다.

  • 각 command는 두개의 PRP entires 또는 하나의 SGL segment를 포함한다.

  • 만약 data buffer를 위해 두개 이상의 PRP entires가 필요하다면, PRP Lists의 pointer가 PRP entires를 가리킨다.

  • 위와 동일하게 하나 이상의 SGL이 필요한 경우, SGL semgment는 다음 SGL segment pointer를 제공한다.

  • Completion Queue (CQ)는 completed command의 상태를 나타내기 위한 고정된 크기의 circular buffer이다. 

  • Completed command는 host software에서 할당된 SQ identifier와 comand identifier의 조합으로 식별된다.

  • Multiple SQ는 하나의 CQ를 사용한다. 

Multi-Path I/O and Namespace Sharing

  • Multi path I/O는 하나의 host와 하나의 namespace 사이간에 두개 이상의 독립된 path를 말한다.

  • 반면에 namespace sharing은 두개이상의 host가 다른 NVM controller를 사용하는 shared namespace에 접근하는 것을 말한다. 

1.5 Conventions

Abbreviations

  • RO : Read Only

  • RW : Read Write

  • R/W : Read Write. The value read may not be the last value written.

  • RWC : Read/Write '1' to clear

  • RWS : Read/Write '1' to set

  • Impl Spec : Implementation Spec

  • HwInit : The default state is dependent on NVMe controller and system configuration

  • Reset : This column indicates the value of the field after a reset

Use a '0's based value 

1.6 Definitions

Admin queue

  • identifier 0을 가지는 SQ와 CQ이다.

  • administrative commnad를 submit하고 completions을 받기 위해 admin SQ와 admin CQ는 pair를 이룬다.

Administrative controller

  • Host가 NVM subsystem을 관리할수 있도록 capabilities를 가지고 있는 controller

  • 해당 controller는 I/O queues를 가지지 않는다.

  • Logical blocks과 관련된 metadata 또는 data에 대한 접근을 제공한다.

  • namespaces를 지원한다.

Arbitration burst

  • Round robin 또는 weighted round robin을 사용하는 SQ로부터 한번에 처리 가능한 commands의 최대 수를 말한다.

Arbitration mechanism

  • SQ에서 Controller에 의해 수행되기 위한 command를 결정하기 위해 사용 된다.

Cache

  • NVM subsystem을 사용하는 data storage area

Command completion

  • Controller가 command를 처리한 command

  • 처리 결과 상태는 completion queue entry에 업데이트 된다.

Command submission

  • Command는 SQ Tail doorbell write는 처리되었을때 submmit 된다. 

Controller

  • Types

    • I/O controllers

    • Discovery controllers

    • Administrative controllers

  • Controller는 host에 의해 SQ에 submmit된 commands를 실행하고 completion queue에 completion을 업로드 한다.

  • 각 controller는 하나의 admin SQ와 하나의 admin CQ를 가진다.

  • Controller에 따라 하나 이상의 I/O queues를 가질수 있다.

directive

  • host와 NVM subsystem 또는 controller 정보를 교환하는 방법이다.

  • 정보는 Directive Send와 Directive Receive commands를 통해 전달된다.

  •  I/O commands의 subset은 I/O command와 관련된 정보를 통신하기 위해 Directive Type field와 Directive Specfic field를 포함한다.

Discovery controller

  • Host가 Discovery Log Page 정보를 받을수 있도록 하는 특성을 가진 controller이다.

  • I/O queues를 가지지 않는다. 

Emulated controller

  • Software에 정의된 NVMe controller이다. 

Endurance Group

  • NVM subsystem내 NVM 중 일부이다.

  • Group 으로 endurance가 관리된다.

extended LBA

  • 연속적인 LBA 전송과 관련된 memta가 전송될때 생성된다.

firmware slot

  • NVM subsystem내에서 firmware image를 저장하기 위해 사용되는 슬롯이다. 

  • NVM subsystem은 1~7개 firmware images를 저장할 수 있다.

I/O completion queue

  • I/O completion queue는 completion queue이다. 

  • 하나 이상의 SQ와 연관되며, I/O CQ identifiers는 64K까지 값을 가진다.

I/O submission queue

  • I/O submission queue는 SQ이다. 

  • Controller에 의해 실행하기 위한 I/O command를 SQ에 submit한다.

I/O controller

  • I/O queues를 가지는 controller이다. 

  • NVM storage를 접근하기 위해 사용된다.

LBA range

  • 연속적인 logical blocks의 범위이다.

Logical block

  • 가잔 작은 접근 가능한 data 단위이다.

Logical block address (LBA)

  • Logical block의 주소이다.

metadata

  • 특정 LBA 데이터에 대한 정보이다.

primary controller

  • Virtualization Management command를 지원하는 NVMe controller이다.

 

윤리의식
회사 내에서 가장 중요한 윤리의식은 세 가지라 생각됩니다. 공동체 의식, 주인 의식과 프로 의식입니다.
첫째, 공동체 의식. 개인의 성과만을 강조하는 것이 아닌 조직력을 중시하는 연구원입니다. 상대방의 주장과 근거가 타당하다면 효율성과 성능 향상이라는 공동의 목표를 이루기 위해 자신의 주장을 굽힐 줄 아는 연구원입니다.
둘째, 주인 의식. 수행 프로젝트 중 다른 layer의 일이 지연되는 경우 프로젝트의 진전을 위해 기꺼이 추가적인 업무도 마다치 않고 수행해 냅니다.
셋째, 프로 의식. 제한 시간 내에 일을 수행하는 것은 당연하다고 생각됩니다. 일을 수행하며 추가적인 아이디어가 있으면 설계, 구현 및 검증을 통한 데이터 시각화를 통해 교수님과의 미팅 시 추가적인 업무를 수행해 냅니다.

개인상품/인성
공과 사(일과 사생활) 구분이 정확하며 연구원으로서 수행 능력과 사교성이 뛰어나 주변 동료들로부터 좋은 평을 듣습니다.
본인이 가진 신념이 뚜렷합니다. 항상 자신 있게 자신의 아이디어를 주장할 줄 알며 일을 해내고자 하는 목표가 뚜렷한 연구원입니다.

조직관
본인이 속한 조직에 깊이 녹아들어 조직의 성과를 우선시합니다.
이번 xxx 파견 연구원(인턴)으로 3개월간 근무했을 때의 사례를 보면 파견 연구원이기 때문에 주어진 업무량만 처리하고 퇴근해도 되지만 항상 부서와 관련된 추가적인 일을 수행하며 팀 내에서 Open Channel SSD를 지원하기 위한 FTL 구현 등 많은 노력을 했습니다.

업무역량/전문성/주요성과
xxx 연구원은 플래시 메모리 기반 스토리지의 소프트웨어 계층 설계에 뛰어난 업무 능력을 갖추고 있습니다. 
다수의 산학 과제를 수행하며 DRAM-less 스토리지를 위한 Map Cache, 수명 및 성능 향상을 위한 Garbage Collection, Wear Leveling을 포함한 FTL 설계 기술과 NAND Flash 메모리 산포 분석 등 다양한 스토리지 설계 기술 요소에 대한 지식이 풍부합니다.

리더십
리더는 묵묵히 자기 일을 수행하며 주변의 동료를 챙기는 것이 리더라 생각됩니다. 그런 부분에서 xxx연구원은 수년간 연구실 내 Simulator팀에서 리더로서 프로젝트의 성공적인 결과를 냈습니다.
자기 일을 정확히 수행하는 것은 물론이며, 동료와 교수님과의 정확한 의사소통이 되지 않는 경우 해당 내용을 본인이 다시 정리해 의사소통을 진행하는 등 주변 동료들에게 많은 본보기를 주었습니다.

기타 추천의견
xxx  연구원을 강력히 추천합니다. xxx 사업부에 입사해 제 임무를 수행하는 것은 물론이며 타 동료들에게 긍정적인 영향을 미칠 것으로 생각합니다.

참조: http://esos.hanyang.ac.kr/?page_id=13347

       http://esos.hanyang.ac.kr/?page_id=15843

 

주제 1. 리눅스의 대용량 메모리 관리 기법 분석

현재 PC 시장에서 DRAM 메모리의 용량은 크게 증가되었으며, 메모리 집적화 기술의 고도화로 인해 대용량 서버 환경에서는 TB 단위의 메모리까지 등장하게 되었다. 하지만 이와 같은 물리 메모리의 증가는 CPU의 하드웨어 캐시인 TLB(Translation Look-aside Buffer)의 잦은 Miss를 통해 전체적인 메모리 작업의 성능을 하락시키는 문제를 발생시켰다. 때문에 리눅스에서는 하나의 페이지의 크기를 2MB, 1GB까지 확장하도록 지원하는THP(Transparent Huge Page)기법을 제공한다. THP 기법은 하나의 TLB에서 관리할 수 있는 페이지의 크기를 늘려, 기존의 TLB로도 효율적으로 대용량 메모리를 관리할 수 있도록 하는 장점이 있다. 하지만, THP 기법은 비효율적인 메모리 할당 정책 및 페이지 할당에 걸리는 시간이 매우 크다는 단점이 존재하기에 아직 완벽한 기법이 아니다. 본 프로젝트에서는 이러한 리눅스의 THP 기법을 코드 단위로 분석하여 그 동작 방식을 이해하며, 대용량 메모리 경에서의 THP 기법 사용의 장단점을 분석한다. 본 프로젝트는 분석을 위해 Sysbench, Cloudstone, Redis, MongoDB  DB환경에서의 성능 분석 툴을 사용하여 Buffered I/O의 지연 시간 및 물리 메모리 사용량을 측정한다. 이러한 분석과정을 통해 리눅스에서 THP 기법의 동작 방식에 대한 장단점 파악 및 개선 방안을 고안한다. 본 프로젝트는 리눅스의 물리 메모리 관리 기법에 대한 이해를 우선할 수 있음은 물론, 리눅스 기반 대용량 메모리 시스템에 최적화 된 메모리 관리 방식을 설계하는 것을 목표로 한다.

프로젝트 완성도 : 최종 보고서, 발표 자료, 소스코드, Transparent Huge Page 개선 방안 등

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 2. EXT4의 Buffered Write 성능 개선

사용자 프로세스가 특별한 플래그(O_DIRECT, O_SYNC) 없이 일반적인 방법으로 열린 파일에 대해서 쓰기(write())를 수행하면, 리눅스 커널은 사용자가 쓰기를 요청한 내용을 디스크 내 파일에 바로 쓰지 않고, 메모리 내 페이지 캐시에서 페이지를 할당 받아 페이지에 내용을 쓴다. 해당 페이지는 더티 페이지로 구분되고, 추후 커널 쓰레드에 의해 파일에 쓰여진다. 이를 Buffered 쓰기라고 한다. Buffered 쓰기를 사용함으로써 사용자 프로세스는 쓰기(write())를 빠르게 수행할 수 있다. 하지만, 사용자 프로세스가 4KB Buffered 쓰기를 과도하게 하면, write() 시스템 콜의 Latency가 1초 이상으로 증가하는 것을 볼 수 있다. EXT4 파일 시스템에서 write() 시스템 콜의 Latency 증가 원인은 쓰기를 수행할 페이지를 할당하는 ext4_write_begin():fs/ext4/inode.c 함수와, 해당 더티 페이지로 구분하고, Buffered 쓰기 동작을 마무리하는 ext4_write_end():fs/ext4/inode.c 함수이다. 본 프로젝트에서는 write() 시스템 콜 Latency 증가의 원인이 되는 두 함수(ext4_write_begin():fs/ext4/inode.c, ext4_write_end():fs/ext4/inode)의 동작을 분석하고, 해당 함수의 동작 중 어떤 부분이 Latency 증가 원인인지 파악 후, 원인이 되는 동작이 write() 시스템 콜 Latency 증가에 영향을 끼치지 않도록 수정하는 방안을 고안하여 수정한다. 그리고, 수정한 EXT4 파일 시스템과 수정하지 않은 기존의 EXT4 파일 시스템에서 동일한 실험(30 Gbyte 이상의 Buffered 쓰기)을 통해 write() 시스템 콜의 지연 시간을 측정하여 성능향상을 확인한다.

프로젝트 완성도 : 최종 보고서발표자료

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 3. EXT4, F2FS, XFS에서의 fsync() 동작 및 성능  분석

fsync()는 파일시스템의 dirty block을 디스크로 플러시 하는 함수이다. 리눅스 시스템 컬중 가장 중요하고 시간이 많이  소요되는 연산이다. fsync()는 입출력 스케쥴링, 파일 시스템 저널링등 모든 분야에 다 걸쳐있다. 본 프로젝트에서는  ext4, f2fs, xfs 파일 시스템의 fsync() 알고리즘을 분석 비교 한다. 그리고, 4KByte 임의 쓰기 실험을 통해 장단점을 비교 분석해 보기로 한다. 분석은 성능과함께 입출력 트레이스를 출력한다. 리눅스 커널의 심도있는 이해를 위한 매우 좋은 주제이다.

프로젝트 제출물 : 최종 보고서, 발표자료

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 4. F2FS 파일 시스템의 세그멘트 클리닝 분석 및 개선

 F2FS는 플래시 전용으로 개발된 로그기반 파일 시스템이다. 현재 화웨이사의 안드로이드 스마트폰인  P9, 구글 NEXUS 9 태블릿등에 탑재되어 시판되고 있다. 로그기반 파일 시스템은 무효화된 블럭을 소거하는 비용이 매우 높은 것으로 알려져있다. 본 프로젝트에서는 F2FS의 GC 알고리즘을 분석하고, 블록을 효율적으로 분리하는 알고리즘을 개발한다.

프로젝트 완성도 : 최종 보고서, 발표 자료

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 5. 리눅스 블록 계층의 멀티 큐 메커니즘 분석 및 개선

오늘날 컴퓨터 시스템에서 저장 장치는 HDD에서 보다 빠른 SSD로 대체되고 있고, 더 나아가 최근에는 PCIe를 이용하는 NVMe(Non-Volatile Memory Express)를 저장 장치로 효율적으로 사용하기 위한 연구가 활발히 진행되고 있다. NVMe는 최대 64K개의 하드웨어 큐를 제공하여, 많은 I/O 요청을 한꺼번에 병렬로 처리하는 것이 가능하다. 리눅스는 이러한 하드웨어 멀티 큐를 사용하는 저장 장치를 지원하기 위해 Multi-Queue block layer를 제공한다. 본 프로젝트에서는 리눅스의 Multi-Queue block layer를 제안한 “Linux Block IO: Introducing Multi-queue SSD Access on Multi-core Systems” 논문을 통해 Multi-Queue block layer의 구조를 이해하고, Multi-Queue block layer 소스코드(block/blk-mq*) Multi-Queue block layer를 사용하는 디바이스 드라이버(drivers/nvme/*)를 분석하여I/O 처리 흐름을 파악한다. 마지막으로 IOZone, Mobibench, Filebench 등의 I/O 벤치마크 툴을 사용하여 Single-Queue Multi-Queue latency를 측정하고, 측정한 값이 위 논문에서 제시하는 성능과 차이가 있는지 비교 분석하는 것을 최종 목표로 한다. Multi-Queue block layer 분석은 리눅스 커널의 블록 계층을 심도있게 이해할 수 있는 좋은 주제이다.

프로젝트 완성도 : 최종 보고서, 발표 자료

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 6. 리눅스 I/O 스케줄러 분석 및 개선

리눅스 운영체제의 I/O 스케줄러와 다양한 입출력 조건에 따른 입출력 성능의 상관관계를 분석한다리눅스는 파일 시스템에서 요청한 입출력을처리(Merging, Sorting)하기 위해 CFQ, Deadline, Noop 등 다양한 스케줄링 기법을 제공하고 있으며 I/O 스케줄러는 각각 장*단점을 가지고 있다예를 들면, CFQ 스케줄러의 경우, I/O 처리에 있어서 공평성(Fairness)를 제공하지만 I/O 처리의 지연 시간(Response time)이 비교적 길다는 단점이 있으며 반대로 Deadline 스케줄러는 I/O 지연을 최소화할 수 있으나 I/O의 공평성을 제공하지는 못한다본 프로젝트에서는 스케줄러의 입출력 처리 과정을 코드 레벨(linux/block/blk-core.c, cfq-iosched.c, deadline-iosched.c, noop-iosched.c)로 확인하고 실제 성능 측정을 통해 I/O 스케줄러가 수행되는 입출력 조건(ex> Storage type, Workload )이 실제 I/O 처리 과정에 끼치는 영향을 분석한다(사용 벤치마크 툴: IOZone, Mobibench, Filebench). 또한 분석 결과를 근거로각 I/O 스케줄러의 처리 기법 상의 장*단점을 분석하고 개선안을 도출하여I/O 스케줄러의 성능을 향상시키는 것을 목적으로 한다.

프로젝트 완성도 : 최종 보고서, 발표 자료, 소스코드

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 7. 안드로이드를 위한 리눅스 메모리 매니저 분석 및 개선

리눅스 운영체제의 메모리 할당기는 안드로이드에는 적합하지 않은것으로 알려져있다. 때문에 많은 내부 파편화가 발생하고 메모리가 낭비되는 것으로 알려져 있다.파편화란, 메모리 내의 빈공간이나 자료가 여러 개의 조각으로 나뉘는 현상을 말한다. 데이터의 크기가 다양하기 때문에 발생하는 현상으로, 파편화가 심할 경우 성능 저하가 발생하고, 여유 공간이 충분히 있어도 할당이 실패하는 현상이 발생할 수도 있다.  본 주제에서는 리눅스의 메모리 할당기 작동을 심도있게 분석하고, 안드로이드 상에서 물리메모리가 할당되는 과정을 살펴본다. 본 프로젝트는 리눅스 운영체제의 메모리 매니저의 장단점을 분석하고, 메모리 할당, 해제, 파편화 등을 분석하는 것을 목표로 한다. 리눅스의 메모리 할당 기법을 심도있게 파악하는 매우 좋은 기회이다.

프로젝트 완성도 : 최종 보고서, 발표 자료, 소스코드, 메모리 분석 결과 등

자격 요건 : 자료구조, 운영체제, C (리눅스 커널 사전지식 불필요)

주제 8. SQLite용 저널모드 분석 및 개선

SQLite는 안드로이드, 아이폰, 타이젠, 파이어폭스등 다양한 모바일 기기에서 공통적으로 사용되는 오픈소스 임베디드 데이타베이스이다. 오픈소스 장점으로 인해 광범위하게 사용되고 있다. SQLite는 비효율적인 저널링 동작으로 인해 과도한 입출력을 발생시킨다. 스마트폰 업계에서는 SQLite의 입출력 작동을 효율화 시키는 것을 매우 중요한 주제로 삼고 있다. 본 주제에서는 SQLite의 저널 모드에 대해 학습하고, 가능한 개선 방법을 모색하도록 한다.

주 : 안드로이드 디바이스 지급

프로젝트 완성도 : 최종 보고서, 발표 자료, 소스코드, SQLite 성능 개선 방안 등

자격 요건 : 자료구조, 운영체제, C (안드로이드 사전지식 불필요)

주제 9. SSD 시뮬레이터 개발

플래시 기반의 SSD는 현대 저장장치기술의 핵심이다. 새로운 저장장치 알고리즘을 개발함에 있어서 새로운 SSD기술을 효율적으로 개발하기 위해서는 하드웨어 개발 이전에 시뮬레이터를 통해서 개발된 기술의 유효성을 검증하는 것이 필수이다. 본 과제에서는 한양대학교에서 개발하여 현재 널리 사용되고 있는 오픈소스 시뮬레이터인 VSSIM 을 개선한다. VSSIM은 오픈 소스 기반  SSD 이뮬레이터이다. SSD의 채널/웨이등을 변경할 수 있고, 이와더불어 다양한 SSD의 매핑 알고리즘과 Garbage Collection 알고리즘을 적용할 수 있다. 이를 다음과 같이 개선한다. 본 주제에서는 SSD용 시뮬레이터 VSSIM에 대해서 학습하고, 다양한 개선점을 모색한다.

– 최신 qemu로 포팅
– 다중 쓰레드 지원
– PCIe 지원

주 : 오픈소스 활동

프로젝트 완성도 : 최종 보고서, 발표 자료, 소스코드, 알고리즘, 성능 개선 방향 등

자격 요건 : 자료구조, 운영체제, C, 핀토스 사전지식 필요

주제 10. MongoDB 분석및 개선

mongdb는 현재 다양한 웹사이트에서 사용되는 효율적인 데이타베이스 이다.  블로그, 게임아이템 저장을 위해서 사용되는 가장 대중적인 자료구조이다. 몽고 DB의 핵심인 LSM tree가 어떤것인지 살펴보고 그의 동작을 분석해본다. LSM tree 가 많이 사용되는 Redis, Cassendra등의 성능을 분석한다.

프로젝트 완성도 : 최종 보고서, 발표 자료등

자격 요건 : 자료구조, 운영체제, C (안드로이드 사전지식 불필요)

+ Recent posts