onkwon
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Zephyr 스터디 노트 <details markdown="1"> <summary>스터디 소식</summary> ## 시작하기 ### 아이스브레이킹 * 돌아가면서 간단히 자기소개 - 본명이든 별명이든 불리고 싶은 이름으로 - 나이는 공개하지 않는 편이 - 호칭은 님으로 통일 - 자기소개의 목적은 모두 짧게라도 한마디씩 해서 보다 깊이 인볼브되도록 하는 것 - 능동적인 모임, 활발한 토론 - 참석자들의 영상을 여는 게 친밀감 높이는 데 도움이 될 지 모르겠음 * 주로 사용하는 MCU 그리고 개발환경 공유 * 매주 코드 드라이버 뽑기 * 공부하고 싶은 분야 그리고 스터디에서 다루고 싶은 부분 - 빌드 시스템 - 스케줄러 - 파일 시스템 - 디바이스 트리 - 디바이스 드라이버 - 토이 프로젝트 * 지향점은 조바심내지 않고 차곡차곡 한발씩 함께 밟아나가는 것 ### 1화: Hello, reset.S! * 일시: 2021년 8월 8일, 20시부터 22시까지 * 참석자(6): blackbird, Kye-Hyun Park, Albert, Chae Lee, 허정훈, 권경환 - 드라이버: 권경환 * 매주 일요일 20시부터 22시까지 2시간 동안 커널 소스를 분석하기로 함 - ARM Cortex-M 아키텍처 기반 * 매주 랜덤으로 뽑힌 사람이 소스 화면을 공유, 다함께 라인바이라인으로 읽은 코드 의미를 주석으로 남김. 이를 드라이버라 부르기로 - 드라이버는 화면을 공유하고 코드를 쫓아가는 역할을 할 뿐, 해석은 다함께 하므로 부담가질 필요 없음 - 다른 사람은 어떤 개발환경과 도구를 사용하는 지 보고 배울 수 있음 - 그날 읽은 코드에 오너쉽을 갖고 능동적으로 참여하게 됨 * reset.S 의 `z_arm_reset` 부터 C 도입 부분인 `z_arm_prep_c` 전까지 어셈블리 살펴봄 ### 2화 * 일시: 2021년 8월 15일, 20시부터 22시까지 * 참석자(8): blackbird, Kye-Hyun, Albert, 허정훈, 최봉진, Stephanos, 송종훈, 권경환 - 드라이버: blackbird * 3명이 새로 합류. 스터디 신청자 중 1명만 아직 합류하지 않음(spirit cha) * `z_arm_prep_c` 부터 `z_cstart` 의 `arch_kernel_init` 함수까지 살펴봄 - 디바이스트리와 - Security extension(TrustZone) - Logging subsystem - MPU 관련 코드는 일단 스킵하고 나중에 보기로 함 ### 3화 * 일시: 2021년 8월 22일, 20시부터 22시까지 * 참석자(7): blackbird, Kye-Hyun, 허정훈, Stephanos, yunsik, Chae Lee, 권경환 * 드라이버: 권경환(Kye-Hyun님 화면공유가 안되서 대타) * 자발적 참여로 모임 시작 전 60분 가량 문서읽기로 * oyskwu 님 새로 합류 ### 4화 * 일시: 2021년 8월 29일, 20시부터 22시까지 * 문서읽기는 19시부터 * 참석자(8): Kye-Hyun, 허정훈, yunsik, HyunYoung, 박종한, 최봉진, inhyun, 권경환 * 드라이버: Kye-Hyun * 문서읽기 * 참석자(5): HyunYoung, yunsik, Kye-Hyun, 허정훈, 권경환 * 허정훈 - [external modules](https://docs.zephyrproject.org/latest/guides/modules.html) * Kye-Hyun - [posix](https://docs.zephyrproject.org/latest/guides/portability/index.html) * 권경환 - [kernel timing](https://docs.zephyrproject.org/latest/reference/kernel/timing/clocks.html) * 스터디 소식 * inhyun 님 새로 합류 ### 5화 * 일시: 2021년 9월 5일, 20시부터 22시까지 * 참석자(6): 최봉진, inhyun, Kye-hyun, yunsik, Stephanos, 권경환 * 드라이버: Stephanos * 문서읽기 * 참석자(): * 허정훈 - [드라이버](https://docs.zephyrproject.org/latest/reference/drivers/index.html) * Kye-Hyun - [스레드](https://docs.zephyrproject.org/latest/reference/kernel/threads/index.html) * 권경환 - [커널 오브젝트](https://docs.zephyrproject.org/latest/reference/usermode/kernelobjects.html) * 스터디 소식 * blackbird 님 개인사정으로 하차 ### 6화 * 일시: 2021년 9월 12일, 20시부터 22시까지 * 참석자(7): BongJin, Inhyun, Kye-Hyun, Stephanos, yunsik, 허정훈, 권경환 * 드라이버: 허정훈 * 문서읽기 * 참석자(3): 허정훈, Kye-Hyun, 권경환 * 스터디 소식 * nucleo_l073rz 보드 기반으로 adc 드라이버 예제 읽기로 함 ### 7화 * 일시: 2021년 9월 19일, 20시부터 22시까지 * 참석자(6): Kye-Hyun, BongJin, Inhyun, 김준철, yunsik, 권경환 * 드라이버: BongJin * 문서읽기 * 참석자(2): Kye-Hyun, 권경환 * 스터디 소식 * 준철님 새로 합류 ### 8화 * 일시: 2021년 9월 26일, 20시부터 22시까지 * 참석자(7): Kye-Hyun, BongJin, Inhyun, 김준철, yunsik, 허정훈, 권경환 * 드라이버: yunsik * 문서읽기 * 참석자(2): Kye-Hyun, 권경환 * kobject 문서 훑어봄 ### 9화 * 일시: 2021년 10월 3일, 20시부터 22시까지 * 참석자(7): Kye-Hyun, BongJin, Inhyun, 김준철, yunsik, 허정훈, 권경환 * 드라이버: 김준철 * 문서읽기 * 참석자(3): Kye-Hyun, 김준철, 권경환 * 후보: * https://docs.zephyrproject.org/latest/guides/arch/arm_cortex_m.html * https://docs.zephyrproject.org/latest/guides/porting/index.html * https://docs.zephyrproject.org/latest/guides/test/index.html * https://docs.zephyrproject.org/latest/guides/tfm/index.html * https://docs.zephyrproject.org/latest/guides/build/index.html ### 10화 * 일시: 2021년 10월 10일, 20시부터 22시까지 * 참석자(5): Kye-Hyun, BongJin, Inhyun, 허정훈, 권경환 * 드라이버: Inhyun * 문서읽기 * 참석자(2): Kye-Hyun, 권경환 ### 11화 * 일시: 2021년 10월 17일, 20시부터 22시까지 * 참석자(6): Kye-Hyun, BongJin, Inhyun, 허정훈, yunsik, 권경환 * 드라이버: Kye-Hyun * 문서읽기 * 참석자(3): Kye-Hyun, 허정훈, 권경환 ### 12화 * 일시: 2021년 10월 24일, 20시부터 22시까지 * 참석자(5): Kye-Hyun, Inhyun, 허정훈, yunsik, 권경환 * 드라이버: 허정훈 * 문서읽기 * 참석자(3): Kye-Hyun, 허정훈, 권경환 ### 13화 * 일시: 2021년 10월 31일, 20시부터 22시까지 * 참석자(4): Kye-Hyun, Inhyun, 허정훈, 권경환 * 드라이버: 허정훈 * 문서읽기 * 참석자(3): Kye-Hyun, 허정훈, 권경환 ### 14화 * 일시: 2021년 11월 7일, 19시30분부터 21시30분까지 * 참석자(4): Kye-Hyun, Inhyun, 허정훈, 권경환 * 드라이버: 권경환 * 문서읽기 * 참석자(3): Kye-Hyun, 허정훈, 권경환 ### 15화 * 일시: 2021년 11월 14일, 20시부터 22시까지 * 참석자(4): Kye-Hyun, Inhyun, 허정훈, 권경환 * 드라이버: 권경환 * 문서읽기 * 참석자(3): Kye-Hyun, 허정훈, 권경환 ### 16화 * 일시: 2021년 11월 21일, 20시부터 22시까지 * 참석자(5): Kye-Hyun, Inhyun, yunsik, 허정훈, 권경환 * 드라이버: Kye-Hyun ### 17화 * 일시: 2021년 11월 28일, 20시부터 22시까지 * 참석자(4): Kye-Hyun, yunsik, 허정훈, 권경환 * 드라이버: 허정훈 ### 오프라인 식사 * 일시: 2021년 12월 3일, 19시30분부터 22시까지 * 참석자(5): Kye-Hyun, Inhyun, yunsik, 허정훈, 권경환 * 위치: https://www.diningcode.com/profile.php?rid=jAqpJTgD2b61 ### 18화 * 일시: 2021년 12월 5일, 20시부터 22시까지 * 참석자(4): Kye-Hyun, Inhyun, yunsik, 허정훈, 권경환 * 드라이버: yunsik ### 19화 * 일시: 2021년 12월 12일, 20시부터 22시까지 * 참석자(4): Kye-Hyun, Inhyun, yunsik, 허정훈, 권경환 * 드라이버: 권경환 * 19시에 cmake 관련 자료 살펴봄 * https://www.youtube.com/watch?v=bsXLMQ6WgIk * https://cliutils.gitlab.io/modern-cmake/ * https://hsf-training.github.io/hsf-training-cmake-webpage/ * https://riptutorial.com/cmake * https://www.internalpointers.com/post/modern-cmake-beginner-introduction * https://cmake.org/documentation * IPv6 사양: https://datatracker.ietf.org/doc/html/rfc2460 </details> ## 의문점들 * 초기화에서 dummy thread 가 필요한 이유? * SMP(xtensa)에서의 tick 업데이트 * `drivers/timer/xtensa_sys_timer.c:36` `ccompare_isr()` 에서 스핀락 걸고 announce 함 * 코어별 타이머는 `z_smp_init()` -> `arch_start_cpu()` -> `smp_init_top()` -> `smp_timer_init()` 에서 초기화 됨 * 모든 코어에서 announce하게 되어 있는데 한 곳에서만 해야 하지 않나? * `timeout_q`는 `_kernel` 전역변수에서 관리하는게 좀 더 구조적?이지 않나? 지금 구현은 모듈에서 static 으로 사용하고 있음. 나라면 큐랑 스핀락 모두 전역 커널 자료구조에 넣었을 것 같은데. 모듈화를 선호해서? 설계관점이 궁금하다 * 디바이스 핸들 용도? ## TODOs - [ ] Security extension - [ ] logging subsystem - [ ] 런타임 커버리지 - `z_cstart()` 첫번째 라인: `gcov_static_init()` - [ ] 문서 읽기 - [ ] [User and Developer Guides](https://docs.zephyrproject.org/latest/guides/index.html) - [ ] [Security](https://docs.zephyrproject.org/latest/security/index.html) - [ ] [Build and Configuration Systems](https://docs.zephyrproject.org/latest/guides/build/index.html) - [ ] [Application Development](https://docs.zephyrproject.org/latest/application/index.html) - [ ] [API Reference](https://docs.zephyrproject.org/latest/reference/index.html) - [ ] IPI 그리고 코어들에 대한 global timer의 인터럽트 - [ ] 디바이스 드라이버 정리 - [ ] 시스템콜 정리 - [ ] 빌드시스템 - [ ] 파이썬 스크립트 ## 용어 * PE - Processing Element * MVE - M-Profile Vector Extension * CMSE - Cortex-M Security Extensions ## 코드분석 ### 시스템 리셋 * Cortex-M 실행모드에는 thread mode와 handler mode 두가지 모드가 있음 - 스레드 모드는 어플리케이션 모드 - 핸들러 모드는 시스템 자원을 관리하는 커널 모드라고 볼 수 있음 - 모든 익셉션은 핸들러 모드에서 처리됨. 즉 인터럽트 진입시 무조건 핸들러 모드 - 리셋시 스레드 모드임 * 그리고 privileged 와 unprivileged 두가지 실행 권한이 있음 - 핸들러 모드에서는 무조건 privileged 모드로 실행 - 스레드 모드에서는 설정에 따라 privileged 일수도, unprivileged 일수도 있음 - `CONTROL.nPRIV` 에서 설정 - `CONTROL.nPRIV` 디폴트 값이 0이므로, 리셋시 privileged 모드임 * MSP, PSP 두개의 기본 스택과 security extension 유/무에 따라 MSP_S, PSP_S 두개의 스택이 더 있음 - Security extension 이 없는 경우 reset 시 MSP 를 사용 - Security extension 이 있는 경우 reset 시 MSP_S 를 사용 - 핸들러 모드에서는 MSP 사용 - 스레드 모드에서는 `CONTROL.SPSEL` 설정에 따라 MSP 가 될수도 PSP 가 될수도 있음 * 유효한 MSP 를 가진 Privileged thread mode 로 reset 벡터에 진입해야 함 - 부트로더에서 분기하든 다른 어플리케이션에서 분기하든 이 조건이 만족되어야 함 - 차후 MSP 는 인터럽트 핸들러에서만 사용 * C 초기화 코드로 넘어가기 전에 인터럽트 스택을 초기화하고 임시로(초기화가 끝나기 전까지) psp가 인터럽트 스택을 가리키도록 해 인터럽트 스택을 당분간 사용 * 부트코드는 당연히 하드폴트를 일으키면 안됨. NMI와 하드폴트를 제외한 모든 인터럽트를 금지함 * 시작지점(entry point)으로 `z_arm_reset` 이 지정되어 있지만 부트로더에서 `__start` 심볼을 찾는 경우도 있기 때문에 두 심볼 모두 동일한 주소로 맵핑 * 부트로더나 다른 어플리케이션으로부터 분기했을 수도 있기 때문에 `CONFIG_INIT_ARCH_HW_AT_BOOT` 옵션이 설정되어 있는 경우 core register 상태를 리셋 상태로 초기화함 * LDR 두번째 피연산자 앞에 `=` 용도 - pseudo 명령 사용을 암시함: https://developer.arm.com/documentation/dui0041/c/Babbfdih - `=` 뒤의 값이 어셈블러가 알 수 있는 값이고, 그 값이 “유효범위” 내에 있다면(예컨대 mov 명령어의 경우 imm8 영역) 해당 명령어가 생성됨 - 그러니까 8비트내의 값이라면, ldr은 mov 또는 mvn 명령으로 대체됨 - 유효범위를 벗어날 경우, 상수 값은 리터럴 풀에 저장되고 PC-relative LDR 명령어가 생성됨 - 그러니까 8비트를 벗어나는 값이라면, 그 값은 리터럴 풀에 저장되고 LDR 명령을 통해서 그 값을 레지스터에 읽어오게 됨 - ARM 명령셋은 남는 명령 하위 비트에 제한된 immediate 상수값만을 표현할 수 있음 - Architecture Reference Manual 의 C2 챕터 참고 - 따라서 보다 큰 상수값을 표현하기 위해서 ldr 명령으로 레지스터에 전체 상수값을 로드하는 방식을 사용함 ### 초기화 #### runlevel 에 따른 동적 초기화 * 4 단계의 런레벨로 구분됨 * SMP를 위한 추가적인 런레벨이 있음(총 5단계) * `SYS_INIT` 매크로로 초기화 함수를 등록함 * 등록된 심볼들은 `__init_start` 아래 등록됨 * 내부적으로 `Z_INIT_ENTRY_DEFINE` 매크로로 치환됨 * 어셈블러나 링커에서 alignment를 위한 패딩을 넣을 수 있기 때문에 명시적으로 alignment 를 지정함 * 패딩이 들어가면 array walk 가 쫑날 수 있기 때문 * 링커스크립트의 alignment 구문으로는 충분하지 않음. 어셈블러는 세그먼트별로 패딩을 넣을 수 있기 때문 * 커널 초기화할 때 `z_sys_init_run_level()` 함수로 등록된 초기화 함수들을 커널 컨텍스트에서 실행 ##### PRE_KERNEL_1 * kheap - statics_init * mailbox - init_mbox_module * mem_domain - init_mem_domain_module * mem_slab - init_mem_slab_module * pipes - init_pipes_module * system_work_q - k_sys_work_q_init * userspace - app_shmem_bss_zero ##### PRE_KERNEL_2 * gdb_init ##### POST_KERNEL * disk_init * fs_init ##### APPLICATION ### Memory Barrier * memory barrier 와 synchronization barrier 두가지로 분류 - memory barrier 는 compiler memory barrier와 cpu memory barrier 두가지로 분류 - DMB는 cpu memory barrier - ISB, DSB는 synchronization barrier * 편의상 4단계 파이프라인을 가정: fetch, decode, execution, write back * 언급된 아래 배리어외에도 csdb, pssbb, ssbb 가 있음 #### ISB * ISB 명령을 execute 하게 되면 파이프라인을 flush 하고(ISB 이후에 fetch 및 decode 된 명령들을 취소하고) 새로 fetch 함. 즉, ISB 이전 명령의 모든 연산 결과가 ISB 이후 명령들에 적용됨 * Control 레지스터 변경이나 인터럽트 활성/비활성 등의 명령 뒤에 사용됨. 해당 연산의 결과는 다음 명령에 바로 visible 해야 하기 때문 #### DSB * DMB 는 reordering 만을 방지하는 반면, DSB 는 앞선 메모리 연산이 완료될 때 까지 다음 명령을 실행하지 않는다 * ISB는 flush 하는 반면 DSB는 stall 시킴 * 이를테면, 캐시 invalidate 한 경우 캐시 상태가 시스템 전반에 전달되어야 하기 때문에 DSB 명령이 사용됨 #### DMB * 캐시나 메모리 특성에 따라 의존성이 없는 경우 효율을 위해 메모리 연산을 프로세서가 reordering 하는 경우가 생기는 데, 이를 방지하기 위해 사용 * 가령 memory mapped I/O 레지스터의 결과가 다음 메모리 접근에 영향을 줄 경우, 프로세서는 이를 모르고 reordering 할 수 있음. 이때 두 명령 사이에 DMB 명령을 넣으면 reordering 막아줌 ### Memory Type #### Normal Memory * 일반 코드 및 데이터용 메모리 * 프로세서가 memory reordering 이나 merging 같은 메모리 최적화를 수행할 수 있음 #### Device Memory * load 와 store 가 반드시 코드 순서대로 발생 * 다음과 같은 소속성을 지님 * G: gathering * 여러개의 접근이 하나의 transaction으로 합쳐질 수 있음 * R: reordering * E: early write acknowledge? * 다음 4가지 조합만 가능 * !G!R!E = Strongly ordered memory type * !G!RE = Device memory type * !GRE * GRE #### Strongly Ordered Memory(v6 & v7) * Device Memory 조건 + 해당 연산이 종료될때까지 기다림 ### Memory Attributes #### Shareable * 여러 버스 마스터가 있는 시스템에서 마스터끼리 메모리 동기화 * 가령, 프로세서와 DMA는 하나의 버스를 공유하는 각각의 마스터 * 여러 버스 마스터가 non-shareable 메모리에 접근할 수 있다면, 소프트웨어에서 데이터 coherency 를 반드시 보장해야 함 * strongly-ordered memory 는 항상 shareable 임 #### Cacheable #### Transient * 충분한 시간적 지역성temporal locality을 갖지 못하는 경우 * 다시 사용될 일 없는 데이터에 캐시를 할당하므로써 다른 캐시 엔트리를 밀어내지 않도록 * 캐시의 LRU 위치에 집어넣어 다른 캐시 엔트리에 비해 금방 evict 될 수 있도록 할 수 있는 속성? * 검색을 좀 해보니 사용하는 경우가 없는 듯? 구현비용에 비해 얻는 이득이 크지 않아서? * B7.15: R~XQXW~, I~LDXP~ ### Shareability Domain * 시스템을 어떻게 설계하냐에 따라 다르겠지만, 보통 동일한 운영체제를 사용하는 프로세서들이나 하이퍼바이저는 Inner Shareable shareability domain 에 속함 - 예컨대, 시스템 내의 두 프로세서는 inner로 묶일 수도 있고 outer로 묶일 수도 있음 - 또다른 예로 big.LITTLE 시스템은 두개의 클러스터를 가지는 데, 클러스터 간은 outer, 클러스터 내는 inner로 묶임 * Non-cacheable 일 경우, 모든 observer(master)에게 coherent 해야 하므로 outer shareable 임 * synchronization barriers - ISB는 core 별로 실행되어야 하는 명령이므로 제외 - 외부 버스에 전달되어야 하는 경우(예컨대 DMA): sy 또는 osh - inner의 경우: ish. ### 메모리 도메인 * 여러 파티션(혹은 하나의)을 하나의 도메인으로 묶어 권한을 설정 * 스레드는 하나의 도메인에 속하고 도메인 권한에 따라 메모리 접근 * `SYS_INIT` 매크로로 메모리 도메인을 초기화하는 함수가 등록되어 있음, `init_mem_domain_module()` * 디폴트 도메인을 초기화하고 * libc 파티션을 디폴트 도메인에 추가함 * `gen_app_partitions.py` 의해 관련 심볼들이 명시된 섹션으로 들어가고 * `K_APPMEM_PARTITION_DEFINE` 매크로로 해당 섹션주소를 파티션 주소에 할당 ### Linker script * include/arch/arm/aarch32/cortex_m/scripts/linker.ld - common-rom.ld - snippets-rom-start.ld - arch/arm/core/aarch32/CMakeLists.txt 의해서 만들어짐 - arch/arm/core/aarch32/vector_table.ld - arch/arm/core/aarch32/cortex_m/relay_vector_table.ld * scripts/gen_relocate_app.py - linker_relocate.ld 파일과 - code_relocation.c 파일을 생성함 - 코드 재배치를 위해 소스코드와 input section 지정을 분리한 듯? * scripts/gen_app_partitions.py - CMakeLists.txt 에서 invoke 됨 ### 코드/데이터 메모리 재배치 * 런타임 재배치가 아니라 컴파일 타임 재배치임 * 보드별로 서로 다른 여러개의 메모리 공간region을 갖고 있기 때문에 보드마다 특정한 메모리 공간을 지정하기 위해 사용 * SRAM1, SRAM2, ITCM, DTCM 등 * MMU 가 없는 cortex-m 프로파일에서만 사용 * CMakeLists.txt:797 의 `toolchain_ld_relocation()` 매크로가 gen_relocate_app.py 를 실행 * cmake/linker/ld/target_relocation.cmake 에 정의되어 있음 * gen_relocate_app.py 의 인자는 다음에서 설정됨 * cmake/extensions.cmake:1213 의 `zephyr_code_relocate` 로 `code_data_relocation_target` 을 설정 * 사용처를 찾아보니 현재로선 XIP용 SPI 플래시를 다루는 코드에만 사용하는 듯(속도 때문?) * kernel/init.c 의 다음 코드들은 생성되지 않음 * bss_zeroing_relocation() * data_copy_xip_relocation() * 비용 대비 효율이 안좋은 거 아닌지. 복잡도만 너무 올라간 거 아닌가.. ### 가독성을 해치고 유지보수를 어렵게 하는 #ifdef 전처리 대안 예제: ```c= #define _XXXX1 _YYYY, #define __DEBRACKET(...) __VA_ARGS__ #define __GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET val #define __COND_CODE(one_or_two_args _if_code, _else_code) \ __GET_ARG2_DEBRACKET(one_or_two_args _if_code, _else_code) #define Z_COND_CODE_1(_flag, _if_1_code, _else_code) \ __COND_CODE(_XXXX##_flag, _if_1_code, _else_code) #define COND_CODE_1(_flag, _if_1_code, _else_code) \ Z_COND_CODE_1(_flag, _if_1_code, _else_code) ``` * 참일 경우, 다음과 같이 확장됨 * `COND_CODE_1(1, ("true"), ("false"))` * `Z_COND_CODE_1(1, "true", "false")` * `__COND_CODE(_XXXX1, "true", "false")` * `__GET_ARG2_DEBRAKET(_YYYY, "true", "false")` * `__DEBRACKET "true"` * 참이 아닐 경우, 다음과 같이 확장됨 * `COND_CODE_1(0, ("true"), ("false"))` * `Z_COND_CODE_1(0, "true", "false")` * `__COND_CODE(_XXXX0, "true", "false")` * `__GET_ARG2_DEBRAKET(_XXXX0 "true", "false")` * `__DEBRACKET "false"` * 핵심 트릭은 매크로에 콤마를 넣거나 뺌으로써 value 값을 조정 * 매크로 인자를 반드시 괄호로 감싸주어야 함 * `__VA_ARGS__` 매크로가 마지막 단계에서 괄호를 한단계 풀어(없애)주는 듯 * `__DEBRACKET` 을 호출하는 부분에서 괄호를 씌우면 될텐데 * `__GET_ARG2_DEBRACKET(ignore_this, val, ...) __DEBRACKET(val)` 이런식으로 * 이유가 뭘까? ### 인터럽트 * Processor core exception 과 device-specific exception 으로 나눌 수 있음. 각각 * Internal interrupt * External interrupt 라고 칭하겠음 #### 초기화 * `SHCSR` 레지스터로 각종 fault 활성화 함 * `SCR.SEVONPEND` 로 core 가 슬립상태일 때 인터럽트 발생시 wakeup 할 수 있도록 함 * `AIRCR` 레지스터의 secure 관련 설정 #### Internal interrupts * 커널 코드 시작지점은 링커스크립트의 `ENTRY(CONFIG_KERNEL_ENTRY)`로 지정됨 * 링커스크립트 위치는 `include/arch/arm/aarch32/cortex_m/scripts/linker.ld` * `CONFIG_KERNEL_ENTRY` 디폴트 값은 `__start` * aarch32의 경우 `__start` 는 `arch/arm/core/aarch32/cortex_m/reset.S` 에 정의되어 있음 * 링커스크립트의 벡터테이블 관련 섹션은 `snippets-rom-start.ld` 의해 include 되는데 * 링커스크립트의 `snippets`으로 시작하는 링커 파일들은 cmake의 `zephyr_linker_sources`로 취합된 뒤 generated 디렉토리에 생성됨 * `zephyr_linker_sources` cmake 함수 정의는 `cmake/extensions.cmake` 에 있음 * `snippets-rom-start.ld` 에서 include 되는 `rom_start_offset.ld` 과 `vector_table.ld` 파일은 각각 `arch/common/CMakeLists.txt` 와 `arch/arm/core/aarch32/CMakeLists.txt` 에서 추가됨 * `arch/arm/core/aarch32/cortex_m/vector_table.S` 에 정의된 벡터 테이블은 `vector_table.ld` 에 선언한 `exc_vector_table` 섹션에 위치하게 됨 * `_IRQ_VECTOR_TABLE_SECTION_SYMS`(`.gnu.linkonce.irq_vector_table*`) 는 `exc_vector_table` 섹션 바로 다음 위치에 들어감 #### External interrupts *`IRQ_CONNECT` 로 생성되는 서비스 루틴들 * `IDT_LIST`(`intlist.ld`) 라는 모조의 메모리 공간에 IRQ 메타 데이터(`struct _isr_list`)들이 등록됨 * `ZEPHYR_PREBUILT_EXECUTABLE` 를 먼저 빌드한 뒤 `.intList` 섹션에 등록된 위 데이터를 `isrList.bin` 파일로 만듬 * `isrList.bin` 의 헤더는 `arch/common/isr_tables.c` 파일에서 `_iheader` 를 `.irq_info` 섹션에 저장 * `gen_isr_tables.py` 스크립트를 통해 `isr_tables.c` 파일을 생성하고 이 irq 테이블은 `_IRQ_VECTOR_TABLE_SECTION_NAME` 섹션, 즉 `exc_vector_table` 바로 뒤에 위치하게 됨 * 모든 외부 인터럽트 핸들러는 `ISR_WRAPPER`를 거쳐 호출되게 됨 * `_isr_wrapper`은 `arch/arm/core/aarch32/isr_wrapper.S` 에 정의되어 있음 #### 인터럽트 우선순위 * armv6m 에서 internal interrupt 우선순위는 설정 불가능(svc, pendsv, systick 제외) * v7에서 memmanage, busfault, usagefault, debugmonitor가 추가됐고 우선순위 설정 가능함 * v8에서 banked 된 hardfault 와 securefault 가 추가됨 * CMSIS에서 제공하는 NVIC_SetPriority 함수는 음수값일 경우 internal, 0을 포함한 양수값일 경우 external interrupt 를 가리킴 * SHPRx 레지스터의 초기값이 0이므로 internal interrupt 우선순위는 0 - `z_arm_exc_setup()` 에서 설정됨 * PendSV는 항상 가장 낮은 우선순위를 가짐 * SVC는 external interrupts 보다 항상 높은 우선순위를 가짐 - `CONFIG_ZERO_LATENCY_IRQS` 가 설정된 경우, SVC 보다 우선순위가 높은 external interrupts 를 만들 수 있음 - 즉, 스케줄러가 선점할 수 없고 스케줄러를 선점하는 문맥을 만들 수 있음 - 따라서 관련 코드는 유념해 작성해야함 - 데드락이 발생할 수도 있고 - Busy waiting으로 벽돌이 될 수도 있음 - 노르딕 nrf52 BLE 스택이 zero latency irq 우선순위에서 동작한다고 함 * `CONFIG_NUM_IRQS` 은 벤더에서 구현한 external interrupts 의 갯수 #### 인터럽트 릴레이 * arch/arm/core/aarch32/irq_relay.S * `__vector_relay_table` -> `__vector_relay_handler` -> `_vector_table_pointer` -> `_vector_start` * arch/arm/core/aarch32/cortex_m/vector_table.S * ARMv6-M 나 일부 ARMv8-M baseline core의 경우 벡터 테이블 주소를 변경할 수 없음 * 따라서 부트로더등의 다른 프로그램에 의해 벡터 테이블이 이미 선점된 경우, zephyr 벡터 테이블을 사용할 수 있도록 “릴레이"함 * 예컨대 부트로더의 경우, 부트로더에 `__vector_relay_table` 심볼이 알려져있고 인터럽트 발생시 해당 테이블로 분기해야함 - https://github.com/mcu-tools/mcuboot/blob/e933e586ec179789d98d10821226533586577460/boot/zephyr/main.c#L223 - 현재 mcuboot 만 지원하고 있다는데, 근데 위 코드는 벡터 테이블 주소를 변경 가능한(VTOR) 경우에만 동작할 듯? - VTOR 지원하지 않는 경우엔 Port 레이어에서 처리해줘야 할 듯 #### EXC_RETURN ![D1.2.95 Exception Return Payload](https://i.imgur.com/Ux4LIGT.png) * security 도메인 또는 FPU 사용을 구분해야 할 때 `EXC_RETURN` 은 TCB에 저장되어야 함 #### 인터럽트 wrapper * 모든 인터럽트 핸들러는 마지막에 `z_arm_int_exit` 를 호출함 * `z_arm_int_exit` 는 pendsv 를 올리고 stack sentinel 체크 후 핸들러에서 빠져나감 ### FLOAT & MVE * CP10 과 CP11 이 관련 코프로세서임 * 32개의 단정도 레지스터를 갖고 있음(S0~S31) - 2개의 레지스터를 결합하여 16개의 배정도 레지스터로 사용할 수 있음(D0~D15) * CPACR.CP10 에서 접근권한을 부여함 - CP11은 CP10과 동일한 값을 가져야 함 - Full access, privileged only access, no access 설정 가능 * FPCCR.ASPEN 은 exception 발생시 부동소수점 관련 레지스터도 스택에 저장하도록 함 - 그리고 `CONTROL.FPCA` 플래그를 셋 함 - 인셉션 진입시 그만큼(스택에 S0~S31 저장) latency 발생 - 스택 사용량이 그만큼 커짐 ### MPU * Cortex-M 은 unified 만 지원. instruction/data 영역을 구분하지 않음 * 즉, `MPU_TYPE.DREGION` 만 기능 * `MPU_TYPE.SEPERATE` 는 항상 0 * `MPU_CTRL.PRIVDEFENA` 로 region이 설정되지 않은 영역에 privileged 접근을 가능하게 함 * 총 8개의 region 을 제공 * v6와 v7에서는 8개의 subregion 을 제공함 * 각 영역region은 32바이트 단위로 정렬되어야 함 * cache line length? * region 번호가 높을수록 높은 우선순위 * 비활성화되어 있는 경우, default system address map 에서 접근 속성을 가져옴 * execute-never(XN) 비트는 해당 영역의 instruction이 fetch 될 수 있는지 설정. XN이 활성화된 상태에서 해당 영역을 실행하게 되면 execute 단계에서 memory management fault 발생 * 인터럽트 벡터 어드레스 테이블은 MPU가 체크하지 않음 * 레퍼런스 매뉴얼 B10.1: R~VHHL~ * 벡터 테이블 주소가 바껴도?(VTOR) * 임베디드 시스템에서 보통 다음과 같이 분류함 * privileged code * user code * privileged data * user data * privileged peripherals * user peripherals * Zephyr cortex-m 에서는 다음과 같이 초기 설정함 * non-cacheable ram area * `__nocache` 를 키워드로 사용처를 찾아보니 이더넷과 USB 엔드포인트 버퍼에 사용됨 * 예컨대, 한편으론 DMA를 통해 수신한 이더넷 프레임을 특정 RAM에 저장하고, 다른 한편으론 프로세서에서 해당 RAM 영역에 접근할 경우 * 그 영역이 캐시 가능한 영역이라면 stale 한 값을 읽게 되기 때문 * ram code * ram area for relocated text * for main stack guard * user 스레드에서 RO 코드를 읽거나 실행할 수 있도록 초기 설정 * 스레드 stack guard 는 컨텍스트 스위칭 때 설정됨 * Zephyr 에서는 memory domain 이라는 개념이 있음 * 스레드는 하나의 memory domain 에 속함 * 하나의 memory domain 은 하나 또는 여러개의 파티션으로 이루어짐 * 문맥전환할 때 `z_arm_configure_dynamic_mpu_regions` 로 스레드별 설정 * `CONFIG_USERSPACE` 가 설정되어 있는 경우, 스레드가 속한 메모리 도메인의 파티션들은 파티션당 하나의 region 으로 설정됨 * user 스레드인 경우, 스택 역시 하나의 region 으로 설정됨 * `CONFIG_MPU_STACK_GUARD` 가 설정되어 있는 경우, guard 용도로 하나의 region 이 설정됨 * supervisor 스레드일 경우: `thread->stack_info.start` 앞에 * user 스레드일 경우: `thread->arch.priv_stack_start` 앞에 #### 설정방법 1. 설정 중 폴트발생을 막기 위해 MPU 기능을 비활성화, `MPU_CTRL.ENABLE` 2. 설정하려는 region을 설정, `MPU_RNR.REGION` 3. 설정하려는 region의 시작주소를 설정, `MPU_RBAR` 4. region 속성 설정, `MPU_RBAR` & `MPU_MAIR` 5. region의 마지막주소 설정, `MPU_RLAR` 6. region 속성 연결, `MPU_RLAR.AttrIndx` 7. region 활성화, `MPU_RLAR.EN` ### WFI vs WFE * https://developer.arm.com/documentation/ka001283/latest * WFE 는 multi-processor 설계에 크게 관련있는 듯 * 멀티코어 환경에서의 spinlock 을 예로 들고 있음 * 인터럽트는 이벤트의 일종으로 볼 수 있을 듯(인터럽트 $\subset$ 이벤트) * 기본 idle 함수는 wfi 를 사용하는 반면 atomic 은 wfe 를 사용함 ### 스레드 * 크게 다음의 구성요소를 가짐 * 스택 * TCB(Thread Control block) * 함수 entry * 스케쥴링 우선순위 * 실행모드 * 디폴트는 supervisor 모드. 모든 memory address space와 peripherals 에 접근가능하고 privileged instruction 을 실행할 수 있음 * 시스템콜용 fixed-size privilege elevation stack 이 따로 있음 * 시스템 초기화시 하나의 main 스레드와 코어별 idle 스레드를 생성 * main 스레드는 커널 초기화를 수행하고 `main()` 함수를 호출 * 선점형일 경우 가장 높은 우선순위인 0 * 비선점형일 경우 가장 낮은 우선순위인 -1 * 통상 단일 스레드 어플리케이션일 경우 `main()`함수 사용 * idle 스레드는 항상 존재해야 함 * 우선순위는 항상 가장 낮은 우선순위 * 통상 슬립모드로 들어가는 역할 * 그리고 필요에 따라 시스템 workqueue 스레드를 생성 * 스레드 시작지점은 항상 `z_thread_entry` * `arch_user_mode_enter()` * 스레드 종료시에는 항상 `z_thread_abort()` 가 호출됨 * join 호출등의 이유로 pended 되어 있는 스레드들 다 깨움 * 자원정리 및 정보 업뎃 * `K_THREAD_DEFINE` 매크로로 정적으로 스레드를 등록할 수 있음 * 등록된 스레드는 커널 초기화 후 main 호출 전에 실행됨 #### 스레드 lifecycle #### 스레드 상태 ![](https://docs.zephyrproject.org/latest/_images/thread_states.svg) * `_THREAD_QUEUED` 가 Ready 상태 * `_THREAD_PRESTART` 가 New 상태 #### 스레드 우선순위 * `int8_t` 형 * `CONFIG_NUM_COOP_PRIORITIES` 와 `CONFIG_NUM_PREEMPT_PRIORITIES` 로 설정할 수 있지만, `int8_t` 형 범위를 넘어설 수 없음 * 낮은 숫자일 수록 높은 우선순위 * 우선순위는 런타임에 바뀔 수 있음 * 우선순위에 따라 두가지 종류의 스레드: * cooperative thread * 우선순위가 음수일 경우 * 스스로 CPU 자원을 넘기지 않는 이상 계속 current 스레드가 됨 * preemptible thread * 우선순위가 0과 같거나 큰 경우 * 우선순위가 같거나 높은 스레드에 의해 선점됨 * bottom-half 를 처리하기 위한 meta-irq 우선순위의 스레드가 ready queue에 있을 경우 cooperative 스레드일 경우라도 선점됨 * 스케쥴러 락이 걸려있더라도 선점됨 * 그러니까 어플리케이션이 실행되기 전에 무조건 meta-irq 가 실행됨 ### 스케쥴링 * 우선순위 기반 스케쥴링 * cooperative 와 * preemptive 두 종류 * time slice 를 사용할 경우와 * time slice는 스레드별로 설정하는 게 아니라 시스템 전역임 * 그렇지 않은 경우 * 동일한 우선순위일 경우 가장 오래 실행되지 않은 스레드가 스케쥴링 됨 * ready queue 자료구조는 다음 중 하나가 될 수 있음: * 링크드 리스트(`CONFIG_SCHED_DUMB`) * memory foot print 는 가장 작지만, 적은 수의 스레드만 runnable 인 시스템에 사용 * 스레드 수가 많을수록 비확정적인 latency 발생 * red-black tree(`CONFIG_SCHED_SCALABLE`) * 삽입/삭제에 약간의 오버헤드가 추가됨 * 최대 2KB 코드 사이즈 증가 * multi-queue(`CONFIG_SCHED_MULTIQ`) * `k_sched_lock()`은 선점가능한 스레드를 일시적으로 선점 불가능한 cooperative 스레드로 만듬 * 실제로 우선순위를 변경하는 것 보다 효율적임 * 진입지점인 pendsv 위치는 arch/arm/core/aarch32/swap_helper.S * vector_table.S -> swap_helper.S * 디폴트 스케줄러는 `SCHED_DUMP` * 런큐에 넣을 때 우선순위에 따라 정렬해서 넣으므로 O(N) * 런큐에서 빼낼 때는 맨 앞쪽에 가장 높은 우선순위가 있으므로 O(1) ### 디바이스 * 디바이스는 `DEVICE_DEFINE` 매크로 또는 `SYS_INIT`, `SYS_DEVICE_DEFINE` 매크로로 컴파일 타임에 등록할 수 있음 #### 디바이스트리 * 네 종류의 파일로 이루어짐 * .dts * 타겟 보드의 하드웨어를 기술하는 base 파일. 보통 board 디렉토리에 위치하며 dtsi 파일들을 include 함 * .dtsi * 여러 보드에 공통으로 사용할 수 있는 하드웨어 기능들 * .overlay * optional 이며 base 파일을 override 함 * 가령 디폴트로 비활성화되어 있는 기능을 KConfig 설정으로 활성화시킬 경우, 코드 수정할 일 없이 overlay 로 가능 * .yaml * 바인딩 파일 * dts/bindings 디렉토리에 있음 * 디바이스트리 빌드 방식 * 통상 보드별로 하나의 .dts 파일이 있음. 해당 파일에서는 보드 특정 하드웨어를 기술함 * 다른 보드와 공통된 기능은 .dtsi 파일에 기술되고 위 .dts 파일에서 include 됨 * .dtsi 파일은 board->vendor->architecture->skeleton 식으로 계층적으로 include 됨 * 기존 노드를 overwrite 하고 싶을 때 노드명 앞 `&` 를 붙이고 다시 정의할 수 있음 * `#interrupt-cells` 속성은 값으로 1 또는 2 가질 수 있는데 * 첫번째 값은 인터럽트 인덱스 * 두번째 값은 * 1 = low-to-high edge triggered * 2 = high-to-low edge triggered * 4 = active high level-sensitive * 8 = active low level-sensitive * `DEVICE_DT_INST_DEFINE` -> `DEVICE_DT_DEFINE` * 내부적으로 `Z_DEVICE_DEFINE` 호출 ##### 예제: STM32 ADC 의 경우 `drivers/adc/adc_stm32.c` 파일의 `STM32_ADC_INIT` 매크로로 `POST_KERNEL` 런레벨에 드라이버가 초기화됨. `build/zephyr/include/generated/` 하단에 생성되는 헤더는 `scripts/dts/gen_defines.py` 스크립트에 의해 생성됨. 드라이버 소스(`drivers/adc/adc_stm32.c`)의 제일 하단 `DT_INST_FOREACH_STATUS_OKAY()` 매크로로 드라이버가 등록됨. 확장 순서는 다음과 같음: * 디바이스트리의 해당 노드가 활성화(okay)되어 있다면 등록된 모든 인스턴스에 대해 `STM32_ADC_INIT` 매크로를 실행함 * `DT_FOREACH_OKAY_INST_st_stm32_adc()` 매크로는 `gen_defines.py` 로 만들어짐 * `build/zephyr/include/generated/devicetree_unfixed.h` 에서 확인할 수 있음 * 예제의 경우 인스턴스가 1개이므로 `DT_FOREACH_OKAY_INST_st_Stm32_adc(STM32_ADC_INIT(0))` 로 확장됨 `node_id` 의 경우 `DT_DRV_INST` 매크로를 통해 다음과 같이 확장된다: 1. `DT_DRV_COMPAT`은 드라이버 최상단에 `st_stm32_adc`로 정의되어 있음 2. `DT_INST(0, st_stm32_adc)` 3. `UTIL_CAT(DT_N_INST, DT_DASH(0, st_stm32_adc))` 4. `MACRO_MAP_CAT(aMacroToAddUnderscore, 0, st_stm32_adc)` 5. `UTIL_CAT(DT_N_INST, _0_st_stm32_adc)` 6. 즉, `node_id`는 `DT_N_INST_0_st_stm32_adc`에서 `DT_N_S_soc_S_adc_40012400`으로 확장됨 `MACRO_MAP_CAT` 매크로는 넘어온 인자를 특정패턴으로 반복적으로 이어붙이는 역할을 한다. 내부적으로 사용된 `NUM_VA_ARGS_LESS_1` 매크로는 실제로 전달된 인자의 갯수를 상수로 리턴하는 역할을 한다. `NUM_VA_ARGS_LESS_1_IMPL` 매크로에서 리턴값으로 사용되는 `N`의 위치가 넘어가는 인자 갯수에 따라 달라지기 때문. 1. `Z_DEVICE_DT_DEV_NAME(DT_N_S_soc_S_adc_40012400)` 2. `_CONCAT(dts_ord_, DT_DEP_ORD(DT_N_S_soc_S_adc_40012400))` 3. `DT_DEP_ORD`매크로는 `DT_N_S_soc_S_adc_40012400_ORD`로 확장되고 결국 `13` 이라는 상수값이 됨 4. 즉, `dts_ord_13` 으로 확장됨 따라서 실제 호출 인자는 다음과 같다: `Z_DEVICE_DEFINE(DT_N_S_soc_S_adc_40012400, dts_ord_13, "ADC_1", ...)` device 자료구조는 `__device_dts_13` 형식의 이름으로 정의된 뒤 `devices` 섹션의 `__device_POST_KERNEL` 하단에 등록된다. #### mux * 하위 5비트 = remap * 다음 1비트는 padding * 그 다음 2비트는 alt func * 그 다음 4비트는 pin * 그 다음 4비트는 port ### 시스템콜 * `scripts/gen_syscalls.py` 스크립트로 `z_impl_` prefix를 갖는 함수로 바인딩됨 * include/generated/syscall_dispatch.c 생성 * CMakeLists.txt:623 에서 custom command로 실행 * `_k_syscall_table` 이 위 스크립트로 생성되고 `svc` -> `_do_syscall` 에서 참조됨 * syscalls.json 을 참조하고 만들어지는데 * syscalls.json 파일은 `scripts/parse_syscalls.py` 스크립트로 만들어짐 * 시스템 헤더들에서 `__syscall` 를 추출 * 인덱싱을 어떻게 하는지? ### 동기화 자료구조 * API 문서의 `isr-ok` 특성은 인터럽트 핸들러에서도 해당 함수가 호출될 수 있다(blocking 되지 않는다)일 뿐 thread-safe를 보장하지 않음 * 사용자가 동기화 책임을 가짐 * queue 가 lock-free 자료구조로 구현되어 있나 살펴보니 아니었음 ### kobject * 주목적은 여러 커널 오브젝트들을 특정 오브젝트 타입으로 분류해서 접근권한과 참조수를 관리? * 오브젝트(심볼) 주소로 타입을 찾는데, 이때 해시(gperf)를 사용 * scripts/process_gperf.py * 오브젝트별로 해시를 만드면 메모리 낭비 같은데? * 관련 소스들 * scripts/gen_kobject_list.py * linker/kobject-text.ld * 시스템콜, 스래드 콜 등에서 `z_object_validate()` 함수로 권한 체크함 ### 시스템 클럭 * `sys_clock_isr` -> `sys_clock_announce` * `sys_clock_isr` 은 `SYS_DEVICE_DEFINE`으로 등록됨 * `sys_clock_announce` 에서 스레드 time slice 처리 * elapsed 된 시간만큼 time slice 줄임. 0 이 된 경우 문맥전환 * `z_add_timeout` 으로 등록된 타임아웃 콜백들이 `sys_clock_announce` 에서 호출됨 * timeout 은 가까운 시간순대로 정렬. O(N) 함수임 * tickless일 경우, 가장 가까운 timeout의 dt를 systick load 값으로 설정 * 등록된 timeout이 없을 경우 최대값(`MAX_WAIT`)으로 설정 * 남은 스레드 time slice가 timeout 이나 최대값보다 작을 경우 time slice 값으로 설정 * 전역변수인 `_kernel`의 `timeout_q`와는 무슨 관계 혹은 차이일까? * timeout.c 에 static 으로 정의된 `timeout_list` 와 동일한 용도로 중복된 것 같음 * 코드를 `_kernel.timeout_q` 사용하도록 바꾸는 게? * 그리고 spinlock을 `_kernel` 구조체에 집어넣으면, `timeout_lock`이나 `sched_spinlock`처럼 여러개의 lock을 하나로 합칠 수 있지 않나? ### SMP 이해를 돕기 위한 SMP 다이어그램: ![SMP sample diagram](https://www.intel.com/content/dam/altera-www/global/en_US/documentation/sfo1410070178831/sfo1410068290100.svg) * ARM SMP 시스템에는 다음 세가지 종류의 인터럽트가 있음 * SGI: Software Generated Interrupt * 대게 inter-core 통신을(IPI: Inter-Processor Interrupt) 위해 사용됨. 인터럽트 0~15번이 이 용도로 예약되어 있음 * PPI: Peripheral Private Interrupt * 개별 core 에 종속된 peripheral 에서 발생하는 인터럽트. 인터럽트 16~31번이 이 용도로 예약되어 있음 * SPI: Shared Peripheral Interrupt * 인터럽트 컨트롤러에서 하나 또는 여러개의 core 로 인터럽트를 발생. 인터럽트 32~ 번이 이 용도로 예약되어 있음 ### 네트워크 ### 기타 * 관례상 `_` 로 시작하는 이름은 c 라이브러리와 같은 c 언어에 관련된 용도로 사용 * `__`로 시작하는 이름은 컴파일러 내부에서 사용 * 스택 데이터 타입 * MPU region 설정시 alignment 제약 때문에 임의의 char 형 버퍼를 간단히 스택으로 지정하기 어려움 * 그래서 `K_THREAD_STACK()` 매크로와 opaque data type 을 만듬 * `__LP64__` * 64비트 시스템인 경우 컴파일러에서 define 함 * long pointer 줄임말 * flagged singly linked list * 남는 하위 2비트를 사용자 지정 플래그로 사용하려고 generic 한 API를 만들어 둔 것 * stack canary & stack sentinel * canary 는 컴파일러에서 제공하는 stack smashing protection 기능을 사용하기 위한 것 * sentinel 은 커널(아마도 스케줄링할 때?)에서 주기적으로 체크해 corruption 을 감지하기 위한 것 #### 단계별 초기화 내용 * reset.S * 시스템 상태(레지스터)를 known 상태로 설정 * 인터럽트를 금지 * c 코드로 분기하기 전 인터럽트 스택을 PSP 로 설정하고 전환 * `prep_c.c: z_arm_prep_c` * zephyr 인터럽트 벡터를 사용하도록 설정 * 부트로더등으로부터 분기한 경우 다른 시스템의 인터럽트 벡터를 사용하고 있기 때문 * FPU 초기화 * bss, data 섹션 초기화 * 외부 인터럽트 우선순위 초기화 * `init.c: z_cstart` * 커버리지 정보 초기화 * 로깅 초기화 * 인터럽트 스택 설정 * 내부 인터럽트(우선순위 포함) 초기화 * fault 활성화 시키고 * systick 및 svc, pendsv등 우선순위 설정 * MPU 초기화 * 커널 오브젝트 초기화 * 초기화 코드들 실행 * `PRE_KERNEL_1` * `PRE_KERNEL_2` * main 스레드 생성, 초기화, 실행 * main 스레드로 스위칭하면서 인터럽트 활성화 ## 보드 포팅 * https://docs.zephyrproject.org/latest/guides/porting/board_porting.html ## 참고자료 ### GNU Assembler * https://docs.huihoo.com/redhat/rhel-4-docs/rhel-as-en-4/index.html * https://sourceware.org/binutils/docs/as/Section.html ### ARM #### ARM Instruction Set Architecture * https://developer.arm.com/architectures/instruction-sets #### ARM Architexture Reference Manual * Armv8-M - https://developer.arm.com/documentation/ddi0553/bp - An Introduction to the ARMv8-M architecture - https://developer.arm.com/documentation/100688/0200 * Armv7-M - https://developer.arm.com/documentation/ddi0403/ee * Armv6-M - https://developer.arm.com/documentation/ddi0419/e #### Procedure Call Standard for the Arm Architecture(ABI) * https://developer.arm.com/documentation/ihi0042/latest/ * https://github.com/ARM-software/abi-aa/releases ### Zephyr Documentation * https://docs.zephyrproject.org/latest/guides/build/index.html#build-overview ### Memory barriers * http://www.rdrop.com/users/paulmck/scalability/paper/whymb.2010.07.23a.pdf * https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/memory-access-ordering---an-introduction ### Shareability Domain * https://developer.arm.com/documentation/ihi0022/e/ACE-Protocol-Specification/About-ACE/Concepts-required-for-the-ACE-specification/Domains * https://medium.com/@om.nara/arm64-system-memory-fbf71dce37ee ### C 표준 * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf ### SMP * https://developer.arm.com/documentation/198123/0300/Arm-CoreLink-GIC-fundamentals ### 기타 * 섹션의 allocatable 과 loadable 의 의미 - https://www.avrfreaks.net/forum/lodable-allocatable-sections * Stack smashing protection - https://embeddedartistry.com/blog/2020/05/18/implementing-stack-smashing-protection-for-microcontrollers-and-embedded-artistrys-libc/ - canaries - http://www.lazenca.net/display/TEC/03.Canaries * Transient memory * https://stackoverflow.com/questions/38636326/concept-and-advantages-of-transient-and-non-transient-memory-in-arm * futex * https://eli.thegreenplace.net/2018/basics-of-futexes/ * gperf * https://www.stev.org/post/cppusinggperf * Thread Local Storage * https://maskray.me/blog/2021-02-14-all-about-thread-local-storage * https://chao-tic.github.io/blog/2018/12/25/tls * DeviceTree * https://www.devicetree.org/

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully