tag:blogger.com,1999:blog-63462002456006773552024-03-10T11:45:53.027+09:00Linux Kernel HacksLINUX KERNEL HACKS BY Slowboot~
이 블로그는 다양한 Embedded Board(ARM, MIPS, X86) 환경에서 Bootloader, Linux Kernel & Device Driver, Build system(Yocto, Buildroot, OpenWrt 등)을 심층 분석하고, 이를 공유할 목적으로 만들어졌다. 궁금한 사항이 있다면, 언제든 메모를 남겨주시기 바란다. Thanks to Linus Torvalds & All Linux Kernel Gurus !Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.comBlogger65125tag:blogger.com,1999:blog-6346200245600677355.post-70502415658203787232024-01-20T18:50:00.019+09:002024-02-17T17:05:09.605+09:00DPDK와 FD.io VPP로 고성능 Security Gateway 만들기(두번째 시간)<p><span style="font-family: Nunito;">이번 posting에서는 <a href="https://slowbootkernelhacks.blogspot.com/2020/10/dpdk-fdio-vpp-security-gateway.html">지난 시간</a>에 이어 open source project인</span><span style="background-color: #fff2cc;"><span style="font-family: Nunito;"> </span><b><a href="https://www.dpdk.org/" style="font-family: Nunito;">DPDK</a><span style="font-family: Nunito;">와 </span><a href="https://fd.io/" style="font-family: Nunito;">FD.io VPP(Vector Packet Processing)</a></b></span><span style="font-family: Nunito;"><b style="background-color: #fff2cc;">를 이용하여 고성능 네트워크 장비를 만드는 방법</b>을 소개해 보고자 한다. </span><span style="font-family: Nunito;">이론적인 부분 보다는 실제 예제(네트워크 구성)를 중심으로 <b>VPP</b>를 파헤쳐 보도록 하자. </span><span style="font-family: Nunito; font-size: medium;">😎</span></p><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVkKCK34zBv-LqFnBBSNjMjkR_v0d51c7NN6E2kZSeogLbdrjj6UCQ7X0_JsO3s9xuchSwGtkLVGBKxYBnnYzRV1oZY-Flk0Zd9VW_uLMba-ggtYjVLCkqGmi0w_UQGbCo4JxaZ-uu0-YGdLZAkHuNOxLyADyq3_F5KvlKPN2CVDZ3_EyPDqCu68CKYHv1/s121/dpdk_vpp.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="108" data-original-width="121" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVkKCK34zBv-LqFnBBSNjMjkR_v0d51c7NN6E2kZSeogLbdrjj6UCQ7X0_JsO3s9xuchSwGtkLVGBKxYBnnYzRV1oZY-Flk0Zd9VW_uLMba-ggtYjVLCkqGmi0w_UQGbCo4JxaZ-uu0-YGdLZAkHuNOxLyADyq3_F5KvlKPN2CVDZ3_EyPDqCu68CKYHv1/s16000/dpdk_vpp.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQI6jc2ss1s9OTXi-glmIEnbwbOQY5eXoNCcKGAEt86Gujq2E-Rey3zt5EpSwCEYbCZoXNpM_7fGkMrM8jmpVGWHNtqlCQf6kri9_fVOj6Ex9A9ChtqGKubZNoj0DAFZ2mNFZJLPG3q_2Ya-xSxtktj_Lf3xYLWgnfUhNzj1eSaYVPqvC0wk579P2nqShS/s1158/ethernet_switch_router.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="481" data-original-width="1158" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQI6jc2ss1s9OTXi-glmIEnbwbOQY5eXoNCcKGAEt86Gujq2E-Rey3zt5EpSwCEYbCZoXNpM_7fGkMrM8jmpVGWHNtqlCQf6kri9_fVOj6Ex9A9ChtqGKubZNoj0DAFZ2mNFZJLPG3q_2Ya-xSxtktj_Lf3xYLWgnfUhNzj1eSaYVPqvC0wk579P2nqShS/w200-h83/ethernet_switch_router.png" width="200" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /><span style="font-family: Nunito;"><b><span style="color: #0b5394; font-size: large;">목차</span></b><br /></span></div><div><span style="font-family: Nunito;">1. <b>VPP Reloaded~</b></span></div><div><span style="font-family: Nunito;">2. <b>Interface 설정</b></span></div><div><span style="font-family: Nunito;">3. <b>L2 Bridge</b><br />4. <span><b>L3 NAT Router </b></span></span></div><div><span style="font-family: Nunito;"><span>5. <b>VPP와 Host App 연동하기</b></span></span></div><div><span style="font-family: Nunito;"><span>6. <b><span style="color: #8e7cc3;">ACL 설정하기</span></b></span></span></div><div><span style="font-family: Nunito;">7. <b>Load Balancer</b></span></div><div><span style="font-family: Nunito;">8. <b>WireGuard</b></span></div><div><span style="font-family: Nunito;">9. <span style="color: #6fa8dc;">IPSec</span></span></div><div><span><span style="font-family: Nunito;">10. </span><span style="color: #6fa8dc; font-family: Nunito;">Snort 기반의 IPS</span></span></div><div><span style="font-family: Nunito;"><b>References</b></span><div><span style="font-family: Acme;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">Keyword: VPP(Vector Packet Processing), Intel DPDK, Router, Switch, VPN, IPS, Load Balancer</span></span></div><div><span style="font-family: Acme;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><span style="color: #ff00fe; font-family: Nunito;"><i>이번 blog의 목적은 VPP를 이용하여 네트워크 주요 기능(Bridge, Router, NAT, ACL, VPN, IPS, Load Balancer 등)을 상세하게 소개하는 것이다. Linux kernel을 사용하는 경우와 비교해 어떠한 차이가 있는지 음미해 보기 바란다.</i></span></div><div><span style="font-family: Acme;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><span><div style="font-family: "Noto Sans CJK KR";"><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">1. VPP Reloaded~</span></b></div><div><span style="font-family: Nunito;">오랫 만에 다시 VPP를 설치해 본다. </span><span style="font-family: Nunito;">VPP는 아래 그림에서 보는 것 처럼 On-premise 환경은 기본이고, NFV, Cloud 환경까지 확장성이 아주 많은 녀석(?)이다. 😁 앞으로 vpp를 활용하여 어디까지 나아갈 수 있는지 틈틈히 따져 볼 생각이다.</span></div><div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnwXgTx6oT8wVK4eFze1I67kIEfRb9bUVEy7XItQjCM61QUkMdtMMxnLaScJOmw0NingfieMDXnvb-QCQXdnizjnukOw3V_cpfljj1wReD1KZjNYNjOk-gj6fJ0pGOLU1fX100PAjEwSXnf6GpLVkM2KqXhQcClzyuwAI8AC3YsLpU1ryowuW9isBKYcGZ/s212/fdio_logo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="139" data-original-width="212" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnwXgTx6oT8wVK4eFze1I67kIEfRb9bUVEy7XItQjCM61QUkMdtMMxnLaScJOmw0NingfieMDXnvb-QCQXdnizjnukOw3V_cpfljj1wReD1KZjNYNjOk-gj6fJ0pGOLU1fX100PAjEwSXnf6GpLVkM2KqXhQcClzyuwAI8AC3YsLpU1ryowuW9isBKYcGZ/s1600/fdio_logo.png" width="212" /></a></div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiaQ8gysLc-1aDY1YLu7NTj4WibZya5WAhdhyc2GDby6RrKxrj3eCD_sLSr-f9ApsuRghcZQHtdhEZnQfjSOsWsMbOqlT89iF50BoOvVQEEc6kLcJh1xBd82dnUxQ62gVxHQmD0_CBbH3roegSWvUsFp9Z0StM_TSADuZPTpr8cWcMG_Yl4IRARwUiJQGi/s640/vpp_applications_area.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="456" data-original-width="640" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiaQ8gysLc-1aDY1YLu7NTj4WibZya5WAhdhyc2GDby6RrKxrj3eCD_sLSr-f9ApsuRghcZQHtdhEZnQfjSOsWsMbOqlT89iF50BoOvVQEEc6kLcJh1xBd82dnUxQ62gVxHQmD0_CBbH3roegSWvUsFp9Z0StM_TSADuZPTpr8cWcMG_Yl4IRARwUiJQGi/w400-h285/vpp_applications_area.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.1] VPP의 응용 분야 [출처: 참고문헌 8]</span></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><span style="font-family: Nunito;">이번 blog에서 소개하는 대부분의 내용은 아래 VPP documentation page를 토대로 하였다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://s3-docs.fd.io/vpp/24.02/">https://s3-docs.fd.io/vpp/24.02/</a></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div><span style="font-family: Nunito;">먼저 아래 2가지 방법을 이용하여 vpp를 설치해 보도록 하자. 설치 환경은 Ubuntu 22.04 LTS 이다.</span></div><div><br /></div><div><span style="font-size: medium;"><b style="color: #38761d; font-family: Nunito;">1) So</b><span style="color: #38761d; font-family: Nunito;"><b>urce code build 후 설치</b></span></span></div><div><span style="font-family: Nunito;"><div>$ <b>git clone https://gerrit.fd.io/r/vpp</b></div><div>$ <b>cd vpp</b></div><div>$ <b>make build</b></div><div>$ <b>make pkg-deb</b></div><div>$ <b>cd build-root</b></div><div><div>$ <b>ls -l *.deb</b></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 161142 Jan 2 13:13 libvppinfra-dev_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 197308 Jan 2 13:13 libvppinfra_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 26782 Jan 2 13:13 python3-vpp-api_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 95306746 Jan 2 13:13 vpp-dbg_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 1346260 Jan 2 13:13 vpp-dev_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 5756790 Jan 2 13:13 vpp-plugin-core_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 410212 Jan 2 13:13 vpp-plugin-devtools_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 5235588 Jan 2 13:13 vpp-plugin-dpdk_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 5306706 Jan 2 13:13 vpp_24.02-rc0~206-gb7e66f4a3_amd64.deb</span></div></div><div><br /></div><div>$ <b>sudo dpkg -i ./*.deb</b></div><div><i> => 설치 중 에러가 발생한다.</i></div><div>$ <b>sudo apt-get install -y libnl-route-3-dev</b></div><div>$ <b>sudo apt --fix-broken install</b></div><div><div>$ <b>dpkg -l | grep vpp</b></div><div><b> </b><i>=> 모두 9개의 vpp package가 설치되었다.</i></div><div><span style="font-size: x-small;">ii libvppinfra 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--runtime libraries</span></div><div><span style="font-size: x-small;">ii libvppinfra-dev 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--runtime libraries</span></div><div><span style="font-size: x-small;">ii python3-vpp-api 24.02-rc0~206-gb7e66f4a3 amd64 VPP Python3 API bindings</span></div><div><span style="font-size: x-small;">ii vpp 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--executables</span></div><div><span style="font-size: x-small;">ii vpp-dbg 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--debug symbols</span></div><div><span style="font-size: x-small;">ii vpp-dev 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--development support</span></div><div><span style="font-size: x-small;">ii vpp-plugin-core 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--runtime core plugins</span></div><div><span style="font-size: x-small;">ii vpp-plugin-devtools 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--runtime developer tool plugins</span></div><div><span style="font-size: x-small;">ii vpp-plugin-dpdk 24.02-rc0~206-gb7e66f4a3 amd64 Vector Packet Processing--runtime dpdk plugin</span></div></div><div><br /></div><div><br /></div><div><b style="background-color: #fff2cc;"><여기서 잠깐></b></div><div> <i>=> vpp clean build를 하려면 ...</i></div><div>------------------------------------------------------------------------</div><div>$ <b>make wipe; make build</b></div><div>or</div><div>$ <b>make rebuild</b></div><div><br /></div><div>기타 다양한 vpp make option(Makefile 내용)은 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijqapMwkRruOlSB5gpEPl1_NLR_Nnb99__r3UnJns01DxoROem051XkusuDMXPNyCSGGEafNbgCvPWy8coG0cIZKo0rYrocF6eIdAJgffDU_jNIkIw-UE9sLqXWhlVmgrwTq5uA2oMGtvZ2Orxw98aPNuJ4Z1zXksF8BrUi036bFyLOna0UX25KemRqnLT/s688/vpp_make_options.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="688" height="379" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijqapMwkRruOlSB5gpEPl1_NLR_Nnb99__r3UnJns01DxoROem051XkusuDMXPNyCSGGEafNbgCvPWy8coG0cIZKo0rYrocF6eIdAJgffDU_jNIkIw-UE9sLqXWhlVmgrwTq5uA2oMGtvZ2Orxw98aPNuJ4Z1zXksF8BrUi036bFyLOna0UX25KemRqnLT/w400-h379/vpp_make_options.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] make options</div></span></div></span></div><div><span style="color: #38761d; font-family: Nunito;"><span style="color: black;">------------------------------------------------------------------------</span></span></div><div><span style="color: #38761d; font-family: Nunito;"><span style="color: black;"><br /></span></span></div><div><span style="font-size: medium;"><b style="color: #38761d; font-family: Nunito;">2) release binary </b><span style="color: #38761d; font-family: Nunito;"><b>설치 </b></span></span></div><div><span style="font-family: Nunito;">$ <b>curl -s https://packagecloud.io/install/repositories/fdio/release/script.deb.sh | sudo bash</b></span></div><div><span style="font-family: Nunito;"><div><br /></div><div>$ <b>sudo apt-get update</b></div><div>$ <b>sudo apt-get install vpp vpp-plugin-core vpp-plugin-dpdk</b></div></span></div><div><span style="color: #3d85c6; font-family: Nunito;">$ sudo apt-get install vpp-api-python python3-vpp-api vpp-dbg vpp-dev</span></div><div><span><div style="font-family: Nunito;"><span style="color: #3d85c6;">Reading package lists... Done</span></div><div style="font-family: Nunito;"><span style="color: #3d85c6;">Building dependency tree... Done</span></div><div style="font-family: Nunito;"><span style="color: #3d85c6;">Reading state information... Done</span></div><div style="font-family: Nunito;"><span><span style="color: #3d85c6;">E: Unable to locate package vpp-api-python</span><span><span style="color: #3d85c6;"> </span><span style="color: #b45f06;"> </span><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span><span style="color: #990000;">얘에서 에러가 난다. 일단 얘는 무시하고 나머지 설치 진행하자.</span></span></span></div><div style="font-family: Nunito;"><span><br /></span></div><div style="font-family: Nunito;">$ <b>sudo apt-get install python3-vpp-api vpp-dbg vpp-dev</b></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>$ <b>sudo dpkg -l | grep vpp</b></div><div><i> => 설치된 vpp package를 확인해 본다.</i></div><div><span style="font-size: x-small;">ii libvppinfra 23.10-release amd64 Vector Packet Processing--runtime libraries</span></div><div><span style="font-size: x-small;">ii libvppinfra-dev 23.10-release amd64 Vector Packet Processing--runtime libraries</span></div><div><span style="font-size: x-small;">ii python3-vpp-api 23.10-release amd64 VPP Python3 API bindings</span></div><div><span style="font-size: x-small;">ii vpp 23.10-release amd64 Vector Packet Processing--executables</span></div><div><span style="font-size: x-small;">ii vpp-dbg 23.10-release amd64 Vector Packet Processing--debug symbols</span></div><div><span style="font-size: x-small;">ii vpp-dev 23.10-release amd64 Vector Packet Processing--development support</span></div><div><span style="font-size: x-small;">ii vpp-plugin-core 23.10-release amd64 Vector Packet Processing--runtime core plugins</span></div><div><span style="font-size: x-small;">ii vpp-plugin-dpdk 23.10-release amd64 Vector Packet Processing--runtime dpdk plugin</span></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b style="background-color: #fff2cc;"><여기서 잠깐></b></div><div style="font-family: Nunito;"><i><span style="color: #b45f06;"> => 설치한 vpp package를 삭제하고자 한다면 ...</span></i></div><div style="font-family: Nunito;"><i><br /></i></div><div style="font-family: Nunito;"><div>$ <b>sudo apt-get remove --purge "vpp*"</b></div><div>$ sudo dpkg -l | grep vpp</div><div>$ <b>sudo apt-get remove libvppinfra</b></div><div>$ sudo dpkg -l | grep vpp</div><div>$ <b>sudo apt-get remove libvppinfra-dev</b></div></div><div style="font-family: Nunito;">--------------------------------------------------------------------------------------</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">vpp 설치가 정상적으로 이루어졌으니, 다음으로 해야 할 일은<span style="background-color: #fff2cc;"> ethernet port를 DPDK용으로 binding</span>해 주는 것이다. 참고로 이번 시험에 사용된 LAN card는 Intel XL710(quad port)이다.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSQ6tDnO1qUEBud3SH70bDMnwsALP6sdsLGoyY7pi5vtPn-SRl7FWZ9foI1WHFbIvpHJ5BUL7abkHcaJdQBhpMuVslMvkzxcxQP_gUyXNV1bsjbTReVe9BkFjbJDUzdjaqxt3DZNK-b0KAUJf0xSWQW-F97834b-FSdZlnwXIBLInjC10jCEmS6kKfj_oh/s319/intel_xl710_10g_quard_sfp+.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="246" data-original-width="319" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSQ6tDnO1qUEBud3SH70bDMnwsALP6sdsLGoyY7pi5vtPn-SRl7FWZ9foI1WHFbIvpHJ5BUL7abkHcaJdQBhpMuVslMvkzxcxQP_gUyXNV1bsjbTReVe9BkFjbJDUzdjaqxt3DZNK-b0KAUJf0xSWQW-F97834b-FSdZlnwXIBLInjC10jCEmS6kKfj_oh/s1600/intel_xl710_10g_quard_sfp+.png" width="319" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.3] </span><span style="background-color: white; color: #19191a; font-family: Nunito; text-align: left;">Intel XL710-BM1 Based Ethernet Network Interface Card, 10G Quad-Port SFP+</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJfF5Xbv_d8pBSkNl_flqTxxHcbgPUHTeTC1Iz2ZS4atDFeyMCkIA-wJQ8HIy1QY6LT-351W2lViKjzdBW88GQatGQ0CZUZA-GO2lUUZUZKNH-arkCCF0TO9mwIC7-MLhyphenhyphenWNXcAup4t6fwdUM0mCPH1FxRBnvbLhA_J1hW82Ka6vGoh-bQzalTZfWzCJXx/s452/dpdk1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="452" data-original-width="245" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJfF5Xbv_d8pBSkNl_flqTxxHcbgPUHTeTC1Iz2ZS4atDFeyMCkIA-wJQ8HIy1QY6LT-351W2lViKjzdBW88GQatGQ0CZUZA-GO2lUUZUZKNH-arkCCF0TO9mwIC7-MLhyphenhyphenWNXcAup4t6fwdUM0mCPH1FxRBnvbLhA_J1hW82Ka6vGoh-bQzalTZfWzCJXx/w216-h400/dpdk1.png" width="216" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.4] DPDK 구조1 [출처 - 참고문헌 11]</span></div><div style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span><span style="color: #990000;">ASIC 이나 FPGA의 힘을 빌리지 않고도 사용자 영역의 s/w만으로 고성능을 낼 수 있는 것은 절대적으로 DPDK의 힘에 기인한다.</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div><div>$ <b>sudo apt install dpdk</b></div><div><i> => dpdk package를 설치한다.</i></div><div>$ <b>sudo /usr/bin/dpdk-devbind.py -s</b></div><div><i> => dpdk binding 상태를 확인한다.</i></div><div><span style="font-size: x-small;">Network devices using kernel driver</span></div><div><span style="font-size: x-small;">===================================</span></div><div><span style="font-size: x-small;">0000:<b><span style="color: #990000;">3b:00.0</span></b> 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f0 drv=i40e unused=vfio-pci,uio_pci_generic *Active*</span></div><div><span style="font-size: x-small;">0000:<b><span style="color: #990000;">3b:00.1</span></b> 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f1 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:<b><span style="color: #990000;">3b:00.2</span></b> 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f2 drv=i40e unused=vfio-pci,uio_pci_generic *Active*</span></div><div><span style="font-size: x-small;">0000:<b><span style="color: #990000;">3b:00.3</span></b> 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f3 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:60:00.0 'Ethernet Connection X722 for 1GbE 37d1' if=eno1 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:60:00.1 'Ethernet Connection X722 for 1GbE 37d1' if=eno2 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Baseband' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Crypto' devices detected</span></div><div><span style="font-size: x-small;">============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">DMA devices using kernel driver</span></div><div><span style="font-size: x-small;">===============================</span></div><div><span style="font-size: x-small;">0000:00:04.0 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.1 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.2 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.3 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.4 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.5 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.6 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.7 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.0 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.1 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.2 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.3 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.4 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.5 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.6 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.7 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Eventdev' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Mempool' devices detected</span></div><div><span style="font-size: x-small;">=============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Compress' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Misc (rawdev)' devices detected</span></div><div><span style="font-size: x-small;">===================================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Regex' devices detected</span></div><div><span style="font-size: x-small;">===========================</span></div></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">4개의 ethernet port에 대해 dpdk binding을 시도한다.</div><div style="font-family: Nunito;"><br /></div><div><div style="font-family: Nunito;">$ <b>sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic <span style="color: #990000;">3b:00.0</span></b></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Warning: routing table indicates that interface 0000:3b:00.0 is active. Not modifying</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic <span style="color: #990000;">3b:00.1</span></b></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Error: bind failed for 0000:3b:00.1 - Cannot bind to driver uio_pci_generic: [Errno 19] No such device</span></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Error: unbind failed for 0000:3b:00.1 - Cannot open /sys/bus/pci/drivers//unbind: [Errno 13] Permission denied: '/sys/bus/pci/drivers//unbind'</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic <span style="color: #990000;">3b:00.2</span></b></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Warning: routing table indicates that interface 0000:3b:00.2 is active. Not modifying</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>sudo /usr/bin/dpdk-devbind.py --bind uio_pci_generic <span style="color: #990000;">3b:00.3</span></b></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Error: bind failed for 0000:3b:00.3 - Cannot bind to driver uio_pci_generic: [Errno 19] No such device</span></div><div style="font-family: Nunito;"><span style="font-size: x-small;">Error: unbind failed for 0000:3b:00.3 - Cannot open /sys/bus/pci/drivers//unbind: [Errno 13] Permission denied: '/sys/bus/pci/drivers//unbind'</span></div><div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div></div></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span><span style="color: #990000;">위의 명령을 실행하기 전에 실제 동작 중인 network interface가 있다면, 먼저 down(ifconfig XXX down or ifconfig XXX 0.0.0.0) 시켜 주어야 한다.</span></span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>sudo service vpp restart</b></div><div style="font-family: Nunito;"><i> => dpdk binding 내용을 반영하기 위해 vpp를 재구동시킨다.</i></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>$ <b>sudo dpdk-devbind.py --status</b></div><div><i> => 정상적으로 binding이 이루어진 경우, 아래와 같이 DPDK-compatible driver에 내용이 출력될 것이다. 아래의 경우는 4개의 10GbE port 중 실제로 2 포트만 cable이 연결되어 있어 그렇게 출력된 것이다.</i></div><div><br /></div><div><span style="font-size: x-small;">Network devices using DPDK-compatible driver</span></div><div><span style="font-size: x-small;">============================================</span></div><div><span style="color: #990000; font-size: x-small;">0000:3b:00.1 'Ethernet Controller X710 for 10GbE SFP+ 1572' drv=vfio-pci unused=i40e,uio_pci_generic</span></div><div><span style="color: #990000; font-size: x-small;">0000:3b:00.3 'Ethernet Controller X710 for 10GbE SFP+ 1572' drv=vfio-pci unused=i40e,uio_pci_generic</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">Network devices using kernel driver</span></div><div><span style="font-size: x-small;">===================================</span></div><div><span style="font-size: x-small;">0000:3b:00.0 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f0 drv=i40e unused=vfio-pci,uio_pci_generic *Active*</span></div><div><span style="font-size: x-small;">0000:3b:00.2 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp59s0f2 drv=i40e unused=vfio-pci,uio_pci_generic *Active*</span></div><div><span style="font-size: x-small;">0000:60:00.0 'Ethernet Connection X722 for 1GbE 37d1' if=eno1 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:60:00.1 'Ethernet Connection X722 for 1GbE 37d1' if=eno2 drv=i40e unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Baseband' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Crypto' devices detected</span></div><div><span style="font-size: x-small;">============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">DMA devices using kernel driver</span></div><div><span style="font-size: x-small;">===============================</span></div><div><span style="font-size: x-small;">0000:00:04.0 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.1 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.2 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.3 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.4 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.5 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.6 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:00:04.7 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.0 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.1 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.2 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.3 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.4 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.5 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.6 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;">0000:80:04.7 'Sky Lake-E CBDMA Registers 2021' drv=ioatdma unused=vfio-pci,uio_pci_generic </span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Eventdev' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Mempool' devices detected</span></div><div><span style="font-size: x-small;">=============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Compress' devices detected</span></div><div><span style="font-size: x-small;">==============================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Misc (rawdev)' devices detected</span></div><div><span style="font-size: x-small;">===================================</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">No 'Regex' devices detected</span></div><div><span style="font-size: x-small;">===========================</span></div></div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw1h5VeEkk_11itG-j2DI-qEDR7Ga8eEBvaZr7aojYbYqshkJnyKYhuvMga9dNooUkKHI6BgvUvuKtu9sTDso2pY-nTWxHcztk3W6KY4Ygl63rvLT2v4Vbx36UbmkMBBWmzlhjO5FajwH45K1BJS7WaFzoHMyDYoTyIQVUxgLtlkCI0Ixm7aBoKXSL6ncP/s1196/vpp_dpdk_binding.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="602" data-original-width="1196" height="322" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw1h5VeEkk_11itG-j2DI-qEDR7Ga8eEBvaZr7aojYbYqshkJnyKYhuvMga9dNooUkKHI6BgvUvuKtu9sTDso2pY-nTWxHcztk3W6KY4Ygl63rvLT2v4Vbx36UbmkMBBWmzlhjO5FajwH45K1BJS7WaFzoHMyDYoTyIQVUxgLtlkCI0Ixm7aBoKXSL6ncP/w640-h322/vpp_dpdk_binding.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.5] DPDK binding 예</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">이제 vpp process 상태와 cpu 사용량을 확인해 본 후, vppctl 명령을 실행하여 cli 모드로 진입해 보자.</div><div style="font-family: Nunito;"><br /></div><div><div style="font-family: Nunito;">$ <b>ps aux|grep vpp</b></div><div style="font-family: Nunito;">root 5765 72.5 0.1 287622924 123200 ? Rsl 05:35 0:01 <b><span style="color: #990000;">/usr/bin/vpp -c /etc/vpp/startup.conf</span></b></div><div style="font-family: Nunito;">ztnabox 5832 0.0 0.0 6476 2392 pts/0 S+ 05:35 0:00 grep --color=auto vpp</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">top 명령으로 확인해 보니, cpu 사용량이 100%를 넘는다.</div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5vvg5HHf_0yXGJcbsTgauDF0StcVR3xp_Fn8EfRB3qulP0jFt4xFgvB8AY6gIGUmUTPKyI_a1GPWzI3sGLqg9zzkNH7SZDeU6QKu5EskZFLMmgQ2Rssj0fvJ5YfXQYosD8EW7kMWwyT1dsV3BgZWstrqzFC2ko5QfVB1NAjG2SAgY1g9a2nKncKWO0B2S/s889/vpp_cpu_usage.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="889" height="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5vvg5HHf_0yXGJcbsTgauDF0StcVR3xp_Fn8EfRB3qulP0jFt4xFgvB8AY6gIGUmUTPKyI_a1GPWzI3sGLqg9zzkNH7SZDeU6QKu5EskZFLMmgQ2Rssj0fvJ5YfXQYosD8EW7kMWwyT1dsV3BgZWstrqzFC2ko5QfVB1NAjG2SAgY1g9a2nKncKWO0B2S/w400-h293/vpp_cpu_usage.png" width="400" /></a></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;">[그림 1.6] vpp process의 cpu 사용량 - 100% 육박</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioL5dWxJzFpO58Udv82quJoffnUFVKkDUMtHBWXMoBqOsOANu04VcScBaRzrcPOGZdbrphDJXpwPRlZfo8a-_fB4fCCH_iL_xHYe5SBcB3HpsUnY0vySnFOe1taF6FjRTR3J19w1w3_0vFj3fH_9MHwPjPLE8to6f9Wf0a2hJcD4iQKSE6w4dYA6M8TDVr/s371/dpdk2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="332" data-original-width="371" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioL5dWxJzFpO58Udv82quJoffnUFVKkDUMtHBWXMoBqOsOANu04VcScBaRzrcPOGZdbrphDJXpwPRlZfo8a-_fB4fCCH_iL_xHYe5SBcB3HpsUnY0vySnFOe1taF6FjRTR3J19w1w3_0vFj3fH_9MHwPjPLE8to6f9Wf0a2hJcD4iQKSE6w4dYA6M8TDVr/s320/dpdk2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.7] DPDK 구조 2 [출처 - 참고문헌 11]</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>sudo vppctl</b></div><div style="font-family: Nunito;"> _______ _ _ _____ ___ </div><div style="font-family: Nunito;"> __/ __/ _ \ (_)__ | | / / _ \/ _ \</div><div style="font-family: Nunito;"> _/ _// // / / / _ \ | |/ / ___/ ___/</div><div style="font-family: Nunito;"> /_/ /____(_)_/\___/ |___/_/ /_/ </div><div style="font-family: Nunito;"><br /></div><div><div><span style="font-family: Nunito;">vpp# <b>show version </b></span></div><div><span style="font-family: Nunito;">vpp v23.10-release built by root on 4e2336ec7fb8 at 2023-10-25T14:46:06</span></div></div><div style="font-family: Nunito;"> </div><div style="font-family: Nunito;">vpp# <span><b>show int</b></span></div><div style="font-family: Nunito;"> Name Idx State MTU (L3/IP4/IP6/MPLS) Counter Count </div><div style="font-family: Nunito;">TenGigabitEthernet3b/0/1 1 down 9000/0/0/0 <span style="white-space: pre;"> </span></div><div style="font-family: Nunito;">TenGigabitEthernet3b/0/3 2 down 9000/0/0/0 </div><div style="font-family: Nunito;">local0 0 down 0/0/0/0 </div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">==================</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b style="background-color: #fcff01;"><여기서 잠깐></b></div><div style="font-family: Nunito;"> <i>=> VPP의 성능을 좀 더 끌어 올리고 싶다면 어찌해야 할까 ?</i></div><div style="font-family: Nunito;">-------------------------------------------------------------------------------------</div><div style="font-family: Nunito;">답은 간단하다. /etc/vpp/startup.conf 파일의 설정을 아래과 같이 변경해 주면 된다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b></etc/vpp/startup.conf></b></div><div style="font-family: Nunito;">...</div><div style="font-family: Nunito;"><span style="color: #0b5394;">cpu { </span></div><div style="font-family: Nunito;"><span style="color: #0b5394;"><b> main-core 1 </b></span></div><div style="font-family: Nunito;"><span style="color: #0b5394;"><b> corelist-workers 2-3,18-19 </b></span></div><div style="font-family: Nunito;"><span style="color: #0b5394;">}</span></div><div style="font-family: Nunito;">...</div><div style="font-family: Nunito;">-------------------------------------------------------------------------------------</div><div style="font-family: Nunito;">위와 같이 설정 변경을 할 경우, CPU 사용량이 100% -> 400%로 늘어난 것을 알 수 있다. 그만큼 성능 향상이 있을 수 있음을 의미한다.</div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd0vrPHLfyVxnUKhjhL8MjctfxDYxFJr0fDiKJs6KV4W38sTgvTUVMo2zrgHgOVSETsJHjuH7Yeo03bE1MaTbYTg-PyYQN1SwVcmj7_3522_JTR_Ik2lTTmgwQr863ew8jB91JujXmH7MT0MnwNxBtXwQ04JnMnmhThQuu0v3aLk7VN7NO13P6JmCXcesp/s960/vpp_cpu_workers.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="602" data-original-width="960" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd0vrPHLfyVxnUKhjhL8MjctfxDYxFJr0fDiKJs6KV4W38sTgvTUVMo2zrgHgOVSETsJHjuH7Yeo03bE1MaTbYTg-PyYQN1SwVcmj7_3522_JTR_Ik2lTTmgwQr863ew8jB91JujXmH7MT0MnwNxBtXwQ04JnMnmhThQuu0v3aLk7VN7NO13P6JmCXcesp/w400-h251/vpp_cpu_workers.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.8] vpp process의 cpu 사용량 - 400% 육박</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><span>현재 테스트 중인 서버의 CPU core 갯수는 총 32개(thread 64)이다. 그렇다면 아래와 같이 32개를 거의 대부분 vpp용으로 할당할해 주면 어떻게 될까 ? </span></div><div style="font-family: Nunito;"><span><br /></span></div><div style="font-family: Nunito;"><span><span style="color: #0b5394;">cpu { </span></span></div><div><span style="color: #0b5394; font-family: Nunito;"><b> main-core 0</b></span></div><div><span style="color: #0b5394; font-family: Nunito;"><b> corelist-workers 2-32,33-60</b></span></div><div><span style="color: #b45f06; font-family: Nunito;"><span style="color: #0b5394;">}</span></span></div><div style="font-family: Nunito;"><span style="color: #990000;"><br /></span></div><div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIyfr5pUBUCZRbbviOvHPbqzKGeqUSBVH9M4WiIfSKmAaJcLYM7lU2cexP1NnYjBdqMBcLKqDwUrvgnqz-VBie-nVbxlqNJc4dnSc02-mQ3MIYYWn27OE_6qDxaPoyBlT70CQmgDrjspxZvQrh88o4W02gqElMG1DkeHjF7RH1mDX6wk3ONvJmm2HqVdcU/s837/vpp_top_cpu_usage.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="615" data-original-width="837" height="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIyfr5pUBUCZRbbviOvHPbqzKGeqUSBVH9M4WiIfSKmAaJcLYM7lU2cexP1NnYjBdqMBcLKqDwUrvgnqz-VBie-nVbxlqNJc4dnSc02-mQ3MIYYWn27OE_6qDxaPoyBlT70CQmgDrjspxZvQrh88o4W02gqElMG1DkeHjF7RH1mDX6wk3ONvJmm2HqVdcU/w400-h294/vpp_top_cpu_usage.png" width="400" /></a></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;">[그림 1.9] vpp process의 cpu 사용량 - 1000%를 넘어감</div><div style="font-family: Nunito;"><br /></div><div><span style="font-family: Nunito;">이 상태에서 vppctl show threads 명령을 실행해 보면, 다음과 같이 vpp worker threads가 cpu core별로 할당되어 동작하고 있음을 알 수 있다.</span></div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CWiu6XRTfRGK5xXyHmaopRBJGSznvsLgGq_2oA7PTc25pkkAwUn0QdpV2o8N0XtdzS64XQcHRVLMqFfa0OQOcBfRhL2zHAZXJPWSnFu2x7VN3Niux_ue-_0MB_i5Fuqe_Ewi-tZAbYZEK0o76oMClSVzn6WA60QR1wcysBfxM6vF0ThmHHZ5svI9r4Gi/s909/vpp_show_threads.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="909" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8CWiu6XRTfRGK5xXyHmaopRBJGSznvsLgGq_2oA7PTc25pkkAwUn0QdpV2o8N0XtdzS64XQcHRVLMqFfa0OQOcBfRhL2zHAZXJPWSnFu2x7VN3Niux_ue-_0MB_i5Fuqe_Ewi-tZAbYZEK0o76oMClSVzn6WA60QR1wcysBfxM6vF0ThmHHZ5svI9r4Gi/w400-h274/vpp_show_threads.png" width="400" /></a></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;">[그림 1.10] vpp show threads</div><br /><span style="color: #990000; font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 시험을 해 보면 CPU 점유율이 1000%(심지어는 2000%)를 넘어가는 경우가 발생하는 것을 알 수 있다. 다만, 항상 1000% 대를 유지하는 것은 아니고, 500% 대로 줄었다가, CPU 다시 1000% 대로 넘어가는 것을 볼 수가 있다.</span></span></div><div style="font-family: Nunito;">-------------------------------------------------------------------------------------</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">자, 여기까지 vpp 관련 기본 설치가 모두 끝났다. 이제 부터 본격적으로 network 설정으로 들어가 보도록 하자.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div><div style="font-family: "Noto Sans CJK KR";"><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">2. Interface 설정</span></b></div><div><span style="font-family: Nunito;">VPP 설치 후, network 설정 관련하여 가장 먼저 해야 할 일은 아무래도 interface 설정이 아닐까 싶다. 설정 방법은 간단하다.</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp# <b>show interface</b></span></div><div><div><span style="font-family: Nunito; font-size: x-small;"><div> Name Idx State MTU (L3/IP4/IP6/MPLS) Counter Count </div><div>TenGigabitEthernet3b/0/0 1 down 9000/0/0/0 <span style="white-space: pre;"> </span></div><div>TenGigabitEthernet3b/0/2 2 down 9000/0/0/0 </div><div>local0 0 down 0/0/0/0 </div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp# <b>set interface state TenGigabitEthernet3b/0/0 up</b></span></div><div><span style="font-family: Nunito;"><i> => Interface를 up 시킨다.</i></span></div><div><span style="font-family: Nunito;">vpp# <b>set int ip address TenGigabitEthernet3b/0/0 192.168.10.1/24</b></span></div><div><span style="font-family: Nunito;"><i> => Interface에 ip 주소를 부여한다.</i></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">vpp#<b> set interface state TenGigabitEthernet3b/0/2 up</b></span></div><div><span style="font-family: Nunito;">vpp# <b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24</b></span></div></div><div><span style="font-family: Nunito;"><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWapXcEsj4n51V7RVdKIDlFsn9wrPQ5-LiBRPrld-lnsU66NZvWyp5rRxIo4Bv8mkjEXlkgKkFQZnVPCzYGouHt9Lu-4Zi9eVJFpl4G3mY2D9kad_WZ-2giOB0lUCo0vFwDtFBJUJa6C6qqtA67xLajk37_8mLyHaewMA6c5RLX_SwBGV-32kAsN69Uwr7/s710/vpp_interface_configuration.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="523" data-original-width="710" height="295" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWapXcEsj4n51V7RVdKIDlFsn9wrPQ5-LiBRPrld-lnsU66NZvWyp5rRxIo4Bv8mkjEXlkgKkFQZnVPCzYGouHt9Lu-4Zi9eVJFpl4G3mY2D9kad_WZ-2giOB0lUCo0vFwDtFBJUJa6C6qqtA67xLajk37_8mLyHaewMA6c5RLX_SwBGV-32kAsN69Uwr7/w400-h295/vpp_interface_configuration.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.1] vpp interface 설정 예 - interface 상태 확인</span></div><div><span style="font-family: Nunito; text-align: left;"><br /></span></div><div><span style="font-family: Nunito; text-align: left;">vpp# <b>set interface address</b></span></div></div></div><i> => interface에 할당된 ip 주소를 확인한다.</i></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWoxPv_wWbwcK4s4KEt3_K_JcVzme9O1iFYsMRzQCyQWb1NTwDlvaLIHaNFsr0tVeOZV8NyAjo2rpGaRJRLh7ufPoS_qpBaQQ1el8-g5ZE8FA3zzgcj1cHUIq7b_7GQdFlgO5dziplD5DRr4ZdReAJ58z-uVFf-FWLo4aTz3pewETN1uuKOlZ8-XhGD3LL/s626/vpp_int_addr.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="626" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWoxPv_wWbwcK4s4KEt3_K_JcVzme9O1iFYsMRzQCyQWb1NTwDlvaLIHaNFsr0tVeOZV8NyAjo2rpGaRJRLh7ufPoS_qpBaQQ1el8-g5ZE8FA3zzgcj1cHUIq7b_7GQdFlgO5dziplD5DRr4ZdReAJ58z-uVFf-FWLo4aTz3pewETN1uuKOlZ8-XhGD3LL/w400-h328/vpp_int_addr.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.2] show int addr 명령 실행 예 - interface 별 ip 할당 상태 확인</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">다음으로 소개할 내용은 bonding에 관한 것이다. 다행히도 현재 Quad ethernet NIC(그림 1.2)을 사용하고 있는 관계로 LAN 및 WAN 용으로 각각 2개의 port를 할당하고, 2개를 하나로 묶는 bonding 설정을 해 볼 수 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>create bond ?</b></div><div> create bond create bond mode {round-robin | active-backup | broadcast | {lacp | xor} [load-balance { l2 | l23 | l34 } [numa-only]]} [hw-addr <mac-address>] [id <if-id>] [gso]</div><div><br /></div><div>vpp# <b>create bond mode active-backup</b></div><div><i> => active/backup 형태로 bonding 설정을 한다.</i></div><div><span style="color: #ffa400;">BondEthernet0</span></div><div>vpp# <b>bond add BondEthernet0 TenGigabitEthernet3b/0/0</b></div><div>vpp# <b>bond add BondEthernet0 TenGigabitEthernet3b/0/1</b></div><div>vpp# <b>set interface state BondEthernet0 up</b></div><div><br /></div><div><div>vpp# <b>create bond mode active-backup</b></div><div><span style="color: #ffa400;">BondEthernet1</span></div><div>vpp# <b>bond add BondEthernet1 TenGigabitEthernet3b/0/2</b></div><div>vpp# <b>bond add BondEthernet1 TenGigabitEthernet3b/0/3</b></div><div>vpp# <b>set interface state BondEthernet1 up</b></div></div><div><br /></div><div>vpp# <b>show bond </b></div></span></div></span></div><div><span style="font-family: Nunito;"><div>interface name sw_if_index mode load balance active members members</div><div>BondEthernet0 5 active-backup active-backup 1 2</div><div>BondEthernet1 6 active-backup active-backup 1 2</div><div><br /></div><div>vpp# <b>show interfaces</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtprH6T2tC7AS7AubvC-vFbXzfxQMakadtBk2w2PSzJkYY19cm1XPO4olEWBslSsISXBQQ4yh2unJ-Twal9FBUG1eK72a7QKJJEHImqMB7_2N321E_WO1Gz6VGgOcVrcpJTtiht4Ms2IwsUowAoXXqQmkf0-KNqrCIAKfqTKFzsN9ui8jJU_vVxSN8v-_5/s919/vpp_show_int.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="816" data-original-width="919" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtprH6T2tC7AS7AubvC-vFbXzfxQMakadtBk2w2PSzJkYY19cm1XPO4olEWBslSsISXBQQ4yh2unJ-Twal9FBUG1eK72a7QKJJEHImqMB7_2N321E_WO1Gz6VGgOcVrcpJTtiht4Ms2IwsUowAoXXqQmkf0-KNqrCIAKfqTKFzsN9ui8jJU_vVxSN8v-_5/w400-h355/vpp_show_int.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.3] vpp interface 설정 예 - bonding interface 추가 </span></div><div><br /></div><div><br /></div><div><div>vpp# <b>show int addr</b></div><div><span style="color: #ffa400;">BondEthernet0 (up)</span>:</div><div> L2 bridge bd-id 1 idx 1 shg 0 </div><div><span style="color: #ffa400;">BondEthernet1 (up):</span></div><div> L3 192.168.3.33/24</div><div>TenGigabitEthernet3b/0/0 (up):</div><div>TenGigabitEthernet3b/0/1 (dn):</div><div>TenGigabitEthernet3b/0/2 (up):</div><div>TenGigabitEthernet3b/0/3 (dn):</div><div>bvi0 (up):</div><div> L2 bridge bd-id 1 idx 1 shg 0 bvi</div><div> L3 192.168.10.1/24</div><div>local0 (dn):</div><div>vpp# </div></div><div><br /></div><div><div>vpp# <b>ping 192.168.3.254</b></div><div><i> => wan에 존재하는 다른 장치(192.168.3.254)로 ping을 해 본다.</i></div><div>116 bytes from 192.168.3.254: icmp_seq=1 ttl=64 time=.1512 ms</div><div>116 bytes from 192.168.3.254: icmp_seq=2 ttl=64 time=.1249 ms</div><div>116 bytes from 192.168.3.254: icmp_seq=3 ttl=64 time=.1393 ms</div><div>116 bytes from 192.168.3.254: icmp_seq=4 ttl=64 time=.1115 ms</div><div>116 bytes from 192.168.3.254: icmp_seq=5 ttl=64 time=.1246 ms</div><div><br /></div><div>Statistics: 5 sent, 5 received, 0% packet loss</div></div><div><br /></div></span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">3. L2 Bridge</span></b></div><div><span style="font-family: Nunito;">Layer 2 bridging과 Layer 3 routing은 네트워크의 기본에 해당하는 내용이다. 먼저 이 번 장에서는 Layer 2 bridge 설정 기능을 소개해 보도록 하자.</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_kPxjYAnBE6c10tgcoVMr8fsXMxQQkKIQNZ_0VT67YmyULzFdTilxt2IlOB07z2gpxeSFOekNZr73aDSgRNuIBN61hiwF0Lco3YviZSGkfYuLz2PquSZ0wjuxJr8DihRs6nY5-6ITDG5hdOpHU7Q7HT4BX9PRAtFFN-E2IyhyphenhyphenpTl7P2bqK73PuMMsS4tS/s662/vpp_l2_network2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="415" data-original-width="662" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_kPxjYAnBE6c10tgcoVMr8fsXMxQQkKIQNZ_0VT67YmyULzFdTilxt2IlOB07z2gpxeSFOekNZr73aDSgRNuIBN61hiwF0Lco3YviZSGkfYuLz2PquSZ0wjuxJr8DihRs6nY5-6ITDG5hdOpHU7Q7HT4BX9PRAtFFN-E2IyhyphenhyphenpTl7P2bqK73PuMMsS4tS/w400-h251/vpp_l2_network2.png" width="400" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: Nunito;"><div><div style="text-align: center;"> +------------------+</div><div style="text-align: center;"> | 192.168.10.0/24 |</div><div style="text-align: center;"> +------------------+</div><div style="text-align: center;"> |</div><div style="text-align: center;">+----------------------------+</div><div style="text-align: center;">| TenGigabitEthernet3b/0/0 |</div><div style="text-align: center;">+----------------------------+</div><div style="text-align: center;">+----------------------------+</div><div style="text-align: center;">| TenGigabitEthernet3b/0/2 |</div><div style="text-align: center;">+----------------------------+</div><div style="text-align: center;"> |</div><div style="text-align: center;"> +------------------+</div><div style="text-align: center;"> | 192.168.10.0/24 |</div><div style="text-align: center;"> +------------------+</div></div><div style="text-align: center;"><br style="font-family: "Noto Sans CJK KR";" /></div><div style="text-align: center;"><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.1] L2 Bridge 네트워크 구성</span></div><div><span style="font-family: Nunito; text-align: left;"><br /></span></div></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;"><div style="font-family: Nunito; font-size: 14.85px;">vpp# <b>set interface state GigabitEthernet3/0/0 up</b></div><div style="font-family: Nunito; font-size: 14.85px;">vpp# <b>set interface state GigabitEthernet2/0/0 up</b></div><div style="font-family: Nunito; font-size: 14.85px;"><i> => WAN, LAN interface를 up 시킨다.</i></div><div style="font-family: Nunito; font-size: 14.85px;">vpp# <b>create bridge-domain 1</b></div><div style="font-family: Nunito; font-size: 14.85px;"><i> => l2 bridge domain(1번 domain)을 하나 생성한다.</i></div><div style="font-family: Nunito; font-size: 14.85px;">vpp# <b>set interface l2 bridge GigabitEthernet3/0/0 1</b></div><div style="font-family: Nunito; font-size: 14.85px;">vpp# <b>set interface l2 bridge GigabitEthernet2/0/0 1</b></div><div style="font-family: Nunito; font-size: 14.85px;"><i> => l2 bridge domain 1에 WAN, LAN interface를 포함시킨다.</i></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>show l2fib bd_id 1 </b> </div><div><i> => 1번 bridge domain에 대한 l2 fib(forwarding information base) table(흔히 mac table이라고 부름)내용을 확인한다. 주의: 실제로는 <span style="background-color: white; color: #333333; font-size: 14.85px;">GigabitEthernet3/0/0, </span><span style="background-color: white; color: #333333; font-size: 14.85px;">GigabitEthernet2/0/0 정보가 보여야 하나, 나중에 정리하다 보니, 다른 내용이 보인다. 그냥 무시하기 바란다.</span></i></div><div><span style="font-size: x-small;">Mac-Address BD-Idx If-Idx BSN-ISN Age(min) static filter bvi Interface-Name </span></div><div><span style="font-size: x-small;"> 50:7c:6f:3a:a8:60 1 1 0/1 - - - - TenGigabitEthernet3b/0/0 </span></div><div><span style="font-size: x-small;"> 24:5e:be:80:bc:6d 1 1 0/1 - - - - TenGigabitEthernet3b/0/0 </span></div><div><span style="font-size: x-small;"> 02:fe:af:c2:00:0b 1 6 0/1 - - - - tap0 <span style="color: #bf9000;">#나중에 추가한 내용이라 이런게 들어가 있음. 무시하세요.</span></span></div><div><span style="font-size: x-small;"> b0:b0:00:00:00:00 1 5 0/0 no * - * bvi0 </span></div><div><span style="font-size: x-small;"> dc:a6:32:7f:6d:08 1 1 0/1 - - - - TenGigabitEthernet3b/0/0 </span></div><div><span style="font-size: x-small;"> 94:83:c4:0c:01:9a 1 1 0/1 - - - - TenGigabitEthernet3b/0/0 </span></div><div><span style="font-size: x-small;">L2FIB total/learned entries: 15/12 Last scan time: 0.0000e0sec Learn limit: 16777216 </span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div><b><span style="color: #38761d;"><Windows PC></span></b></div><div>C:\> ping 8.8.8.8</div><div><i> => 내부 PC에서 internet으로 ping을 시도해 본다.</i></div><div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=30.5226 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=30.4559 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=30.4174 ms</div></div><div><br /></div><div><span><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span><span style="color: #990000;"><span style="background-color: white; font-size: 14.85px;"> </span>l2 bridge 관련해서는 사실 이것 보다 훨씬 복잡한 내용이 포함되어 있으나, 일단 여기에서는 이정도 선에서 pass하기로 한다. 추가로 필요한 사항은 나중에 좀 더 살펴 보기로 하자.</span></span></div><div><br /></div><div style="text-align: center;"><a href="https://s3-docs.fd.io/vpp/24.02/cli-reference/clis/clicmd_src_vnet_l2.html">https://s3-docs.fd.io/vpp/24.02/cli-reference/clis/clicmd_src_vnet_l2.html</a></div><div><br /></div><div><br /></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">4. L3 NAT Router </span></b></div><div><span style="font-family: Nunito;">이 장에서는 L3 router 설정 기능(기본 NAT 설정 포함)을 소개할 차례이다.</span></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEAGOqQUS6rjUFUA7Su_PLx-pTY2hQD2F3vSx4wlWFEjrU9j-ybTaLttJ9oOzMQlym7kWDiKDnuMC6nUqOdFxTqqqa7WwC2Wi-gHaioeujjUOYeoEIqRkwVgwchbstRZFmaTO0aMpXt0JaM1plPe-Je8rO2vNSL3T-nFrXBI9k7xCXtdaVK7uGQrkswSvU/s735/vpp_l3_network.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="471" data-original-width="735" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEAGOqQUS6rjUFUA7Su_PLx-pTY2hQD2F3vSx4wlWFEjrU9j-ybTaLttJ9oOzMQlym7kWDiKDnuMC6nUqOdFxTqqqa7WwC2Wi-gHaioeujjUOYeoEIqRkwVgwchbstRZFmaTO0aMpXt0JaM1plPe-Je8rO2vNSL3T-nFrXBI9k7xCXtdaVK7uGQrkswSvU/w400-h256/vpp_l3_network.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><div style="text-align: center;"><div><div> +----------------------+</div><div> | 192.168.10.0/24 |</div><div> +----------------------+</div><div> |</div><div>+------------------------------------+</div><div>| TenGigabitEthernet3b/0/0 |</div><div>+------------------------------------+</div><div>+------------------------------------+</div><div>| TenGigabitEthernet3b/0/2 |</div><div>+------------------------------------+</div><div> |</div><div> +--------------------+</div><div> | 192.168.3.0/24 |</div><div> +--------------------+</div></div><div><br /></div><div><span style="font-family: Nunito; text-align: left;">[그림 4.1] L3 Router 네트워크 구성</span></div></div></div><div><br /></div><div><span style="font-family: Nunito;"><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>bvi create instance 0</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge bvi0 1 bvi</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int ip address bvi0 192.168.10.1/24</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state bvi0 up</b></div><div><i> => bridge virtual interface를 하나 만들고, bridge domain 1에 포함시킨다. 이어 ip 주소를 할당한다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge TenGigabitEthernet3b/0/0 1</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state TenGigabitEthernet3b/0/0 up</b></div><div><i> => 물리 LAN port(TenGigabitEthernet3b/0/0)를 bridge domain 1에 포함시킨다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface state TenGigabitEthernet3b/0/2 up</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24</b></div><div><i> => WAN port(TenGigabitEthernet3b/0/2)를 up시키고, ip를 할당한다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>ip route add 0.0.0.0/0 via 192.168.3.254 TenGigabitEthernet3b/0/2</b></div><div><i> => default gateway를 추가한다.</i></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span><span style="color: #990000;"><span style="background-color: white; font-size: 14.85px;"> </span>routing table은 show ip fib 명령으로 확인 가능하다.</span></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 forwarding enable</b></div><div><i> => nat44 forwardng을 enable 시킨다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 plugin enable sessions 10000</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface nat44 in bvi0 out TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"> => bvi0를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 add interface address TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"> => NAT44 interface로 WAN port를 등록한다.</i></div><div><br /></div><div><div><b><span style="color: #38761d;"><Windows PC></span></b></div><div>C:\> ping 8.8.8.8</div><div><i> => 내부 PC에서 internet으로 ping을 시도해 본다.</i></div></div><div><br /></div></span></div><div><br /></div><div><b><span style="color: #ff00fe; font-family: Nunito;"><여기서 잠깐 - Port Forwarding 설정하기></span></b></div><div><span style="font-family: Nunito;">==================================</span></div><div><span style="font-family: Nunito;">nat44를 이용하여 port forwarding 설정을 하려면 어떻게 해야 할까 ? 답은 간단하다. 아래와 같이 nat44 static mapping 기능을 이용하면 된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">vpp# <b>nat44 add static mapping tcp local 192.168.10.200 22 external 192.168.3.33 22</b></span></div><div><span style="font-family: Nunito;"> <i>=> 외부 PC --> 192.168.3.33:22 -> 192.168.10.200:22</i></span></div><div><span style="font-family: Nunito;">vpp# <b>nat44 add static mapping tcp local 192.168.10.100 22 external 192.168.3.33 2022</b></span></div></div><div><span style="font-family: Nunito;"> => </span><i style="font-family: Nunito;">외부 PC --> 192.168.3.33:2022 -> 192.168.10.100:22</i></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span><span style="color: #990000;"><span style="background-color: white; font-size: 14.85px;"> </span>주의: 보통의 경우는 external ip가 먼저 오고, internal(local) ip 설정이 뒤에 오는게 일반적인데, vpp의 경우는 그렇지 못하다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #990000;"><br /></span></span></div><div><span style="font-family: Nunito;"><b><외부 PC></b></span></div><div><span style="font-family: Nunito;"><div>$ <b>ssh pi@192.168.3.33</b></div><div>pi@192.168.3.33's password: </div><div>Linux raspberrypi 5.15.84-v7l+ #1613 SMP Thu Jan 5 12:01:26 GMT 2023 armv7l</div></span></div><div><span style="font-family: Nunito;">...</span></div><div><span style="font-family: Nunito;">==================================</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">이 밖에도 vpp에는 아주 다양한(모든) NAT 기능이 포함되어 있다. 궁금한 사항은 아래 page를 참고하기 바란다.</span></div><div style="text-align: center;"><span style="background-color: white; font-size: 14.85px;"><span style="font-family: Nunito;"><a href="https://wiki.fd.io/view/VPP/NAT">https://wiki.fd.io/view/VPP/NAT</a></span></span></div><div><span style="background-color: white; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div><span style="background-color: white; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">5. VPP와 Host App 연동하기</span></b></div><div><span style="font-family: Nunito;">이 장에서 소개할 내용은 Host(Linux) 상의 application을 VPP를 통해 연결하는 것에 관한 것이다. 즉, host 상에서 동작하는 ssh server나 web server를 VPP를 통해 연결하는 방법을 소개하고자 한다. </span></div></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-cvckIAxWLpKuDlhYTScRXNmZAFpLIgHpltEu2RqKCAKVhfmII3shu_MRgk_II7H4TlWKMN6pSVdpYk6AebXOdxs_Pp-hLRqH43jCk7ywkoZ-RipYfMzKXtR6rOqQ7dAzkfkQ-XaIjyBZb4_3Madc6gjzoh1GkSXSm4jn48svz82pe2UhncyVqaKyudyY/s1114/vpp_host_internal_access.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="590" data-original-width="1114" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-cvckIAxWLpKuDlhYTScRXNmZAFpLIgHpltEu2RqKCAKVhfmII3shu_MRgk_II7H4TlWKMN6pSVdpYk6AebXOdxs_Pp-hLRqH43jCk7ywkoZ-RipYfMzKXtR6rOqQ7dAzkfkQ-XaIjyBZb4_3Madc6gjzoh1GkSXSm4jn48svz82pe2UhncyVqaKyudyY/w400-h211/vpp_host_internal_access.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 5.1] Host app과 VPP 연동 (내부망에서 접근 예)</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span><span style="color: #990000;"><span style="background-color: white; font-size: 14.85px;"> </span></span></span><span style="font-family: Nunito;"><span style="color: #990000;">이 내용은 switching chip(ASIC)을 사용하는 경우, switching chip과 CPU를 연결하는 cpu trap 의 개념과 유사하다고도 볼 수 있다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #38761d; font-family: Nunito;"><b><VPP></b></span></div><div><div><span style="color: #bf9000;">comment { This is the LAN bridge interface }</span></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + }</span></div><div>vpp# <b>bvi create instance 0</b></div><div>vpp# <b>set int l2 bridge bvi0 1 bvi</b></div><div>vpp# <b>set int ip address bvi0 192.168.10.1/24</b></div><div>vpp# <b>set int state bvi0 up</b></div><div><i style="font-family: Nunito;"> => </i><i style="font-family: Nunito;">bridge virtual interface를 하나 만들고, bridge domain 1에 포함시킨다. 이어 ip 주소를 할당한다.</i></div><div><i style="font-family: Nunito;"><br /></i></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + TenGigabitEthernet3b/0/0 }</span></div><div>vpp# <b>set int l2 bridge TenGigabitEthernet3b/0/0 1</b></div><div>vpp# <b>set int state TenGigabitEthernet3b/0/0 up</b></div><div><i style="font-family: Nunito;"> => 물리 LAN port를 bridge 1에 포함시킨다.</i></div><div><i style="font-family: Nunito;"><br /></i></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + TenGigabitEthernet3b/0/0 + tap0 }</span></div><div>vpp# <b>create tap host-if-name <span style="background-color: #d9ead3;">lantap</span> host-ip4-addr 192.168.10.2/24 host-ip4-gw 192.168.10.1</b></div><div>vpp# <b>set int l2 bridge tap0 1</b></div><div>vpp# <b>set int state tap0 up</b></div><div><i style="font-family: Nunito;"> => tap0 interface를 하나 만들고 bridge 1에 포함시킨다. </i><i style="font-family: Nunito;">이때 Linux host 상에는 lantap 이라는 tap interface가 생성된다.</i></div><div><i style="font-family: Nunito;"><br /></i></div><div><span style="color: #bf9000;">comment { This is the WAN interface }</span></div><div>vpp# <b>set interface state TenGigabitEthernet3b/0/2 up</b></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24</b></div><div><i style="font-family: Nunito;"> => WAN port를 up시키고, ip를 할당한다.</i></div><div><i style="font-family: Nunito;"><br /></i></div><div><span style="color: #bf9000;">comment { Add default gateway }</span></div><div>vpp#<b> ip route add 0.0.0.0/0 via 192.168.3.254 TenGigabitEthernet3b/0/2</b></div><div><i style="font-family: Nunito;"> => default gateway를 추가한다.</i></div><div><i style="font-family: Nunito;"><br /></i></div><div><span style="color: #bf9000;">comment { Add nat44 rules }</span></div><div><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 forwarding enable</b></div><div style="font-family: Nunito;"><i> => nat44 forwarding을 enable 시킨다.</i></div><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 plugin enable sessions 10000</b></div><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface nat44 in bvi0 out TenGigabitEthernet3b/0/2</b></div><div style="font-family: Nunito;"><i style="background-color: white; color: #333333; font-size: 14.85px;"> => bvi0를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.</i></div><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 add interface address TenGigabitEthernet3b/0/2</b></div><div style="font-family: Nunito;"><i style="background-color: white; color: #333333; font-size: 14.85px;"> => NAT44 interface로 WAN port를 등록한다.</i></div></div></div><div><br /></div><div><br /></div><div><span style="color: #38761d; font-family: Nunito;"><b><Linux Host></b></span></div><div><span style="font-family: Nunito;">$ <b>ifconfig -a</b></span></div><div><span style="font-family: Nunito;">...</span></div><div><span style="font-family: Nunito;"><div><div><span style="background-color: #d9ead3;"><b>lantap</b></span>: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500</div><div> inet 192.168.10.2 netmask 255.255.255.0 broadcast 0.0.0.0</div><div> inet6 fe80::fe:97ff:fe0c:43fb prefixlen 64 scopeid 0x20<link></div><div> ether 02:fe:97:0c:43:fb txqueuelen 1000 (Ethernet)</div><div> RX packets 12 bytes 594 (594.0 B)</div><div> RX errors 0 dropped 0 overruns 0 frame 0</div><div> TX packets 18 bytes 1180 (1.1 KB)</div><div> TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0</div></div></span></div><div><span><div style="font-family: Nunito;"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><b style="color: #38761d;"><Windows PC></b></span></div><div style="font-family: Nunito;">C\> <b>ping 192.168.10.2</b></div><div style="font-family: Nunito;"><div>116 bytes from 192.168.10.2: icmp_seq=1 ttl=64 time=.1005 ms</div><div>116 bytes from 192.168.10.2: icmp_seq=2 ttl=64 time=.0934 ms</div><div>Connection to 10.30.0.100 closed.</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>C\> <b>ssh test@192.168.10.2</b></div><div><div>...</div></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>C\> <b>ping 8.8.8.8</b></div><div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=.1005 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=64 time=.0934 ms</div><div>Connection to 10.30.0.100 closed.</div></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><span style="color: #990000;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span> vpp 환경에서는 bvi0 interface 즉, 192.168.10.1로 ssh 연결을 시도할 경우, 동작하지 않는다. </span><span style="color: #990000;">이유는 vpp application 자체에는 ssh server가 포함(plugin)되어 있지 않기 때문이다. 따라서 이런 경우를 위해 tap interface가 사용되는 것이다.</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">지금까지 내부망에서 VPP host(Host 상의 application)에 접근하는 설정에 대해서 살펴 보았다. 그렇다면 만일 외부망에서 Host 상의 application에 접근하려면 어찌해야 할까 ? </div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4U_CsW_5PZgmDhmCdV_-AFLqjPRoiZR-xQppZHizwhIy6y_G3omv4a2doQKaU659y4-KtH6ms-QboMMjjPh8vwdp1wAfweQRFU9apbvJ9hANxVicecmSu3radf4VguEQe7hRFFaz89ufpq5cQ54CMchH_M3-D-swHL4jyeWw2fTpm8-XkzYNC7JqwWn4/s1144/vpp_host_external_access.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="555" data-original-width="1144" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4U_CsW_5PZgmDhmCdV_-AFLqjPRoiZR-xQppZHizwhIy6y_G3omv4a2doQKaU659y4-KtH6ms-QboMMjjPh8vwdp1wAfweQRFU9apbvJ9hANxVicecmSu3radf4VguEQe7hRFFaz89ufpq5cQ54CMchH_M3-D-swHL4jyeWw2fTpm8-XkzYNC7JqwWn4/w400-h194/vpp_host_external_access.PNG" width="400" /></a></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><span style="text-align: left;">[그림 5.2] Host app과 VPP 연동 (외부망에서 접근 예)</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>답은 동일하다. 아래 설정을 참조하기 바란다(WAN 이후 부분만 정리함).</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b style="color: #38761d;"><VPP></b></div><div style="font-family: Nunito;"><div><span style="color: #bf9000;">comment { This is the WAN interface }</span></div><div><span style="color: #bf9000;">comment { WAN bridge = bvi1 + }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>bvi create instance <span style="color: #990000;">1</span></b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge <span style="color: #38761d;">bvi1</span> <span style="color: #990000;">2 </span>bvi</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int ip address <span style="color: #38761d;">bvi1 </span>192.168.3.33/24</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state <span style="color: #38761d;">bvi1 </span>up</b></div><div><i> => </i><i>bridge virtual interface를 하나 만들고, bridge domain 2에 포함시킨다. 이어 ip 주소(wan ip 주소)를 할당한다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { WAN bridge = bvi1 + TenGigabitEthernet3b/0/2 }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge TenGigabitEthernet3b/0/2 <span style="color: #990000;">2</span></b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface state TenGigabitEthernet3b/0/2 up</b></div><div><i> => 물리 WAN port를 bridge 2에 포함시킨다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { WAN bridge = bvi1 + TenGigabitEthernet3b/0/2 + tap1 }</span></div><div><span style="color: #bf9000;">comment { create tap host-if-name wantap host-ip4-addr 192.168.3.51/24 host-ip4-gw 192.168.3.33 }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>create tap host-if-name <span style="background-color: #fcff01;">wantap </span>host-ip4-addr 192.168.3.51/24 host-ip4-gw 192.168.3.33</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge <span style="color: #38761d;">tap1</span> <span style="color: #990000;">2</span></b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state <span style="color: #38761d;">tap1</span> up</b></div></div><div style="font-family: Nunito;"><i> => tap1 interface를 하나 만들고 bridge 2에 포함시킨다. 이때 Linux host 상에는 wantap 이라는 tap interface가 생성된다.</i></div><div style="font-family: Nunito;"><i><br /></i></div><div style="font-family: Nunito;"><div><span style="color: #bf9000;">comment { Add default gateway }</span></div><div><span style="color: #bf9000;">comment { ip route add 0.0.0.0/0 via 192.168.3.254 bvi1 }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>ip route add 0.0.0.0/0 via 192.168.3.254 <span style="color: #38761d;">bvi1</span></b></div><div><i><span> => default gateway를 추가한다. 단, 이때 대표 인터페이스는 </span>TenGigabitEthernet3b/0/2가 아니라 bridge interface bvi1으로 한다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { Add nat44 rules }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 forwarding enable</b></div><div><i> => nat44 forwarding을 enable 시킨다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 plugin enable sessions 10000</b></div><div><span style="color: #bf9000;">comment { set interface nat44 in bvi0 out bvi1 }</span></div><div><span style="color: #bf9000;">comment { nat44 add interface address bvi1 }</span></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface nat44 in bvi0 out <span style="color: #38761d;">bvi1</span></b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;">=> bvi0를 input으로 하고, bvi1을 output으로 하는 NAT44 rule을 추가한다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 add interface address <span style="color: #38761d;">bvi1</span></b></div></div><div style="font-family: Nunito;"><i style="background-color: white; color: #333333; font-size: 14.85px;"> => NAT44 interface로 WAN bridge interface bvi1을 등록한다.</i></div><div style="font-family: Nunito;"><i style="background-color: white; color: #333333; font-size: 14.85px;"><br /></i></div><div style="font-family: Nunito;"><i style="background-color: white; color: #333333; font-size: 14.85px;"><br /></i></div><div style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito;"><b><Linux Host></b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">$ <b>ifconfig -a</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">...</span></div></div><div style="font-family: Nunito;"><div><b style="background-color: #fcff01;">wantap</b>: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500</div><div> inet <b>192.168.3.51</b> netmask 255.255.255.0 broadcast 0.0.0.0</div><div> inet6 fe80::fe:ddff:fe57:a101 prefixlen 64 scopeid 0x20<link></div><div> ether 02:fe:dd:57:a1:01 txqueuelen 1000 (Ethernet)</div><div> RX packets 2025 bytes 267992 (267.9 KB)</div><div> RX errors 0 dropped 51 overruns 0 frame 0</div><div> TX packets 1691 bytes 158942 (158.9 KB)</div><div> TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div><span style="font-family: Nunito;"><b style="color: #38761d;"><Windows PC></b></span></div><div>C\> <b>ping 192.168.3.51</b></div><div>PING 192.168.3.51 (192.168.3.51): 56 data bytes</div><div>64 bytes from 192.168.3.51: seq=0 ttl=64 time=0.258 ms</div><div>64 bytes from 192.168.3.51: seq=1 ttl=64 time=0.169 ms</div><div>64 bytes from 192.168.3.51: seq=2 ttl=64 time=0.239 ms</div><div>^C</div><div>--- 192.168.3.51 ping statistics ---</div><div>3 packets transmitted, 3 packets received, 0% packet loss</div><div>round-trip min/avg/max = 0.169/0.222/0.258 ms</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">만일, 외부망의 Windows PC에서 wantap interface로 들어오는 packet을 차단하고 싶다면, 어찌해야 할까 ? 이 부분은 6장의 주제이기도 한데, 여기에서는 tap interface가 kernel에서 생성되는 것이니 만큼, 특별히 iptables를 활용하면 된다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b style="color: #38761d;"><Linux Host></b></div><div style="font-family: Nunito;">$ s<b>udo iptables -I INPUT -p icmp -s 0.0.0.0/0 -d 192.168.3.51/32 -j DROP</b></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">-------------------------------------------------------------------------------------------</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div><b><span style="background-color: #fcff01;"><여기서 잠깐></span></b></div><div>---------------</div><div>vpp와 host application을 연결하는 방법으로 tap interface만 있는 것은 아니다. <b>veth(tap interface와 비교해 최근에 등장한 개념)를 이용한 방법</b>과 shared memory를 기반으로 하는 packet interface인 <b>memif interface를 이용하는 방법</b>도 있다.</div><div>먼저 veth interface를 이용한 방법은 tap interface를 이용한 방법과 개념적으로 유사하다고 볼 수 있다. 자세한 사용 방법은 아래 page에서 확인할 수 있다.</div><div><br /></div><div style="text-align: center;"><a href="https://s3-docs.fd.io/vpp/24.02/gettingstarted/progressivevpp/interface.html">https://s3-docs.fd.io/vpp/24.02/gettingstarted/progressivevpp/interface.html</a></div><div><br /></div><div>한편, memif interface 방법(vpp 간의 통신시에도 사용)은 shared library를 사용하는 만큼 속도가 빠른게 특징인데, host application은 vpp와 통신하기 위해 master 혹은 slave mode로 동작하게 된다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCF-6hAVOGsFEKWZ-NP8xXToqgtcUwOf-Nmvp0Tw81V1uGKTYwz_u8BS_xBCqFV2DkxwKJU5jZ79ieykNqQqbUANvbc4llZ8xGi7gXbBA3_Y9hgdXlEHXs5HRlGm5ECwpFKlK_swPDSUelq2VmU8ZtlSVeV-kRWHwxy8Y_vETkAf7i3H0WHHG7q-gxfGnc/s875/vpp_libmemif_architecture.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="302" data-original-width="875" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCF-6hAVOGsFEKWZ-NP8xXToqgtcUwOf-Nmvp0Tw81V1uGKTYwz_u8BS_xBCqFV2DkxwKJU5jZ79ieykNqQqbUANvbc4llZ8xGi7gXbBA3_Y9hgdXlEHXs5HRlGm5ECwpFKlK_swPDSUelq2VmU8ZtlSVeV-kRWHwxy8Y_vETkAf7i3H0WHHG7q-gxfGnc/w400-h138/vpp_libmemif_architecture.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.3] VPP memif library</span></div><div><br /></div><div>-------------------------------------------------------------------------------------------</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">마지막으로, tap interface를 이용해 vpp와 host app을 연동하는 것과 관련하여, 아주 심오한(?) 그림(VPP 기반의 router 구현)이 하나 있어, 여기에 옮겨 본다. 이렇게 구성하면 vpp 기반의 고성능 router(BIRD project 사용)를 만들 수도 있다.😛</div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwS8EueJIxpg7E3XwF7cVqNSX8AyAo945njzcfwld1wryWNZjvhIjF09JsNxN53yHfdLTmB7Z-W8P50htYVTWCucQvgNUqNQKB3cBoHaQ2d-aThlhhqZBsIKxWLDA-Q-LTuRfEF-QgauphBfAOniGaz7P2ph14_yepeyL6vlFgjh2d3S_EXzwn6ksEzwCS/s698/vpp_router.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="515" data-original-width="698" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwS8EueJIxpg7E3XwF7cVqNSX8AyAo945njzcfwld1wryWNZjvhIjF09JsNxN53yHfdLTmB7Z-W8P50htYVTWCucQvgNUqNQKB3cBoHaQ2d-aThlhhqZBsIKxWLDA-Q-LTuRfEF-QgauphBfAOniGaz7P2ph14_yepeyL6vlFgjh2d3S_EXzwn6ksEzwCS/s320/vpp_router.png" width="320" /></a></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><span style="text-align: left;">[그림 5.4] VPP 기반 router [출처 - 참고문헌 4]</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">6. ACL 설정하기</span></b></div><div><span style="font-family: Nunito;">이 장에서는 ACL 즉, Access Control List(일명 packet filter)을 통해 패킷을 차단/허용하는 예제를 소개해 보고자 한다. 편의상 네트워크 구성은 4장의 그것(L3 NAT router)과 동일하게 가져가도록 하자.</span></div></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLZ2-OeUwtup5a7KkciOK-ZsMO7Sy2pPwGn3VdzZWLzLo3_vuKZgkzsThcp_HS8X4JQtsZqijAzmjz3RqNWo3sIdfrXn2-olDgLhki4hohCFQwwiMRwJdZbYKy8XvZWXqr2w-gYURr-RKQtjVFFHYnYaBGnQrUn-nMs3TS98uqQ2tcrp5bsQS8n7GIS0q5/s982/vpp_acl_network.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="763" data-original-width="982" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLZ2-OeUwtup5a7KkciOK-ZsMO7Sy2pPwGn3VdzZWLzLo3_vuKZgkzsThcp_HS8X4JQtsZqijAzmjz3RqNWo3sIdfrXn2-olDgLhki4hohCFQwwiMRwJdZbYKy8XvZWXqr2w-gYURr-RKQtjVFFHYnYaBGnQrUn-nMs3TS98uqQ2tcrp5bsQS8n7GIS0q5/w400-h311/vpp_acl_network.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 6.1] ACL Test 구성도</span></div></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><div><span style="color: #38761d; font-family: Nunito;"><b><VPP></b></span></div><div><div><span style="color: #bf9000;">comment { This is the LAN bridge interface }</span></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + }</span></div><div>vpp# <b>bvi create instance 0</b></div><div>vpp# <b>set int l2 bridge bvi0 1 bvi</b></div><div>vpp# <b>set int ip address bvi0 192.168.10.1/24</b></div><div>vpp# <b>set int state bvi0 up</b></div><div><i> => </i><i>bridge virtual interface를 하나 만들고, bridge domain 1에 포함시킨다. 이어 ip 주소를 할당한다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + TenGigabitEthernet3b/0/0 }</span></div><div>vpp# <b>set int l2 bridge TenGigabitEthernet3b/0/0 1</b></div><div>vpp# <b>set int state TenGigabitEthernet3b/0/0 up</b></div><div><i> => 물리 LAN port를 bridge 1에 포함시킨다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { LAN bridge = bvi0 + TenGigabitEthernet3b/0/0 + tap0 }</span></div><div>vpp# <b>create tap host-if-name lantap host-ip4-addr 192.168.10.2/24 host-ip4-gw 192.168.10.1</b></div><div>vpp# <b>set int l2 bridge tap0 1</b></div><div>vpp# <b>set int state tap0 up</b></div><div><i> => tap0 interface를 하나 만들고 bridge 1에 포함시킨다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { This is the WAN interface }</span></div><div>vpp# <b>set interface state TenGigabitEthernet3b/0/2 up</b></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24</b></div><div><i> => WAN port를 up시키고, ip를 할당한다.</i></div><div><br /></div><div><div><span style="color: #bf9000;">comment { Add default gateway }</span></div><div>vpp#<b> ip route add 0.0.0.0/0 via 192.168.3.254 TenGigabitEthernet3b/0/2</b></div><div><i> => default gateway를 추가한다.</i></div><div><i><br /></i></div><div><span style="color: #bf9000;">comment { Add nat44 rules }</span></div><div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 forwarding enable</b></div><div><i> => nat44 forwardng을 enable 시킨다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 plugin enable sessions 65535</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface nat44 in bvi0 out TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"> => bvi0를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.</i></div></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 add interface address TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"><i style="font-size: 14.85px;"> => N</i>AT44 interface로 WAN port를 등록한다.</i></div></div></div><div><br style="font-family: "Noto Sans CJK KR";" /></div><div><br /></div></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">ACL 설정 명령 syntax는 다음과 같다.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito;">set acl-plugin acl [index <idx>] <permit|deny|permit+reflect> src <PREFIX> dst <PREFIX> [proto X] [sport X[-Y]] [dport X[-Y]] [tcpflags <int> mask <int>] [tag FOO] {use comma separated list for multiple rules}</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito;">set acl-plugin interface <interface> <input|output> <acl INDEX> [del]</span></div></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: Nunito;">먼저, 아래와 같이 하여 ssh(tcp(6), 목적지 port 22) 서버로 향하는 패킷을 허용해 보도록 하자.</div><div><span><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set acl-plugin acl permit+reflect src 192.168.10.77/32 dst 192.168.10.2/32 proto 6 sport 0-65535 dport 22</b></div><div style="font-family: Nunito;"><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set acl-plugin interface bvi0 input acl 0</b></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">이번에는 permit+reflect 대신에 deny를 주어 해당 패킷을 차단해 보도록 하자.</div><div style="font-family: Nunito;"><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set acl-plugin acl deny src 192.168.10.77/32 dst 192.168.10.2/32 proto 6 sport 0-65535 dport 22</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set acl-plugin interface bvi0 input acl 0</b></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><span style="background-color: #d0e0e3;">... 여러 차례 반복 시험 ...</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><span style="background-color: white;">근데, 뭔가 좀 이상하다. 생각 처럼 제어가 안되는 느낌이다. 아래 내용은 이후 이것 저것 시험해 본 것인데, acl 적용 순서는 제대로 먹히는 듯 한데, 앞서 설정해 본 것과 같이 protocol 제어가 안되는 것 같고, tcp/udp port 제어도 안된다. 왜 일까 ?</span> 😈</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">-----------------------------------------------------------------------------------</div><div style="font-family: Nunito;"><div>vpp# <b>set acl-plugin acl deny src 0.0.0.0/0 dst 0.0.0.0/0 tag BBB</b></div><div>ACL index:0</div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 0</b></div><div>vpp# <b>show acl-plugin acl </b></div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>vpp# <b>ping 8.8.8.8</b></div><div><br /></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div><div><i><span style="color: #ffa400;">=> ping이 안된다. 이건 OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin acl permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 tag AAA</b></div><div>ACL index:1</div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 1 </b> </div><div>vpp# </div><div>vpp# </div><div>vpp# <b>show acl-plugin acl </b> </div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 1 count 1 tag {AAA}</div><div> 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>vpp# </div><div>vpp# </div><div>vpp# </div><div>vpp# <b>ping 8.8.8.8 </b> </div><div><br /></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div><div><i><span style="color: #ffa400;">=> permit+reflect rule을 추가했으나, acl 0에서 deny하고 있으니, ping이 안되는 것은 맞다. 이건 OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 0 del</b></div><div>vpp# <b>ping 8.8.8.8 </b> </div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=30.5226 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=30.4559 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=30.4174 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=4 ttl=116 time=30.3815 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=5 ttl=116 time=30.3922 ms</div><div><br /></div><div>Statistics: 5 sent, 5 received, 0% packet loss</div><div><i><span style="color: #ffa400;">=> acl 0은 지웠으니, ping이 되는 것도 정상 OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin acl deny src 0.0.0.0/0 dst 0.0.0.0/0 tag CCC</b></div><div>ACL index:2</div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 2</b></div><div>vpp# <b>show acl-plugin acl </b></div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: </div><div> used in lookup context index: </div><div>acl-index 1 count 1 tag {AAA}</div><div> 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 2 count 1 tag {CCC}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>vpp#<b> ping 8.8.8.8</b></div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=30.5507 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=30.4598 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=30.3940 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=4 ttl=116 time=30.3909 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=5 ttl=116 time=30.3897 ms</div><div><br /></div><div>Statistics: 5 sent, 5 received, 0% packet loss</div><div><i><span style="color: #ffa400;">=> 새로 추가한 deny rule은 acl 2에 위치하므로 acl 1(permit+reflect)가 적용되어 ping OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 1 del</b></div><div>vpp# </div><div>vpp# </div><div>vpp# <b>show acl-plugin acl </b> </div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: </div><div> used in lookup context index: </div><div>acl-index 1 count 1 tag {AAA}</div><div> 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: </div><div> used in lookup context index: </div><div>acl-index 2 count 1 tag {CCC}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>vpp# </div><div>vpp# <b>ping 8.8.8.8</b></div><div><br /></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div><div><i><span style="color: #ffa400;">=> acl 1(permit+reflect) 삭제했으니, ping 안되는 것 역시 OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 2 del</b></div><div>vpp# <b>ping 8.8.8.8 </b> </div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=30.4948 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=116 time=30.4885 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=3 ttl=116 time=30.3899 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=4 ttl=116 time=30.4338 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=5 ttl=116 time=30.4061 ms</div><div><br /></div><div>Statistics: 5 sent, 5 received, 0% packet loss</div><div><i><span style="color: #ffa400;">=> acl 2(deny) rule 삭제했으니 ping 되는 것 OK</span></i></div><div><br /></div><div>vpp# <b>set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 0</b></div><div>vpp# <b>ping 8.8.8.8 </b> </div><div><br /></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div><div><i><span style="color: #ffa400;">=> acl 0(deny rule) 다시 enable했으니, ping 안되는 것은 OK</span></i></div><div><br /></div><div>vpp#<b> set acl-plugin interface TenGigabitEthernet3b/0/2 input acl 1</b></div><div>vpp# <b>show acl-plugin acl</b> </div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 1 count 1 tag {AAA}</div><div> 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 2 count 1 tag {CCC}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: </div><div> used in lookup context index: </div><div>vpp# </div><div>vpp# </div><div>vpp# <b>ping 8.8.8.8 </b> </div><div><br /></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div><div><i><span style="color: #ffa400;">=> acl 1(permit+reflect) 다시 enable 했으나, acl 0(deny)가 적용되어 ping 안되는 것 OK</span></i></div><div><br /></div><div>vpp# <b>show acl-plugin acl </b> </div><div>acl-index 0 count 1 tag {BBB}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 1 count 1 tag {AAA}</div><div> 0: ipv4 permit+reflect src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: 3</div><div> used in lookup context index: 0</div><div>acl-index 2 count 1 tag {CCC}</div><div> 0: ipv4 deny src 0.0.0.0/0 dst 0.0.0.0/0 proto 0 sport 0-65535 dport 0-65535</div><div> applied inbound on sw_if_index: </div><div> used in lookup context index: </div><div>vpp# </div><div>-----------------------------------------------------------------------------------</div></div><div style="font-family: Nunito;"><br /></div><div><div><span style="font-family: Nunito;">여기까지 확인 결과, acl 적용 순서는 제대로 먹히는게 분명하다. 문제는 tcp/udp/icmp protocol에 대한 제어가 안되는 것 같다는 것인데 ... 뭐가 문제일까 ? 😂</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌</span><span style="color: #990000; font-family: Nunito;"> vpp ACL과 관련해서는 좀 더 분석 후 다시 정리해 보도록 하자. vppctl 대신 vpp_api_test program을 이용하는 방법도 함께 고민해 보도록 하자.</span></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://wiki.fd.io/view/VPP/SecurityGroups">https://wiki.fd.io/view/VPP/SecurityGroups</a></span></div><div><br /></div><div><br /></div><div style="font-family: "Noto Sans CJK KR";"><br /></div></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><div><div style="font-family: "Noto Sans CJK KR";"><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">7. Load Balancer</span></b></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">이 장에서는 vpp load balancing의 개념을 살펴본 후, (아래 그림에서 사용하는 lb 명령 보다 상대적으로 간단한) NAT44 기반의 Load balancer를 만드는 방법을 소개해 보고자 한다.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>1) VPP 전용 Load Balancer</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">VPP에는 아래 그림에 해당하는 load balancing 전용 명령(lb)이 포함되어 있다. 먼저 이 방법을 이용해 load balancing 설정을 해 보려고 보니, 머리가 좀 지끈거린다(준비할게 한두가지가 아니다). 😂</span></div><div style="font-family: "Noto Sans CJK KR";"><br /></div></div><div style="font-family: "Noto Sans CJK KR";"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3ckEPDHddLv8ZUnJzN43EXUMndaT4hqfJ_ZYY3pke5zJXS1K120qL6D2TC_nEkDAN7i4XIdTnm4nhlmuJVWMF6-yx7XDZU0znY55Uj5ioq7_0vnZPeER6TFamOL_zJ90vECTgicc0_JMzuXV7AiTyOqUbLwD6Cay3hHzuDgt_WmOi0Kymh231Bov4FOVU/s528/vpp_loadbalancer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="413" data-original-width="528" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3ckEPDHddLv8ZUnJzN43EXUMndaT4hqfJ_ZYY3pke5zJXS1K120qL6D2TC_nEkDAN7i4XIdTnm4nhlmuJVWMF6-yx7XDZU0znY55Uj5ioq7_0vnZPeER6TFamOL_zJ90vECTgicc0_JMzuXV7AiTyOqUbLwD6Cay3hHzuDgt_WmOi0Kymh231Bov4FOVU/s320/vpp_loadbalancer.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 7.1] VPP 기반 Load Balancer [출처: 참고 문헌 4]</span></div></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">vpp# <b>lb ?</b></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><div> lb as lb as <vip-prefix> [protocol (tcp|udp) port <n>] [<address> [<address> [...]]] [del] [flush]</div><div> lb conf lb conf [ip4-src-address <addr>] [ip6-src-address <addr>] [buckets <n>] [timeout <s>]</div><div> lb flush vip lb flush vip <prefix> [protocol (tcp|udp) port <n>]</div><div> lb set interface nat4 lb set interface nat4 in <intfc> [del]</div><div> lb set interface nat6 lb set interface nat6 in <intfc> [del]</div><div> lb vip lb vip <prefix> [protocol (tcp|udp) port <n>] [encap (gre6|gre4|l3dsr|nat4|nat6)] [dscp <n>] [type (nodeport|clusterip) target_port <n>] [new_len <n>] [src_ip_sticky] [del]</div><div><br /></div></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><div><span style="font-family: Nunito;"><b><span style="color: #a64d79;"><load balacning을 위한 encapsulation 방법></span></b></span></div><div><div><i> => Load balancing을 위해 packet을 전달하는 방법에는 크게 3가지 기법이 있다(단, 아래 내용에는 IPv6는 편의상 생략).</i></div><div><span style="color: #a64d79;">a) IPv4+GRE</span></div><div><span style="color: #a64d79;">b) IPv4+L3DSR - VIP <-> DSCP에 mapping하는 방법</span></div><div><span style="color: #a64d79;">c) NAT4</span></div><div><br style="font-family: Nunito;" /></div></div><div>이 중, GRE 터널을 이용한 방법과 NAT를 이용한 방법은 그럭저럭 알겠는데, L3DSR은 단어(L3DSR - L3 Direct Server Return)만 보아서는 무슨 말인지 잘 이해가 안된다. 이건 뭘까 ?</div><div><br /></div><div>백문이 불여일견~ 아래에 L3DSR를 보다 이해하기 쉽도록 하나의 그림으로 표현해 보았다. 아래 그림이 이해가 되는가 ?</div></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwDYCMy3eaUg79xButyaoJpbk2XskMK6qMKPUqRi9AimvisYQWab3rWI22kCZ8fraFMpNq62c9FdDPLvcC9Bw6MrCCYYhmlnYD1gGzFTrc-OtpwhnfyQbSiigzkqI7om8YkZPsSxIUwNUA7IPmeYr6EuviE7Rze9ViehVXo5fsaabrK3rnHAQS6_AYTgcZ/s767/vpp_lb_l3dsr.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="339" data-original-width="767" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwDYCMy3eaUg79xButyaoJpbk2XskMK6qMKPUqRi9AimvisYQWab3rWI22kCZ8fraFMpNq62c9FdDPLvcC9Bw6MrCCYYhmlnYD1gGzFTrc-OtpwhnfyQbSiigzkqI7om8YkZPsSxIUwNUA7IPmeYr6EuviE7Rze9ViehVXo5fsaabrK3rnHAQS6_AYTgcZ/w400-h176/vpp_lb_l3dsr.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 7.2] VPP 기반 L3DSR Load Balancing 개념도 [출처: 참고 문헌 5]</span></div><div><br /></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌</span><span style="color: #990000;"> DSCP는 우선순위 정보를 담기 위해 사용(QoS)하는 ipv4 header 내의 필드이다. 이 값에 적절한 정보를 실어 보내고 이를 VIP 값과 matching 즉, DSCP 000010 => VIP x.x.x.2 하는 방법을 사용하여 load balancing을 구현한 것이 L3DSR이다.</span></div><div><br /></div><div>여기까지의 구성은 생각보다 좀 복잡하다. 그 이유는 VPP가 LB 장비 위에만 올라가는 구조가 아니기 때문이다. 즉, VPP는 (그림 7.1 기준으로) Router, LB, Proxy 세곳에 모두 올라가 있어야만 제대로 동작한다.</div></span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="color: #38761d; font-size: large;">2) NAT 기반 초 간단 Load Balancer</b></span></div><div>아, 그렇다면, load balancer가 반드시 위와 같은 구조이어야만 할까 ? 일반적인 L4 switch는 장비 하나로만 구성되어 있지 않은가 ? </div><div><br /></div><div style="font-family: "Noto Sans CJK KR";"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwaeyCJidn2vGqUBvSXEB4byXHboIw7FmqdPOCgZ1yOlJelmBrPBx7d5izwNk-QsGjxDSlWTe6PnlkJiqRYfaqngG8An6c_LcrSoYSJn5SQ8T3WuBcgSqo6CEu0pCmgv2hrdZve9mdmhOjc1SM8Mr-Ap-5kooh3vYHG1gf-ths540FcDFwNgYIJGWZ4wGo/s956/vpp_nat_load_balancer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="448" data-original-width="956" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwaeyCJidn2vGqUBvSXEB4byXHboIw7FmqdPOCgZ1yOlJelmBrPBx7d5izwNk-QsGjxDSlWTe6PnlkJiqRYfaqngG8An6c_LcrSoYSJn5SQ8T3WuBcgSqo6CEu0pCmgv2hrdZve9mdmhOjc1SM8Mr-Ap-5kooh3vYHG1gf-ths540FcDFwNgYIJGWZ4wGo/w400-h188/vpp_nat_load_balancer.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 7.3] VPP 기반 Load Balancer Testbed - NAT 기반</span></div></div><div><br /></div><div>이제부터는 NAT44 static mapping 기능을 사용하여 L4 switch와 유사한 load balacner를 구현하는 예제를 소개해 보기로 한다.</div><div><br /></div><div>======================</div><div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>bvi create instance 0</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge bvi0 1 bvi</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int ip address bvi0 192.168.10.1/24</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state bvi0 up</b></div><div><i> </i><i>=> </i><i>bridge virtual interface를 하나 만들고, bridge domain 1에 포함시킨다. 이어 ip 주소를 할당한다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int l2 bridge TenGigabitEthernet3b/0/0 1</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int state TenGigabitEthernet3b/0/0 up</b></div><div><i> => 물리 LAN port를 bridge 1에 포함시킨다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface state TenGigabitEthernet3b/0/2 up</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24</b></div><div><i> => WAN port를 up시키고, ip를 할당한다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>ip route add 0.0.0.0/0 via 192.168.3.254 TenGigabitEthernet3b/0/2</b></div><div><i> => default gateway를 추가한다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 forwarding enable</b></div><div><i> => nat44 forwardng을 enable 시킨다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 plugin enable sessions 10000</b></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>set interface nat44 in bvi0 out TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"> => bvi0를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.</i></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">vpp# </span><b>nat44 add interface address TenGigabitEthernet3b/0/2</b></div><div><i style="background-color: white; color: #333333; font-size: 14.85px;"> => NAT44 interface로 WAN port를 등록한다.</i></div></div><div>======================</div><div><br /></div><div>여기까지는 4장의 L3 NAT router 설정과 동일하며, 마지막에 아래 명령을 추가해 주면 된다.</div><div><br /></div></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><div>vpp# <b><span style="color: #b45f06;">nat44 add load-balancing static mapping protocol tcp external 192.168.3.33:80 local 192.168.10.100:80 probability 50 local 192.168.10.200:80 probability 50</span></b></div></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><i>=> 내부에 server가 여러 개일 경우, local ip:port 형태로 반복해서 열거해 주면 된다. 물론 이때 probability 값도 그에 맞게 조정해 주어야 한다. 2개의 내부 서버를 설정해 주었으므로 probability 값은 50이다. 그림 7.3 처럼 4개의 서버가 있다면 </i><i>probability 값은 25가 되어야 한다.</i></div><div><br /></div><div><div>vpp# <b>show nat44 static mappings</b></div><div>NAT44 static mappings:</div><div> TCP external 192.168.3.33:22 </div><div> local 192.168.10.200:22 vrf 0 probability 50</div><div> local 192.168.10.100:22 vrf 0 probability 50</div></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div style="font-family: "Noto Sans CJK KR";"><b><span style="color: #38761d;"><Windows PC></span></b></div><div style="font-family: "Noto Sans CJK KR";">web browser: http://192.168.3.33</div></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><i> => 테스트 결과, 1:1 비율로 web service가 분배되는 것을 알 수 있다.</i></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><i> => 설정을 바꾸어, web 대신 ssh를 이용해서 테스트해 보아도 좋다.</i></span></div><div style="font-family: Nunito;"><span style="font-family: Nunito;"><br /></span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">8. WireGuard</span></b></div><div><span style="font-family: Nunito;">이 장에서는 WireGuard plugin을 이용하여 vpn 터널을 만드는 방법을 소개하고자 한다. W</span><span style="font-family: Nunito;">ireGuard(linux kernel 기반)와 관련해서는 이미 여러 차례 내용 정리를 한 바가 있다.</span></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><i>a) WireGuard Original => </i></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><i><span style="font-family: Nunito;">b) PQ-WireGuard(양자내성 암호 알고리즘이 통합된 wireguard) =></span></i></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html">https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsdGuZRpJUcYFahwM-esI8OlIl2BxnPY-oRxp7RCDGyfIYCeF_8ivkSz6foOjdP2GXS-hBBlK35z0W8PKykHkQ8iCnoOK-TPqA6pYdUlGWM2q_spAkd-RMEsYbDyoOu2N6lOnB6DeQNqVuHEQCNQjNPwh0Z4349XTdrdqJwFoiIV_fV5dKk4dvbsHsbpBv/s1038/vpp_wireguard_network.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="465" data-original-width="1038" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsdGuZRpJUcYFahwM-esI8OlIl2BxnPY-oRxp7RCDGyfIYCeF_8ivkSz6foOjdP2GXS-hBBlK35z0W8PKykHkQ8iCnoOK-TPqA6pYdUlGWM2q_spAkd-RMEsYbDyoOu2N6lOnB6DeQNqVuHEQCNQjNPwh0Z4349XTdrdqJwFoiIV_fV5dKk4dvbsHsbpBv/w400-h179/vpp_wireguard_network.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 8.1] WireGuard VPN 터널(VPP wireguard <=> ubuntu wireguard)</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div style="background-color: white; color: #333333; font-size: 14.85px;"><span style="font-family: Nunito;"><div>vpp# <b>set interface state TenGigabitEthernet3b/0/0 up <span style="color: #38761d;">#vpp 장비 LAN port up</span></b></div><div>vpp# <b>set interface state TenGigabitEthernet3b/0/2 up <span style="color: #38761d;">#vpp 장비 WAN port up</span></b></div><div><br /></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/0 192.168.10.1/24 <span style="color: #38761d;">#vpp LAN ip 설정</span></b></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24 <span style="color: #38761d;">#vpp WAN ip 설정</span> </b></div></span></div><div style="background-color: white; color: #333333; font-size: 14.85px;"><span style="font-family: Nunito;"><br /></span></div><div style="background-color: white;"><span style="font-family: Nunito;"><div style="color: #333333; font-size: 14.85px;">vpp# <b>wireguard create listen-port 59760 src 192.168.3.33 <span style="color: #38761d;">#wireguard interface 생성(keypair 생성 포함)</span></b></div><div style="color: #333333; font-size: 14.85px;">wg0</div><div style="color: #333333; font-size: 14.85px;">vpp# <b>show wireguard interface</b> </div><div style="color: #333333; font-size: 14.85px;">[0] wg0 src:192.168.3.33 port:59760 private-key:EAAAADAAAAAg72qwxn8AAAoAAAAAAAAAwPzoB8d/AAA= 100000003000000020ef6ab0c67f00000a00000000000000c0fce807c77f0000 public-key:Fp57l81Z2RCToioDipRIN54/a+bVeD4Lpc1CDdDyJBo= 169e7b97cd59d91093a22a038a9448379e3f6be6d5783e0ba5cd420dd0f2241a mac-key: 72d149c21d7b81ba57fb201daded7c62775c107a4192a4fc49d1c131ed87bece</div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333;"><span style="color: #b45f06;">📌</span><span style="color: #990000;"> 위의 create 명령을 실행할 경우, 매번 새로운 </span><span style="color: #990000;">public/privatekey pair가 생성되는 문제(?) 가 있다. </span><span style="color: #990000;">한번 생성한 public/privatekey pair를 일정 기간 유지하기 위해서는 아래와 같이, vpp 외부에서 keypair를 생성 후 사용하면 된다.</span></div><div><span style="color: #45818e;">$ <b>wg genkey | tee ./privatekey | ./wg pubkey > ./publickey</b></span></div><div><span style="color: #45818e;"><span style="font-size: 14.85px;">vpp#</span> <b>wireguard create listen-port 59760 private-key <privatekey> src 192.168.3.33</b></span></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;"><div>vpp# <b>set interface state wg0 up <span style="color: #38761d;">#wg0 interface up</span></b></div><div>vpp# <b>set int ip address wg0 172.16.1.99/24 </b><b><span style="color: #38761d;">#wg0 interface ip 설정</span></b></div><div>vpp# <b>show int addr</b></div><div>TenGigabitEthernet3b/0/0 (up):</div><div>TenGigabitEthernet3b/0/1 (dn):</div><div>TenGigabitEthernet3b/0/2 (up):</div><div><span style="color: #ffa400;"> L3 192.168.3.33/24</span></div><div>TenGigabitEthernet3b/0/3 (dn):</div><div>local0 (dn):</div><div>wg0 (up):</div><div><span style="color: #ffa400;"> L3 172.16.1.99/24</span></div></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;">vpp# <b>wireguard peer add wg0 public-key</b> <b>EgJxYfRtnM1iYO4W223wstMy/45iMCRGf/b4qSryzT0= endpoint 192.168.3.101 </b><b style="font-size: 14.85px;">dst-port 59760 </b><b style="font-size: 14.85px;">allowed-ip 0.0.0.0/0 allowed-ip 172.16.1.254/32 persistent-keepalive 25 <span style="color: #38761d;">#wireguard peer 설정</span></b></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;">vpp# <b>set interface mtu packet 1420 wg0 <span style="color: #38761d;">#wireguard mtu 설정</span> </b></div><div style="color: #333333; font-size: 14.85px;"> </div><div style="color: #333333; font-size: 14.85px;">vpp# <b>ip route add 0.0.0.0/0 via 172.16.1.99 wg0 <span style="color: #38761d;">#wg0를 이용하는 routing entry 설정</span></b></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;"><div>vpp# <b>ping 8.8.8.8 </b> </div><div><span style="color: #ffa400;">참고) vpp에서 kernel wireguard 장비를 통해 internet(8.8.8.8)으로 ping 시도</span></div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=36.5289 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=36.1525 ms</div></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;">$ <b>sudo tcpdump -i eth2 port 59760 </b> <b><span style="color: #38761d;">#kernel wireguard 장비에서 wireguard packet capture</span></b></div><div style="color: #333333; font-size: 14.85px;"><div>19:19:27.564590 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:19:27.600483 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:19:28.564570 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:19:28.600506 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div></div><div style="color: #333333; font-size: 14.85px;">...</div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;">vpp# <b>ip route del 0.0.0.0/0 via 172.16.1.99 wg0 </b></div><div style="color: #333333; font-size: 14.85px;">vpp# <b>ip route add 192.168.5.0/24 via 172.16.1.99 wg0 </b></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;"><div>vpp# <b>ping 192.168.5.1</b></div><div><span style="color: #ffa400;">참고) vpp에서 kernel wireguard 장비 LAN ip로 ping 시도</span></div><div>116 bytes from 192.168.5.1: icmp_seq=1 ttl=64 time=.3942 ms</div><div>116 bytes from 192.168.5.1: icmp_seq=2 ttl=64 time=.3891 ms</div></div><div style="color: #333333; font-size: 14.85px;"><br /></div><div style="color: #333333; font-size: 14.85px;">$ <b>sudo tcpdump -i eth2 port 59760 </b> <b><span style="color: #38761d;">#kernel wireguard 장비에서 wireguard packet capture</span></b></div><div style="color: #333333; font-size: 14.85px;"><div>19:21:27.238980 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:28.238698 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:28.238996 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:29.238651 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:29.238940 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:30.238610 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:30.238815 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div></div></span></div></div><div><br /></div><div><span style="color: #b45f06; font-family: Nunito;">아, 그런데 반대 방향으로의 ping이 안된다. 왜 일까 ?</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="color: #38761d; font-family: Nunito;"><b>좌측 Ubuntu --> wireguard tunnel --> vpp -> internal network(192.168.10.200)</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b><Ubuntu></b></span></div><div><span style="font-family: Nunito;">$ <b>ip route add 192.168.10.0/24 dev wg0</b></span></div><div><span style="font-family: Nunito;">$ <b>ping 192.168.10.200</b></span></div><div><span style="font-family: Nunito;"> -> 아무래도 응답을 못하는 것 같다 😓</span></div><div><br /></div><div><div><div style="background-color: white;"><span style="font-family: Nunito;"><div style="color: #333333; font-size: 14.85px;">$ <b>sudo tcpdump -i eth2 port 59760 </b> <b><span style="color: #38761d;">#kernel wireguard 장비에서 wireguard packet capture</span></b></div><div style="color: #333333; font-size: 14.85px;"><div>19:21:27.238980 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:28.238996 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:29.238940 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:30.238815 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div></div></span></div></div><div>...</div></div><div><br /></div><div><br /></div><div><b style="background-color: #fff2cc;"><여기서 잠깐></b></div><div><span style="font-family: Nunito;"> => WireGuard의 chacha20-poly1305 AEAD를 h/w적으로 가속화할 수는 없을까 ? 아래에 답이 있다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ6paRHFPzsXjDRwDQ18N653WzmmAKp4UvniqBF2yVPuE7IySLjAMGe0xISMbQLqT2hrgnyalYWQeC2jGCUZNesdeOne9aLWUKY5yq9fepC0kn0mWAQRjfr2dVqSpPpfPgWXReimmLS8b2IEf9Y4KRC7oIcCazQAyPlnt8Piosu0u-HjRt8l4MY5X4bMy6/s785/intel_qat_8960_8970.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="785" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJ6paRHFPzsXjDRwDQ18N653WzmmAKp4UvniqBF2yVPuE7IySLjAMGe0xISMbQLqT2hrgnyalYWQeC2jGCUZNesdeOne9aLWUKY5yq9fepC0kn0mWAQRjfr2dVqSpPpfPgWXReimmLS8b2IEf9Y4KRC7oIcCazQAyPlnt8Piosu0u-HjRt8l4MY5X4bMy6/w400-h189/intel_qat_8960_8970.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 8.2] Intel QAT 8960/8970 암호 가속기</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3w2xl1XRugLo72urhoXJL1zh9uL36G0_OBxX3Sr1H6xihzd2F03YrlAvWT5OIS4A8fBL288f3gHkPgDzp_vim8pOAAS0t-148Nfx_dH8ttgoW3Xrec0LqAQuaWOJ3GWnHCU3DnslkzVxHdAmrUF0DxXJL0heTAiKW8Lfr74eGVU7c7Gs3Gr4dgdyeOKci/s954/vpp_wireguard_intel_qat.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="355" data-original-width="954" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3w2xl1XRugLo72urhoXJL1zh9uL36G0_OBxX3Sr1H6xihzd2F03YrlAvWT5OIS4A8fBL288f3gHkPgDzp_vim8pOAAS0t-148Nfx_dH8ttgoW3Xrec0LqAQuaWOJ3GWnHCU3DnslkzVxHdAmrUF0DxXJL0heTAiKW8Lfr74eGVU7c7Gs3Gr4dgdyeOKci/w640-h238/vpp_wireguard_intel_qat.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 8.3] Intel QAT를 이용한 wireguard 암호 가속[출처 - 참고문헌 12]</span></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">참고로, 아래 supermicro appliance에는 intel QAT chip이 자체적으로 포함되어 있어, 매우 편리하다.</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgalp4Ms4b4QaYQoRvAEO6bUcjC08pquvW3OVAShbIHjRoXQCboj6hxVUYul3uwkkwzyxdBsqu1mxtJXN5d2SCveYjje8gGnJSa8NJ8bDRDTyxrKc-hPT6GM_R_SQ7No5NgDpTfX7MmrOvDYhnYiFtyaPGVlzOnuOBggjvtdHZumVM-kLo26TB0CKPRYF07/s487/supermicro_sys_110d_8c_fran8tp.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="258" data-original-width="487" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgalp4Ms4b4QaYQoRvAEO6bUcjC08pquvW3OVAShbIHjRoXQCboj6hxVUYul3uwkkwzyxdBsqu1mxtJXN5d2SCveYjje8gGnJSa8NJ8bDRDTyxrKc-hPT6GM_R_SQ7No5NgDpTfX7MmrOvDYhnYiFtyaPGVlzOnuOBggjvtdHZumVM-kLo26TB0CKPRYF07/s320/supermicro_sys_110d_8c_fran8tp.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 8.4] Test 장비(</span><span style="background-color: white; color: #222222; font-family: Nunito; text-align: left;">IoT SuperServer SYS-110D-8C-FRAN8TP) [출처 - 참고문헌 13]</span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌</span><span style="color: #990000;"><span style="background-color: white; font-family: Nunito;"> </span><span style="font-family: Nunito;">Intel QAT와 관련해서는 참고문헌 14를 참고하기 바란다.</span></span></div><div><br /></div><div>-------------------------------------------------------------------------------------------------</div><div><br /></div><div><br /></div><div><br /></div><div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">9. IPSec</span></b></div><div><span style="font-family: Nunito;">이 장에서는 (개인적으로는 WireGuard 골수 왕 팬이지만, 그래도 30년 이상 명맥을 이어온) IPSec에 관하여 소개해 보고자 한다. VPP에 구현되어 있는 코드의 경우, 아직까지는 WireGuard(development 수준) 보다는 IPSec(production 수준)이 좀 더 안정화되어 있는 느낌이다. </span></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVgDSWhEYMpB8pE4WRBxOv1WBAOcNY9iCYN_-rW1gFaJqC153QzPLTMkJ4uiJqpBPuizmZXnUHF_6f85bbKz_UE5X9-He1GOiqe_bEX71MdccWbjebdmd8iV6Fk_Z80uYG67el4DhWSQodDIdemiH8kXyfNRPbHF4xcQYR0ifIcUzpL5aM4NOBpUde8WVa/s1214/vpp_ipsec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="1214" height="175" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVgDSWhEYMpB8pE4WRBxOv1WBAOcNY9iCYN_-rW1gFaJqC153QzPLTMkJ4uiJqpBPuizmZXnUHF_6f85bbKz_UE5X9-He1GOiqe_bEX71MdccWbjebdmd8iV6Fk_Z80uYG67el4DhWSQodDIdemiH8kXyfNRPbHF4xcQYR0ifIcUzpL5aM4NOBpUde8WVa/w400-h175/vpp_ipsec.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 9.1] IPSec VPN 터널 구성</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://s3-docs.fd.io/vpp/24.02/cli-reference/clis/clicmd_src_vnet_ipsec.html">https://s3-docs.fd.io/vpp/24.02/cli-reference/clis/clicmd_src_vnet_ipsec.html</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>ipsec ?</b></div><div> ipsec itf create ipsec itf create [instance <instance>]</div><div> ipsec itf delete ipsec itf delete <interface></div><div> ipsec policy ipsec policy [add|del] spd <id> priority <n> </div><div> ipsec sa bind ipsec sa [unbind] <sa-id> <worker></div><div> ipsec sa ipsec sa [add|del]</div><div> ipsec select backend ipsec select backend <ah|esp> <backend index></div><div> ipsec spd ipsec spd [add|del] <id></div><div> ipsec tunnel protect ipsec tunnel protect <interface> input-sa <SA> output-sa <SA> [add|del]</div><div><br /></div><div><div>vpp# <b>show ipsec ?</b></div><div> show ipsec all show ipsec all</div><div> show ipsec backends show ipsec backends</div><div> show ipsec interface show ipsec interface</div><div> show ipsec protect show ipsec protect</div><div> show ipsec protect-hash show ipsec protect-hash</div><div> show ipsec sa show ipsec sa [index]</div><div> show ipsec spd show ipsec spd [index]</div><div> show ipsec tunnel show ipsec tunnel</div></div><div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div><div>vpp# <b>ikev2 ?</b></div><div> ikev2 dpd disable ikev2 dpd disable</div><div> ikev2 initiate ikev2 initiate sa-init <profile id></div><div>ikev2 initiate del-child-sa <child sa ispi></div><div>ikev2 initiate del-sa <sa ispi></div><div>ikev2 initiate rekey-child-sa <child sa ispi></div><div> ikev2 profile ikev2 profile [add|del] <id></div><div>ikev2 profile set <id> auth [rsa-sig|shared-key-mic] [cert-file|string|hex] <data></div><div>ikev2 profile set <id> id <local|remote> <type> <data></div><div>ikev2 profile set <id> tunnel <interface></div><div>ikev2 profile set <id> udp-encap</div><div>ikev2 profile set <id> traffic-selector <local|remote> ip-range <start-addr> - <end-addr> port-range <start-port> - <end-port> protocol <protocol-number></div><div>ikev2 profile set <id> responder <interface> <addr></div><div>ikev2 profile set <id> ike-crypto-alg <crypto alg> <key size> ike-integ-alg <integ alg> ike-dh <dh type></div><div>ikev2 profile set <id> esp-crypto-alg <crypto alg> <key size> [esp-integ-alg <integ alg>]</div><div>ikev2 profile set <id> sa-lifetime <seconds> <jitter> <handover> <max bytes>ikev2 profile set <id> disable natt</div><div> ikev2 set liveness ikev2 set liveness <period> <max-retires></div><div> ikev2 set logging level ikev2 set logging level <0-5></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>show ikev2 ?</b></div><div> show ikev2 profile show ikev2 profile</div><div> show ikev2 sa show ikev2 sa [rspi <rspi>] [details]</div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">IPSec & IKEv2 설정 방법과 관련해서는 아래 wiki page에 아주 잘 설명되어 있으며, 이를 참조하는게 답일 듯 하다. 근데, vpp old version을 기준으로 설명되어 있어, 일부 명령이 좀 달라졌으니, 주의를 요한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://wiki.fd.io/view/VPP/IPSec_and_IKEv2">https://wiki.fd.io/view/VPP/IPSec_and_IKEv2</a></span></div><div><span style="font-family: Nunito;"><div><br style="font-family: "Noto Sans CJK KR";" /></div></span></div><div><span style="font-family: Nunito;">또한 아래 youtube 영상도 VPP 기반 IPSec을 이해하는데 도움이 될 것으로 보인다.</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://www.youtube.com/watch?v=C8cbJCT2blY&ab_channel=LFNetworking">https://www.youtube.com/watch?v=C8cbJCT2blY&ab_channel=LFNetworking</a></span></div><div><br /></div><div><br /></div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">10. </span></b><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">Snort 기반의 IPS</span></b></div><div><span style="font-family: Nunito;">VPP를 활용하면, <a href="https://www.snort.org/">Snort</a>나 <a href="https://suricata.io/">Suricata</a> 등과 연합하여 S/W 기반의 고성능 IPS(Intrusion Prevention System) 개발도 가능하다. 이번 장에서는 IPS를 만드는 과정을 소개해 보고자 한다.</span></div></div><div><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglIRSkjGoyFLlqGJKsnvhn-CZzA_vhBTz9wc-ybW8shlkKeNZ2KW539YTVnQSKCuIP61Rp3517Q72-SbEZats9Uj972JMhOxVzXS37v10olnQbo_NSGhMQr3rAhQWVjG3-hmK4LnfHbDeWSftsZeXtD34W_kPdczTLabBMHv9bXDwhL4dAn3yx_lgCNQJN/s1001/vpp_snort.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="498" data-original-width="1001" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglIRSkjGoyFLlqGJKsnvhn-CZzA_vhBTz9wc-ybW8shlkKeNZ2KW539YTVnQSKCuIP61Rp3517Q72-SbEZats9Uj972JMhOxVzXS37v10olnQbo_NSGhMQr3rAhQWVjG3-hmK4LnfHbDeWSftsZeXtD34W_kPdczTLabBMHv9bXDwhL4dAn3yx_lgCNQJN/w400-h199/vpp_snort.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 10.1] VPP & Snort IPS 구성 [출처 - 참고문헌 10]</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3F4YGY7ImhyphenhyphenTRVOzvmH0VWOU_t_1U9CVIo5anXug3QvnhmRpSfV3RgH2YADaZkn7kbE6OKlUIHoXQdz-r6kRrE0cPBYnSBKGti_TL8YnyPUNSyTz-cuwR1zp9EEtQznLuQSnhVbd-8FfBdMXgZDQ_pVHyDZ628Yr5FF-2Z7nzL7t0zZdQNowySLNGqtqS/s604/vpp_snort_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="321" data-original-width="604" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3F4YGY7ImhyphenhyphenTRVOzvmH0VWOU_t_1U9CVIo5anXug3QvnhmRpSfV3RgH2YADaZkn7kbE6OKlUIHoXQdz-r6kRrE0cPBYnSBKGti_TL8YnyPUNSyTz-cuwR1zp9EEtQznLuQSnhVbd-8FfBdMXgZDQ_pVHyDZ628Yr5FF-2Z7nzL7t0zZdQNowySLNGqtqS/w400-h213/vpp_snort_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 10.2] VPP & Snort IPS 구성 [출처 - 참고문헌 10]</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #ffa400; font-family: Nunito; font-size: medium;"><b>To be continued...</b></span></div><div><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">References</span></b></div><div><div style="background-color: white;"><span style="font-family: Nunito;">[1] </span><span style="background-color: transparent;"><span style="font-family: Nunito;">https://s3-docs.fd.io/vpp/24.02/</span></span></div></div></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[2] https://ipng.ch/s/articles/</span></span></div><div style="background-color: white;"><span style="color: #ffa400; font-family: Nunito;"><i> => VPP examples</i></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[3] https://events19.linuxfoundation.org/wp-content/uploads/2017/12/Implementing-A-High-Performance-Virtualized-CPE-Solution-Hongjun-Ni-Xingfu-Li-Intel.pdf</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="color: #ffa400; font-family: Nunito;"><i> => VPP로 할 수 있는 것들을 한눈에 ...</i></span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[4] https://www.dpdk.org/wp-content/uploads/sites/35/2018/12/A-Hierarchical-SW-Load-Balancing-Solution-for-Cloud-Deployment.pdf</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[5] https://events19.linuxfoundation.org/wp-content/uploads/2018/07/ONS.NA_.2019.VPP_LB_public.pdf</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="color: #ffa400; font-family: Nunito;"><i> => Load balancing 관련 </i></span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[6] https://www.youtube.com/watch?v=C8cbJCT2blY&ab_channel=LFNetworking</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[7] https://docs.nxp.com/bundle/GUID-3FFCCD77-5220-414D-8664-09E6FB1B02C6/page/GUID-EBA9A5C6-2407-4AC7-87B6-C1470B2CD92D.html</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;"> <i><span style="color: #ffa400;"> => IPSec 관련</span></i></span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[8] https://www.netgate.com/resources/articles-vector-packet-processing</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[9] https://wiki.fd.io/view/VPP/NAT</span></span></div><div style="background-color: white;"><span style="background-color: transparent;"><span style="font-family: Nunito;">[10] Next_Generation_Firewall_Optimizations_Solution_Brief_765277v1.pdf</span></span></div><div style="background-color: white;"><span style="font-family: Nunito;">[11] </span><span style="background-color: transparent;"><span style="font-family: Nunito;"> Impressive Packet Processing Performance Enables Greater Workload Consolidation</span></span></div><div style="background-color: white;"><span style="font-family: Nunito;"><span style="background-color: transparent;">[12] </span>Intel® AVX-512 and Intel® QAT - Accelerate WireGuard </span><span style="font-family: Nunito;">Processing with Intel® Xeon® D-2700 Processor</span></div><div style="background-color: white;"><span style="background-color: transparent; font-size: 14.85px;"><span style="font-family: Nunito;">[13] https://www.supermicro.com/en/products/system/iot/1u/sys-110d-8c-fran8tp<br />[14] https://cdrdv2-public.intel.com/784475/784475_Network%20Security%20with%20Intel%C2%AEQuickAssist%20Technology.pdf</span></span></div><div style="background-color: white;"><span style="background-color: transparent; font-size: 14.85px;"><span style="font-family: Nunito;">[15] https://github.com/mwang005/a-deep-dive-into-vpp (Good site)</span></span></div><div style="background-color: white;"><span style="background-color: transparent; font-size: 14.85px;"><span style="font-family: Nunito;"><br /></span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: right;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>Slowboot</b></span></div><div><b style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px; text-align: right;"><span style="color: #38761d; font-family: Mukta; font-size: medium;"><br /></span></b></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-80464682115753879302023-02-22T16:40:00.003+09:002023-10-01T17:24:16.855+09:00NanoPi R4S로 PQ-Wireguard VPN Router 만들기(Part II)<p><span style="font-family: Nunito;">이번 시간에는 지난 시간에 이어</span><span style="font-family: Nunito;"> </span><a href="https://www.friendlyelec.com/index.php?route=product/product&product_id=284" style="font-family: Nunito;">NanoPi R4S board</a><span style="font-family: Nunito;">를 가지고 PQC Wireguard 기반 초소형 VPN router를 만드는 과정(<b><span style="color: #990000;">Part II</span></b>)을 소개해 보고자 한다. 😎</span></p><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzA63CNtMR8tiktuOtwKEZ1DjdyZfbecKlb1uaJT25phs0ntYwy6FbsGW01fvLXa8rZcHpozBFy4bfEN0fcTM4w10VISWwCbweuZ7g0uxI2NzulfpNsNEPqAIhUALC0ANXXAj6ClPMn1U4zWS-qi5jWYmSArfPnz0nH8oeTjO-DPISCV2nyPpBmD9CPQ/s349/pq_wireguard.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="49" data-original-width="349" height="45" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzA63CNtMR8tiktuOtwKEZ1DjdyZfbecKlb1uaJT25phs0ntYwy6FbsGW01fvLXa8rZcHpozBFy4bfEN0fcTM4w10VISWwCbweuZ7g0uxI2NzulfpNsNEPqAIhUALC0ANXXAj6ClPMn1U4zWS-qi5jWYmSArfPnz0nH8oeTjO-DPISCV2nyPpBmD9CPQ/s320/pq_wireguard.png" width="320" /></a></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAKn2egW9GnzX2EMo0z1QHWZ-YY6nmHI9Cu1xLOoAXhbkM75GZ-b3jR8F55NTRr-VU-5E52V8gH5jWzUvwBghHeHMwpV7j229P55TiSqeETjIxcKz_dDv72Fu_1cZv4BbIHpGrRuCHGYxqHLz9TK70ctW_DLK1tpKykc3V1rrWkLpOnoqbfJGpLuVK_Q/s500/NanoPi_R4S-4GB_Front.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="500" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAKn2egW9GnzX2EMo0z1QHWZ-YY6nmHI9Cu1xLOoAXhbkM75GZ-b3jR8F55NTRr-VU-5E52V8gH5jWzUvwBghHeHMwpV7j229P55TiSqeETjIxcKz_dDv72Fu_1cZv4BbIHpGrRuCHGYxqHLz9TK70ctW_DLK1tpKykc3V1rrWkLpOnoqbfJGpLuVK_Q/s320/NanoPi_R4S-4GB_Front.jpg" width="320" /></a></div><span style="font-family: Nunito;">목차<br /><i><span style="color: #999999;">1. NanoPi R4S board 소개<br />2. OpenWrt build하기<br />3. WireGuard Kernel 코드 분석하기</span><br /><span>4. CRYSTALS Kyber PQC 알고리즘 소개</span></i></span></div><div><span style="font-family: Nunito;"><i><span>5. NanoPi R4S 용 Quantum Safe WireGuard 구현하기</span></i></span></div><div><i style="font-family: Nunito;"><span>6. Alpine Linux 용 Quantum Safe WireGuard 구현하기</span></i></div><div><span style="font-family: Nunito;"><i>7. References</i></span></div><div><span style="color: #b45f06; font-family: Nunito;">Keyword: NanoPi R4S, Intel AVX2, Alpine Linux, WireGuard, PQC, CRYSTALS Kyber</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><br /></div><div><span style="font-family: Nunito;"><b><Part I></b></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html">https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html</a></span></div><div><br /></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><i>WireGuard는 정말로 잘 설계된 vpn protocol이다. WireGuard에 NIST 표준으로 지정된 CRYSTALS Kyber 알고리즘을 접목시킴으로써 양자컴퓨터 시대를 대비하는 새로운 vpn protocol을 만들어 보면 어떨까 ?</i></span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><i><br /></i></span><div><b style="font-family: Nunito;"><span style="color: #0b5394; font-size: x-large;">4. CRYSTALS Kyber PQC 알고리즘 소개</span></b><br /><span style="font-family: Nunito;">이번 장에서는 PQC 알고리즘 중 CRYSTALS Kyber의 세부 동작 과정을 분석해 보고자 한다.</span> CRYSTALS Kyber 관련 많은 논문(paper)를 읽어 보았지만, 아래 논문이 가장 이해하기 쉬운 형태의 그림을 제공하고 있어서, 이번 장에서는 아래 논문을 기초로 CRYSTALS Kyber의 세부 동작 원리를 파헤쳐 보고자 한다. 이 자리를 빌어 아래 논문 저자에게 감사의 인사를 전한다. 😍</div><div><div><br /></div><div style="text-align: center;"><b><span style="color: #990000;">Active Implementation of End-to-End Post-Quantum Encryption</span><span style="color: #134f5c;">, Anton Tutoveanu</span></b></div></div><div><br /></div><div><b><span style="color: #38761d; font-size: large;">a) CRYSTALS Kyber KEM 소개</span></b></div><div>CRYSTALS Kyber는 KEM(Key Encapsulation Mechanism)을 위한 PQC 알고리즘이다. KEM은 아래와 같이 3단계 과정 즉, <b>Keypair 생성</b>, <b>Encapsulation </b>및 <b>Decapsulation</b>으로 구성되어 있다.</div><div><br /></div><div><b><KEM 절차 요약></b></div><i><span style="color: #134f5c;"><span style="background-color: white;"><b>(1)</b> Alice(Initiator)는 Key 쌍 (pk, sk)를 하나 만든 후, Bob(Responder)에게 pk(public key)를 전달한다.<br /></span><span style="background-color: white;"><b>(2) </b>pk를 받은 Bob은 Enc(encapsulation) 함수를 이용하여 대칭키 ss와 ss를 암호화한 값 c를 만든 후, Alice에게 c 값을 전달한다.<br /></span></span></i><span style="background-color: white;"><i><span style="color: #134f5c;"><b>(3)</b> c 값을 수신한 Alice는 자신이 이미 가지고 있는 sk(secret key = private key)와 Dec(decapsulation) 함수를 이용해 대칭 키 ss를 획득한다.</span></i></span><div><span style="background-color: white; color: #333333;">이후, Alice와 Bob은 서로 공유하게 된 ss 값을 이용해 암호 통신(예: AES, ChaCha20 등)을 수행하게 된다.</span> </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl6eYJLAHRzxHcjH8ZWb9C2ukbYESX8WhJ3zFxFr8wcVFW-MvpveIi24ADJbTQf89gwChbjBIGlf7s_g7VG-jBBhMVxpJznRiNnfL3BxI3SHe4ohHHkNqnc3kIhTJ8O2dctkAnLWSkB-cVa5ZUJWP6Kt5l2zG1zL7xyvcCTzeuzcC9En3j9h9fWLyzTw/s276/pqc_kem_1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="250" data-original-width="276" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl6eYJLAHRzxHcjH8ZWb9C2ukbYESX8WhJ3zFxFr8wcVFW-MvpveIi24ADJbTQf89gwChbjBIGlf7s_g7VG-jBBhMVxpJznRiNnfL3BxI3SHe4ohHHkNqnc3kIhTJ8O2dctkAnLWSkB-cVa5ZUJWP6Kt5l2zG1zL7xyvcCTzeuzcC9En3j9h9fWLyzTw/s1600/pqc_kem_1.png" width="276" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.1] PQC KEM 개요(1) [출처 - 참고문헌 11]</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqobqZgvNQmm8wt37ga2hRtnuyeE5KwHbSZSYgEpgrvNzJPkDNf49X6i2u-v1MTPu2x1KKcCecFhxqGSJpPp_Sg2ELMhU5X9siuu1WEzQdFpdAsRCRT4QX9PWV0ijjn7K1FrzukuZn8nkAf0jDdZbypVyiscUkmyJsKY3ADs49RZ3oMe2OkcudrTT7yw/s460/pqc_kem_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="277" data-original-width="460" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqobqZgvNQmm8wt37ga2hRtnuyeE5KwHbSZSYgEpgrvNzJPkDNf49X6i2u-v1MTPu2x1KKcCecFhxqGSJpPp_Sg2ELMhU5X9siuu1WEzQdFpdAsRCRT4QX9PWV0ijjn7K1FrzukuZn8nkAf0jDdZbypVyiscUkmyJsKY3ADs49RZ3oMe2OkcudrTT7yw/s320/pqc_kem_2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.2] PQC KEM 개요(2) [출처 - 참고문헌 11]</span></div><div><br /></div><div><b><span style="color: #38761d; font-size: large;">b) CRYSTALS Kyber 알고리즘의 상세 동작 원리</span></b></div><div>CRYSTALS Kyber는 M-LWE(Module Learning with Errors) 문제에 기초하고 있는데, 알고리즘의 세부 구조를 앞서 설명한 3단계 과정을 기준으로 가볍게(?) 짚고 넘어 가도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWMB3yUyn1GmBs1oCW-BFen6csVLEt3_a0E1DEx0-lxXAJEbHKOyK2yMPgMt3KtsDUMYMBmgeWG96DUZEsnqI79naGjayZ3zNpmc7bF_5KXqQxxCjrxw5vCAtQZRJFMK_W1uts6Jo_AsM8gYyo80mIVr5uWFdrA5IRuVceGobD7R-ubARs9up46NJltQ/s426/pqc_lwe.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="426" height="171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWMB3yUyn1GmBs1oCW-BFen6csVLEt3_a0E1DEx0-lxXAJEbHKOyK2yMPgMt3KtsDUMYMBmgeWG96DUZEsnqI79naGjayZ3zNpmc7bF_5KXqQxxCjrxw5vCAtQZRJFMK_W1uts6Jo_AsM8gYyo80mIVr5uWFdrA5IRuVceGobD7R-ubARs9up46NJltQ/s320/pqc_lwe.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.3] Learning with Errors [출처 - 참고문헌 11]</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 위의 그림에서 vector B가 public key로 사용(matrix A는 public key를 만들기 위해 필요함)되고, vector s가 secret key(= private key)로 사용된다. Vector e는 작은 에러(noise) 값이다.</span></div><div><br /></div><div><b>(1) Key 생성 과정</b></div><div>Public, Private key 쌍을 생성하기 위해 제일 먼저 해야 하는 일은 [그림 4.3]의 public matrix <b>A</b>, secret vector <b>s</b> 및 error(= noise) vector <b>e</b>를 만드는데 필요한 random seed 값을 생성하는 것이다. 먼저 <span style="background-color: white;">32 byte random bytes에 대해 SHA3-512를 돌려 64bytes output(digest)를 생성한다. 64 bytes 중 앞의 32 bytes는 public seed(Matrix A 생성용)로, 나머지 반은 noise seed 값으로 활용된다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBVq3I8tiy7pIC4pCiYfdAxUZNCHBpT5s4s1kjcAMpON__wQaTTt9JG0tLWqnWhLRjG_8jExBcxr-n_TTiwFGqD1UnXmAfzAOHpiKHROJwQ8XLjdR8yLYzHT0c6CxDON-9PKRvrUZmUxbu8YY_5CMvWt8LqE0EU_l8R5uSOw4dJv6dx8UFhbn3fdvAA/s452/kyber_seed_generation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="452" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBVq3I8tiy7pIC4pCiYfdAxUZNCHBpT5s4s1kjcAMpON__wQaTTt9JG0tLWqnWhLRjG_8jExBcxr-n_TTiwFGqD1UnXmAfzAOHpiKHROJwQ8XLjdR8yLYzHT0c6CxDON-9PKRvrUZmUxbu8YY_5CMvWt8LqE0EU_l8R5uSOw4dJv6dx8UFhbn3fdvAA/s320/kyber_seed_generation.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.4] CRYSTALS Kyber <b>Seed 생성 과정</b>[출처 - 참고문헌 11]</span></div><div><br /></div><div>(설명 과정을 단순화하기 위해)Kyber768의 경우, A는 256길이 mod q 계수 배열을 포함하는 3x3 matrix(행렬)로, matrix의 각 항목을 생성하기 위해 앞서 생성한 public seed와 index 값 i, j를 기반으로 SHAKE-128을 돌린다. SHAKE-128을 통해 생성된 byte array는 다시 값을 수락 or 거부하는 sampling 함수를 거쳐 최종적으로 길이 256 다항식 mod q를 결과로 출력하게 되고, 이것이 matrix A의 (i, j) 값을 구성하게 된다. <span style="color: #e69138;">캬~ 무슨 말인지 좀 어렵다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHHW09UvH5_CWsA3kNrEo3JuTIAI7QaeSAEzrUJbk6W_rlYbfb8jR6WhuaMyh5sSdQrc1cZdjMXmhC5kmqLV5fKbnUhjgmSnaI1pKfAtdQoXFA2qX-hkDcddECEc3nwwc7uMpA0EPigy5d9YiJo_U30WXcHOnXacjWhehwGLZeEwLoqBu7N__ySpHLA/s534/kyber_matrix_A_gen.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="458" data-original-width="534" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHHW09UvH5_CWsA3kNrEo3JuTIAI7QaeSAEzrUJbk6W_rlYbfb8jR6WhuaMyh5sSdQrc1cZdjMXmhC5kmqLV5fKbnUhjgmSnaI1pKfAtdQoXFA2qX-hkDcddECEc3nwwc7uMpA0EPigy5d9YiJo_U30WXcHOnXacjWhehwGLZeEwLoqBu7N__ySpHLA/s320/kyber_matrix_A_gen.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.5] CRYSTALS Kyber <b>Public Matrix A 생성 과정</b>[출처 - 참고문헌 11]</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 SHAKE-128은 XOF(eXtendable Output Function)로, output 길이가 변할 수 있는 hash 함수이다.</span></div><div><br /></div><div>Public matrix A가 만들어 졌으니, 이번에는 secret s vector와 noise e vector를 만들 차례이다. 2개를 만드는 방식은 동일한데, 먼저 [그림 4.4]에서 생성한 noise seed 값과 Nonce(정수이면서 매번 1씩 증가) 값에 대해 SHAKE-256을 돌려 128 bytes array를 만든다. 다음으로 128 bytes array를 1024 bits로 바꾼 후, CBD(centered binomial distribution - 중심 이항 분포) sampling를 한다. 그 결과 256 길이의 array를 얻을 수 있게 되고, 이는 secret s로 활용된다. noise e도 동일 과정을 통하여 생성한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF4a9LUQIxRLhU7-cOa8x51-Eb9N79aoweoMtaORR6sRSAR6wymKZ7m--pRKpz967HAIDvakfIAKFhqUUIk3a-tVb5fUhh-SIs0vRWrqsRkXoC7HEHCOMvtIQ8ecgNQyHYlqa5MkSkkpnYqVYhfnCWA28HQf1A98hsjVdVMyZr2XFxQL0E7Ich0ESsjw/s508/kyber_secret_noise_sampling.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="436" data-original-width="508" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF4a9LUQIxRLhU7-cOa8x51-Eb9N79aoweoMtaORR6sRSAR6wymKZ7m--pRKpz967HAIDvakfIAKFhqUUIk3a-tVb5fUhh-SIs0vRWrqsRkXoC7HEHCOMvtIQ8ecgNQyHYlqa5MkSkkpnYqVYhfnCWA28HQf1A98hsjVdVMyZr2XFxQL0E7Ich0ESsjw/s320/kyber_secret_noise_sampling.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.6] CRYSTALS Kyber <b>Secret & Noise 생성 과정</b>[출처 - 참고문헌 11]</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 CBD sampling은 쉽게 얘기해서 1024bits 내용에 대해 순차적으로 4bit 씩 묶어, {-2, -1, 0, 1, 2} 중의 하나로 줄이는 과정으로 이해하면 된다.</span></div><div><br /></div><div>여기까지의 과정을 거쳐, matrix A, secret s vector, noise e vector가 만들어 졌으니, 이제 아래의 연산을 통해 pk 즉 public key를 만드는 것이 가능해졌다.</div><div style="text-align: center;"><b><span style="color: #38761d; font-size: medium;">As + e = pk</span></b></div><div><br /></div><div>As + e의 결과 값은 (n 차원 polynomial mod q) 1x3 vector 인데, 256 bytes인 각 항목을 encoding하여 384 bytes로 만든 후, 앞서 생성했던 public seed 32bytes를 이어 붙이면 아래와 같이 1184 bytes의 public key(Kyber 768 기준)가 만들어지게 된다.</div><div style="text-align: center;"><b>384 x 3 + 32 = 1184 bytes</b></div><div><br /></div><div>한편 Private key(= secret key)는 1x3 secret vector를 encoding 하여 384 bytes로 만든 후, 이들을 연결(concatenation)하여, 아래와 같이 1152 bytes로 완성되게 된다.</div><div style="text-align: center;"><b>384 x 3 = 1152 bytes</b></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUJN1fNatpRi76nvahgrb1Pgi-kD949BrGO4Wz1R3fPMKu19ucx2D3XPeos7uVzVvk512rlaLZuZpyJSUv7L3eOdKgncmjn84LwymAVy8925kZWecs-Ve0BXyitL_yEBdRF5j9l-OR5z3kiuFzJQ2W8WRXnnouY6vHmUBpc36l45Tkvp7_eFeKrIxODw/s633/kyber_pk_sk_computation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="545" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUJN1fNatpRi76nvahgrb1Pgi-kD949BrGO4Wz1R3fPMKu19ucx2D3XPeos7uVzVvk512rlaLZuZpyJSUv7L3eOdKgncmjn84LwymAVy8925kZWecs-Ve0BXyitL_yEBdRF5j9l-OR5z3kiuFzJQ2W8WRXnnouY6vHmUBpc36l45Tkvp7_eFeKrIxODw/s320/kyber_pk_sk_computation.png" width="276" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.7] CRYSTALS Kyber <b>Public & Private Key 계산 과정</b>[출처 - 참고문헌 11]</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b>(2) Encapsulation 과정 및 (3) </b><b>Decapsulation 과정</b></div><div>여기까지, 매우 험난한(?) 과정을 통해, public key와 private key(or secret key)가 만들어 졌다. 이제 Encapsulation(Encrypt) 과정과 Decapsulation(Decrypt) 과정을 소개할 차례이다. </div><div><br /></div><div>먼저, Encrypt 과정을 위해서는 앞서 생성한 <b>public key,</b> 32bytes <b>message</b>(shared secret), 그리고 <b>coin</b>(<span style="color: #ffa400;">'0', '1'의 반복이 동전을 던져 앞면, 뒤면이 random하게 나오는 것과 유사해서 그렇게 부름</span>)이라고 부르는 32bytes random byte array가 사용되고, 그 결과로 ciphertext 1088 bytes(Kyber 768 기준)가 생성된다.</div><div>Public key를 전달 받은 Bob은 random array <b>r</b>과 matrix <b>A</b>(정확히는 A의 전치 행렬) 및 <b>e1</b>을 이용해 1x3 vector <b>u</b>를 계산하고, <b>r</b>과 <b>public key</b>(정확히는 public key의 transpose), <b>e2</b>, 그리고 message <b>m</b>을 이용해 <b>v</b> 값을 생성해 낸다. 이 두개의 값 <b>u + v</b>를 한 것이 <b>ciphertext</b>가 된다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Ciphertext를 만들기 위해 단순히 u+v하는 것은 아니고, ciphertext size를 줄이기 위해 압축(compressing)과 하위 bit 일부를 정리하는 과정(?)을 거친다.</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div><b>Alice's KeyGen( )</b></div><div><b style="text-align: center;"><span style="color: #38761d;"> As + e = pk</span></b></div><div><b style="text-align: center;"><span style="color: #38761d;"><br /></span></b></div><div><b>Bob's Enc( )</b></div><div> r x A(t) x pk </div><div> + e1 | e2</div><div> + 0 | m</div><div> = u | v</div><div><br /></div><div>위의 수식을 위에서 부터 아래로 줄줄이 계산해 보면, 아래와 같은 식을 얻을 수 있다.</div><div style="text-align: center;"><b>r x A(t) + e1 = u</b></div><div style="text-align: center;"><b>r x pk(t) + e2 + m = v</b></div><div><br /></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 r과 e1, e2는 앞서 설명한 noise sampling을 통해 생성한 값들이다.</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><span style="font-size: 14.85px;">📌 암호 연산 과정에는 곱셈 연산이 많이 등장하는데, 알고리즘 속도에 지대한 영향을 주는 부분이므로, Kyber에서는 NTT(Number Theoretic Transform)라는 기법을 사용하여 속도 문제를 해결하고 있다.</span></span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUEnNFh23kk2Qq3akv_K9sjcwmT-9fJHKDzcKHOTRg04RFa6fbCMUL3g0dvlX0Luy9vODtYDSZWpAZXLDig2P0IPcKkpUpTc2yrRR_EJyppL3y_Vi_OFUw885Cyq59ZVAGbMfBB5xkH5pbVaAmvYtdhNjrrbrQHrnuRwRWSaPGydk5VzY-2583o1W3-A/s620/kyber_encrypt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="456" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUEnNFh23kk2Qq3akv_K9sjcwmT-9fJHKDzcKHOTRg04RFa6fbCMUL3g0dvlX0Luy9vODtYDSZWpAZXLDig2P0IPcKkpUpTc2yrRR_EJyppL3y_Vi_OFUw885Cyq59ZVAGbMfBB5xkH5pbVaAmvYtdhNjrrbrQHrnuRwRWSaPGydk5VzY-2583o1W3-A/s320/kyber_encrypt.png" width="235" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.8] CRYSTALS Kyber <b>Encapsulation 과정</b>[출처 - 참고문헌 11]</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>한편, ciphertext (u, v)를 전달받아, message m(shared secret)을 구해내는 decapsulation 과정은 u, v 및 secret vector s를 통해 진행된다. 먼저, 전달 받은 ciphertext (u, v)에 대해 decoding과 decompressing을 한 후에 원본 message m을 아래 수식을 통해 구하게 된다.</div><div><br /></div><div><div><div><b>Alice's Dec( )</b></div><div> v - (u x s(t)) = m + [x]</div></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 [x]는 버리거나 올림할 수 있는 작은 값이다. 예를 들어, [3.4] => 버림 => [3], [3.6] => 올림 => [4] ...</span></div></div><div><br /></div><div>아래 그림은 v - (u x ) = m + [x]의 수식의 원리를 설명해 주는 그림이다. 앞서 Bos's Enc( )에서 언급했던 수식을 참조하여 계산해 보면, u와 v의 관계가 설명될 줄로 믿는다. 😋</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju7_dD2_gq-bqn2txSFU2_sCypY_OQixppozVwmjJ9uMEjmhtQ_wyrnV51b2hvTGuPQ36_eI4I7hey4FiaoUrBEpruXawWcDFMQbLPC5CTCazWZIuuce4GGgo9mGbi9GL1NAYLwmrgqlXoAgWawUodnJh_9MFPUdeKqv7kvvgYHOYaFuNpY0RrTZPb-A/s638/pqc_kem2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="638" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju7_dD2_gq-bqn2txSFU2_sCypY_OQixppozVwmjJ9uMEjmhtQ_wyrnV51b2hvTGuPQ36_eI4I7hey4FiaoUrBEpruXawWcDFMQbLPC5CTCazWZIuuce4GGgo9mGbi9GL1NAYLwmrgqlXoAgWawUodnJh_9MFPUdeKqv7kvvgYHOYaFuNpY0RrTZPb-A/w640-h301/pqc_kem2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.9] CRYSTALS Kyber Decapsulation 과정 중, u, v의 관계 [출처 - 참고문헌 12]</span></div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 위의 그림에서 t는 pk(public key)이다. 서로 다른 문서에서 발췌하다 보니 수식의 변수명이 좀 다르다.</span><br /><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi4QiI2b_kgEq_71BCpFT2Ly4mxESrVYoAKd6rlwpr_XrXVKFPq590SM42-CUB03vqcbgKxjSL970AfnAiESbmcEwgpQuZce539NUEBNDQiOos5OHaxvBxVpZ4eSsn8Iy8_QZyqlPXppd7JnSSV1L0OhV3RX9SEcJUizlmqU_4SUT8eF43JXVvCwiCeg/s430/kyber_decrpyt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="120" data-original-width="430" height="89" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi4QiI2b_kgEq_71BCpFT2Ly4mxESrVYoAKd6rlwpr_XrXVKFPq590SM42-CUB03vqcbgKxjSL970AfnAiESbmcEwgpQuZce539NUEBNDQiOos5OHaxvBxVpZ4eSsn8Iy8_QZyqlPXppd7JnSSV1L0OhV3RX9SEcJUizlmqU_4SUT8eF43JXVvCwiCeg/s320/kyber_decrpyt.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.10] CRYSTALS Kyber <b>Decapsulation 과정</b>[출처 - 참고문헌 11]</span></div><div><br /></div><div>이상으로 조금은 난해하지만, CRYSTALS Kyber의 세부 동작 원리를 파악해 보았다. 설명이 부족한 부분에 대해서는 앞서 제시한 논문을 꼼꼼히 읽어 보기를 권한다. <span style="color: #38761d;">공돌이가 수학을 이해하려니 조금 힘에 부친다. </span>😓</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b><span style="color: #0b5394; font-size: x-large;">5. NanoPi R4S 용 Quantum Safe WireGuard 구현하기</span></b><br /><span style="font-family: Nunito;">이번 장에서는 CRYSTALS Kyber KEM을 WireGuard에 접목시키는 내용을 소개해 보고자 한다. 이 장에서 소개하는 내용은 아래 PQ-WireGuard 논문에서 영감을 받긴 했으나, 접근 방법을 좀 달리 하고자 하였다.</span></div><div style="text-align: center;"><a href="https://eprint.iacr.org/2020/379.pdf" style="background-color: white; color: #992211; font-family: "Noto Sans CJK KR"; font-size: 14.85px; text-decoration-line: none;">https://eprint.iacr.org/2020/379.pdf</a></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><b>WireGuard Protocol(NoiseIK) + CRYSTALS Kyber KEM</b></span></div><div><br /></div><div><b><span style="color: #38761d; font-size: large;">a) WireGuard에 Kyber KEM 추가하기</span></b></div><div>Wireguard에 CRYSTALS Kyber 알고리즘 적용 시, NoiseIK 프로토콜이 일부 변형될지라도, 속도 저하가 없는 방법이 필요하다. 아래 세 장의 그림은 CRYSTALS Kyber를 WireGuard Protocol에 녹이는 내용(idea)을 정리해 본 것이다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Noise Handshaking 중에 속도 저하가 발생하지 않도록 하기 위해서는 반드시 Initiation message와 Response message가 1번씩만 전송되도록 설계되어야 한다.</span><br /><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGEqcMkrl1QgiLL0IDn7Z0DT4DBRQGANhsOgU2cPFzjZw9y0j8fDmOXC0mX24QkGZY6g6roKpvHidvnguHZNrQ1gNj2Mml1TatD6no1MGDnFXz6P5WABzOEmhLc2Pm_U8AtzbZ-x09czA8lYn0J8VfD25kRKNiTMEs7GqibeUnVPiUVOS7T-mpGz8vdA/s1078/quantum_safe_wireguard1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="529" data-original-width="1078" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGEqcMkrl1QgiLL0IDn7Z0DT4DBRQGANhsOgU2cPFzjZw9y0j8fDmOXC0mX24QkGZY6g6roKpvHidvnguHZNrQ1gNj2Mml1TatD6no1MGDnFXz6P5WABzOEmhLc2Pm_U8AtzbZ-x09czA8lYn0J8VfD25kRKNiTMEs7GqibeUnVPiUVOS7T-mpGz8vdA/w640-h314/quantum_safe_wireguard1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.1] Quantum Safe WireGuard Protocol(1) - Kyber KEM 과정 추가</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1iL6rA_WmfwWUBi0Ox0Q5KvmPbuPC2y4TWGpk1CSsIe9RGs4Dx9HS-D9YjcWfuhcaJCCk4Rgd782AHLksLjwkChjz-j8TLEUb9F5qoB1L8NHI58-s4kd5dPBlQAtDsnceApY4qArv7M9GYpdXYapwCUAGVMtqvk2_LDev02yiZohPy2OXowDwM6YBDw/s1030/quantum_safe_wireguard2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="515" data-original-width="1030" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1iL6rA_WmfwWUBi0Ox0Q5KvmPbuPC2y4TWGpk1CSsIe9RGs4Dx9HS-D9YjcWfuhcaJCCk4Rgd782AHLksLjwkChjz-j8TLEUb9F5qoB1L8NHI58-s4kd5dPBlQAtDsnceApY4qArv7M9GYpdXYapwCUAGVMtqvk2_LDev02yiZohPy2OXowDwM6YBDw/w640-h320/quantum_safe_wireguard2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.2] Quantum Safe WireGuard Protocol(2) - Handshake 메시지 변경</span></div><div><br /></div><div>Kyber768의 public key size는 1184 bytes이고, ciphertext size는 1088 bytes이다. WireGuard의 Initiation Message의 size가 148 bytes, Response Message의 size가 92 bytes인 점을 감안할 때, 아무리 커져도 1332 bytes를 넘지 못하게 되고, 이 크기는 wireguard MTU 1420을 초과하지 않으므로, Initiation message와 Reponse message는 1번씩만 전송되게 된다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk3R7tlvOFOqSzx8yhmuVFSm21MPSWamVE-hz-39f2h66J9o4TH1sQ1adHCIRZoDzz6D0HpB3Z1ozP7KusRQ8SYVLG0TOyIaP4177ofgU0wJv5ByyvGFHKY0q2exQJNLpSHE5OhLXnaPyCcRsujhf_U1P90Ws6G_zFt5tq34RL8MteNiLFfmDly1wsvA/s1150/improved_noiseik.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="545" data-original-width="1150" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhk3R7tlvOFOqSzx8yhmuVFSm21MPSWamVE-hz-39f2h66J9o4TH1sQ1adHCIRZoDzz6D0HpB3Z1ozP7KusRQ8SYVLG0TOyIaP4177ofgU0wJv5ByyvGFHKY0q2exQJNLpSHE5OhLXnaPyCcRsujhf_U1P90Ws6G_zFt5tq34RL8MteNiLFfmDly1wsvA/w640-h304/improved_noiseik.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.3] Quantum Safe WireGuard Protocol(3) - Noise Protocol 변경</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><b><span style="color: red;">CRYSYALS Kyber KEM을 통해 획득한 shared secret은 NoiseIK(4번의 ECDH)를 통해 획득한 shared secret과 최종적으로 HKDF 함수(Blake2s 기반 hash 함수 사용)를 통해 다시한번 mix 되게 된다.</span></b> 이는 Kyber를 통해 획득한 shared secret을 양자 computer로도 알아낼 방법이 없기 때문에, Post Quantum 시대에도 안전하다고 말할 수 있겠다. 이름하여 <b>Hybrid WireGuard</b>(= Quantum Safe WireGuard)~✌</div><div class="separator" style="clear: both; text-align: justify;"><br /></div><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #ff00fe;">Final Shared Secret = HKDF(NoiseIK result, Kyber KEM result)</span></b></div><div><br /></div><div><div><b><span style="color: #38761d; font-size: large;">b) Porting 절차 요약</span></b></div><div>Wireguard에 CRYSTALS Kyber KEM을 적용하기 위해 필요한 porting 절차를 정리해 보기로 한다. Porting을 위해 사용한 code는 PQClean이 되겠다.</div></div><div style="text-align: center;"><a href="https://github.com/PQClean/PQClean">https://github.com/PQClean/PQClean</a>/crypto_kem/kyber768/clean</div><div><br /></div><div><b><porting 절차></b></div><div>1) cd drivers/net/wireguard</div><div>2) Makefile을 수정하여 아래 내용을 추가한다.</div><div><div><i><span style="font-size: x-small;">ccflags-y += -O3 -fvisibility=hidden</span></i></div><div><i><span style="font-size: x-small;">ccflags-y += -Wframe-larger-than=2048</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/cbd.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/fips202.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/indcpa.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/kem.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/ntt.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/poly.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/polyvec.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/reduce.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/symmetric-shake.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/verify.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/clean/kex.o</span></i></div></div><div><br /></div><div>3) userspace용 C header를 제거하고, kernel header로 교체한다.</div><div><i><span style="font-size: x-small;">#include <stdint.h> => #include <linux/types.h></span></i></div><div><i><span style="font-size: x-small;">#include <stddef.h></span></i></div><div><i><span style="font-size: x-small;">#include <string.h> => #include <linux/string.h></span></i></div><div><br /></div><div>4) fips202.[ch] 파일을 common에서 복사해 온다. malloc/free code를 kmalloc/kfree code로 전환한다. exit 함수를 제거한다.</div><div><br /></div><div>5) randombytes.h 파일을 common에서 복사해 온다. </div><div><br /></div><div>6) [중요] local buffer size가 큰 경우, array 관련 코드를 kmalloc 등으로 교체한다. 이 작업을 안할 경우 system이 그냥 뻗어 버린다.</div><div> - stack buffer size 2048 이상의 경우 kmalloc으로 교체 검토</div><div> - indcpa.c의 keypair, enc, dec 3개 함수 polyvec, poly 부분 kmalloc으로 전환</div><div> - 아래 header를 추가한다.</div><div><div><i><span style="font-size: x-small;">#include <linux/gfp.h></span></i></div><div><i><span style="font-size: x-small;">#include <linux/slab.h></span></i></div><div><i><span style="font-size: x-small;">#include <linux/mm.h></span></i></div></div><div><br /></div><div>7) 기타 compile을 하면서 자잔한 warning & error를 수정해 나간다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 참고: linux kernel은 C90 compiler를 기본으로 하고 있기 때문에 C99 기반의 코드 사용시 error가 발생하니 주의한다.</span></div><div><br /></div><div>8) message.h를 수정하여 kyber public key와 ciphertext를 message에 포함시킨다.</div><div><br /></div><div>9) noise.[ch] 파일일 수정하여, [그림 5.3]의 내용을 구현한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmQgjCkPomsZPCH6VDy4cPxFWHLGt8z0USTIZgOPBf-LhGqK_L_OR5VOJlltaAb6ngj6rlI1hlvOJwhEOPQKbFEPmRc7dSG_h6hyAqOhtQ2oS-RT0xk9e2m4CXzJdmMdTTVuUqBBkPGCnWapMt5xcdbgmUTO0hy86BwdDNc6N7MQu-s8leJ_vm_v7mQLCH/s960/noise_ik_handshake_initiation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="597" data-original-width="960" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmQgjCkPomsZPCH6VDy4cPxFWHLGt8z0USTIZgOPBf-LhGqK_L_OR5VOJlltaAb6ngj6rlI1hlvOJwhEOPQKbFEPmRc7dSG_h6hyAqOhtQ2oS-RT0xk9e2m4CXzJdmMdTTVuUqBBkPGCnWapMt5xcdbgmUTO0hy86BwdDNc6N7MQu-s8leJ_vm_v7mQLCH/w400-h249/noise_ik_handshake_initiation.png" width="400" /></a></div><div><br /></div><div><br /></div><div><b><span style="color: #38761d; font-size: large;">c) 2대의 Nano Pi간 동작 시험</span></b></div><div>지금까지 작업한 내용을 아래와 같이 NanoPi 2대에 적용하여, Quantum Safe WireGuard가 정상 동작하는지를 확인해 보도록 한다.</div><div><br /></div><div>$<b> export ARCH=arm64</b></div><div><div>$ <b>export CROSS_COMPILE=aarch64-linux-gnu-</b></div><div>$<b> export PATH=/opt/FriendlyARM/toolchain/11.3-aarch64/bin:$PATH</b></div><div>$ <b>export CC=aarch64-linux-gnu-gcc</b></div><div>$<b> export LD=aarch64-linux-gnu-ld</b></div><div><b><br /></b></div><div>$<b> cd kernel</b></div><div>$<b> make nanopi4_linux_defconfig</b></div><div>$ <b>make menuconfig</b></div><div>$<b> make -j8</b></div></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 kernel/drivers/net/wireguard/wireguard.ko 파일을 target board로 복사한다.</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqxu2VL2qGR--UGnZ6hX1t4ggUxCLH7BQB0SJHtP_q_4S5hXtgzx5ApdaFrnjPtDI8cKWJ1cpAU6fTfIOF6tcX2cYRwTHbDxkTabLhzJDUC0mqtMxiCfwID4YfBeO2-S6M244L1Cxv-c2Kgzv9rAdDLyEvb82rA7e4yRMjNESDNBQvaAi_Qdl0MKbh9w/s4000/20230218_163614.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4000" data-original-width="3000" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqxu2VL2qGR--UGnZ6hX1t4ggUxCLH7BQB0SJHtP_q_4S5hXtgzx5ApdaFrnjPtDI8cKWJ1cpAU6fTfIOF6tcX2cYRwTHbDxkTabLhzJDUC0mqtMxiCfwID4YfBeO2-S6M244L1Cxv-c2Kgzv9rAdDLyEvb82rA7e4yRMjNESDNBQvaAi_Qdl0MKbh9w/s320/20230218_163614.jpg" width="240" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.4] Nano Pi 2개로 구성된 Quantum Safe WireGuard 테스트베드</span></div><div style="font-family: "Noto Sans CJK KR";"><span><span><br /></span></span></div><div><span><span><div><b><NanoPi 1 설정></b></div><div>Nano Pi 1의 wireguard 설정 및 ping 시험 결과는 다음과 같다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 wireguard 설정을 하기 위해서는 먼저 wireguard-tools를 설치해야 한다</span></div><div><span style="background-color: white; font-size: 14.85px;"><span style="color: #b45f06;"># opkg update</span></span></div><div><span style="background-color: white; font-size: 14.85px;"><span style="color: #b45f06;"># opkg install wireguard-tools</span></span></div><div><span style="background-color: white; font-size: 14.85px;"><span style="color: #b45f06;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Dh7UV-QKZTk09mRs1b3YcWQ9xEj9bY0ZNIIABloDkXpIiLaSBP77_o2dg6RhnApqvP3ePp18HEEALgcb4tE689WIziZzXlVEWPG4-iqjL-TUCNJeQpNZgWSkk4jpWxPH66DoP1VFcp2g5HM2-PaJbn68uCCb2k__C8iHcnOYpTinxxa2NTF-baCEqw/s873/nanopi1_quantum_safe_wg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="867" data-original-width="873" height="398" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_Dh7UV-QKZTk09mRs1b3YcWQ9xEj9bY0ZNIIABloDkXpIiLaSBP77_o2dg6RhnApqvP3ePp18HEEALgcb4tE689WIziZzXlVEWPG4-iqjL-TUCNJeQpNZgWSkk4jpWxPH66DoP1VFcp2g5HM2-PaJbn68uCCb2k__C8iHcnOYpTinxxa2NTF-baCEqw/w400-h398/nanopi1_quantum_safe_wg.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.5] Nano Pi 1의 wireguard 설정 및 ping 결과</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Handshake message format 및 noise protocol만 일부 변경되었기 때문에, 나머지 설정 부분은 기존과 동일하다. 뿐만 아니라 이후 암호화(ChaCha20Poly1305 AEAD) 처리는 기존과 그대로다(즉, 속도 저하가 전혀 없다).</span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><div style="color: black; font-size: 14.85px;">root@FriendlyWrt:~/workspace# <b>lsmod |grep wireguard </b> </div><div style="color: black; font-size: 14.85px;"><span style="font-size: 14.85px;">wireguard 114688 0</span></div><div style="color: black; font-size: 14.85px;">libchacha20poly1305 16384 1 wireguard</div><div style="color: black; font-size: 14.85px;">libcurve25519_generic 40960 1 wireguard</div><div style="color: black; font-size: 14.85px;">udp_tunnel 24576 2 l2tp_core,wireguard</div><div style="color: black; font-size: 14.85px;"><span style="font-size: 14.85px;">ip6_udp_tunnel 16384 2 l2tp_core,wireguard</span> </div><div style="color: black; font-size: 14.85px;"><br /></div></span></div><div><span style="background-color: white; font-size: 14.85px;"><div>root@FriendlyWrt:~/workspace#<b> rmmod wireguard</b></div><div> <span style="font-size: 14.85px;"> </span></div><div>root@FriendlyWrt:~/workspace#<b> insmod /root/workspace/wireguard.ko </b></div><div>[ 6753.266363] wireguard: WireGuard 1.0.0 loaded. See www.wireguard.com for information.</div><div>[ 6753.267079] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.</div><div>[ 6753.267921] wireguard: <span style="color: #ffa400;">PQC(Kyber768 KEM) for WireGuard NoiseIK is ready.</span></div><div><br /></div><div>root@FriendlyWrt:~/workspace# </div><div>root@FriendlyWrt:~/workspace# <b>lsmod |grep wireguard</b></div><div>wireguard 114688 0</div><div>libchacha20poly1305 16384 1 wireguard</div><div>libcurve25519_generic 40960 1 wireguard</div><div>udp_tunnel 24576 2 l2tp_core,wireguard</div><div>ip6_udp_tunnel 16384 2 l2tp_core,wireguard</div></span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div><b><NanoPi 2 설정></b></div><div>한편, Nano Pi 2의 wireguard 설정 및 ping 시험 결과는 다음과 같다.</div></span></span></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH03gIaZcwF3TxVUZatcYh9T73MqAMdLVVDiOcxMRba-2rVEGO4VZWAcoN8cj9JfvZlReegwhZv4CrgSst56Ezhz2YyYlG7GNdGqoxnWq0ml4t861UUkUBcA1lm6FAp56hbwNkY7pYjYCrfhwDpiNbBvz0aakJRi167Amfr_E7U6l5yTKC8CB-ASsvbg/s911/nanopi2_quantum_safe_wg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="837" data-original-width="911" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH03gIaZcwF3TxVUZatcYh9T73MqAMdLVVDiOcxMRba-2rVEGO4VZWAcoN8cj9JfvZlReegwhZv4CrgSst56Ezhz2YyYlG7GNdGqoxnWq0ml4t861UUkUBcA1lm6FAp56hbwNkY7pYjYCrfhwDpiNbBvz0aakJRi167Amfr_E7U6l5yTKC8CB-ASsvbg/w400-h368/nanopi2_quantum_safe_wg.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.6] Nano Pi 2의 wireguard 설정 및 ping 결과</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">OK, 정상적으로 동작한다. Great~ 😎</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div style="font-family: "Noto Sans CJK KR";"><p><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">6. Alpine Linux 용 </span></b><b style="font-family: Nunito;"><span style="color: #0b5394; font-size: x-large;">Quantum Safe </span></b><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">WireGuard 구현하기</span></b></p></div><div>이번 장에서는 아주 작고(lightweight), 안전한(secure) linux로 알려진 <a href="https://www.alpinelinux.org/">Alpine linux </a>kernel에 Quantum Safe WireGuard를 올리는 과정을 소개해 보고자 한다. 🏂</div><div><span><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguzruBISnZQmM2Y7RO6SyLjQhUG_1LKp-ZJj0RWxCXYycRS8XrDQoXmyKr_L_gYNK1SSa5EZULDzb-D_k8XVeHhI8ZLsw6b2llu_6JqEC0eTVR7OFL2sTTa3CVPvWqcr2qjJAdNaSsv9VCbaWvXf95RQT8QekyJDctZlrTPViGsc2RURgPi_296fFX1A/s349/pq_wireguard.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="49" data-original-width="349" height="45" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguzruBISnZQmM2Y7RO6SyLjQhUG_1LKp-ZJj0RWxCXYycRS8XrDQoXmyKr_L_gYNK1SSa5EZULDzb-D_k8XVeHhI8ZLsw6b2llu_6JqEC0eTVR7OFL2sTTa3CVPvWqcr2qjJAdNaSsv9VCbaWvXf95RQT8QekyJDctZlrTPViGsc2RURgPi_296fFX1A/s320/pq_wireguard.png" width="320" /></span></a></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd51JsE3qN9dMS_6bCVwbSjI_XBt8hidjgwq6Tg1wh0JNr0RwWy-0ZlUXN9a3gJFA8wM18KIPLsP3You6Ticksl9So9GOwDvZumzUEtZ42ybTW4hVvFU-KTfUqhBez7xaQVJQcam_Dbd0ADMBKjywvqVwIqZi67eUi6a784PHPPf6TElm1FN0OJhqoNw/s1280/Alpine_Linux.svg.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><br /><img border="0" data-original-height="312" data-original-width="1280" height="98" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd51JsE3qN9dMS_6bCVwbSjI_XBt8hidjgwq6Tg1wh0JNr0RwWy-0ZlUXN9a3gJFA8wM18KIPLsP3You6Ticksl9So9GOwDvZumzUEtZ42ybTW4hVvFU-KTfUqhBez7xaQVJQcam_Dbd0ADMBKjywvqVwIqZi67eUi6a784PHPPf6TElm1FN0OJhqoNw/w400-h98/Alpine_Linux.svg.png" width="400" /></span></a></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 6.1] Alpine Linux Logo</span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><br /><span style="color: #38761d; font-family: Nunito; font-size: large;"><b>a) Alpine Linux 소개<br /></b></span><span style="font-family: Nunito;">아주 오래 전(Long long ago 호랑이 담배 피던 시절에~ 😓)에 LEAF(Linux Embedded Appliance Framework)라는 project를 이용하여 Linux Router를 개발했던 적이 있다. 최근 들어 LEAF로 network 장비를 만들어 볼까 하는 마음에 다시 찾던 중, LEAF는 없어지고 그 후예(fork)로 Alpine linux가 있다는 사실을 알게 되었다.</span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="color: #38761d; font-family: Nunito; font-size: large;"><b>b) Alpine Linux kernel build하기<br /></b></span><span style="font-family: Nunito;">이번 장에서는 Alpine Linux가 이미 설치되어 있는 서버(</span><span style="font-family: Nunito;">Intel CPU)</span><span style="font-family: Nunito;">상에서 alpine linux kernel을 build하는 절차를 소개하고자 한다.<br /></span><span><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white; font-size: 14.85px;">📌 </span>Alpine linux는 경량한 구조 덕분에 docker에 올라가는 OS로도 널리 알려져 있다. 따라서 아래 제시하는 내용은 Ubuntu PC에 Docker를 설치하고, 다시 docker 내에 Alpine linux를 설치한 후 테스트해 보아도 동일한 결과를 얻을 수 있다. 실제로 필자는 이와 같은 환경에서 개발을 하긴한다. 하지만, kernel build 속도가 아무래도 신경이 쓰이기 때문에 오늘은 실제 server에서 build하는 형태로 접근해 보자.</span></span></div><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="color: #990000; font-family: Nunito; font-size: medium;"><b>1) Kernel build 전 준비 작업(주요 패키지 설치)</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="background-color: white; color: #b45f06; font-size: 14.85px; white-space: normal;">📌 </span><span style="color: #b45f06; white-space: normal;">Alpine linux를 설치하는 내용은 다루지 않는다. 따라서 아래 내용은 이미 Alpine linux가 설치되었다고 가정하고 진행하도록 한다.</span></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><b><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sudo </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">apk update</span></b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><b><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sudo </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">apk upgrade</span></b></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span id="docs-internal-guid-f3744832-7fff-51f0-6b28-5c1130dc960c"><span style="font-family: Nunito;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ <b>sudo </b></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><b>apk add vim alpine-sdk</b></span></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/ # </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">visudo /etc/sudoers</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">## </span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">## User privilege specification </span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">##</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">root ALL=(ALL) ALL</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><b>chyi ALL=(ALL) ALL </b> //사용하는 계정을 등록한다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><span id="docs-internal-guid-4f19c3a3-7fff-e758-1a88-de2d1d4f7273"></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">...</span></span></p><div style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><br /></div><div style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo vi /etc/abuild.conf<br /></span></span><span style="background-color: white; color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">PACKAGER 부분을 자신의 정보로 수정한다.</span></span><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="background-color: white; color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">...</span></span></div><div style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="background-color: white; white-space: pre-wrap;">PACKAGER="Chunghan.Yi <chunghan.yi@gmail.com>"</span></div><div style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="background-color: white; white-space: pre-wrap;">MAINTAINER="$PACKAGER"</span></div><div style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="background-color: white; white-space: pre-wrap;">...</span></div><div style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="background-color: white; white-space: pre-wrap;"><br /></span></div><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo addgroup chyi abuild</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: #e69138; font-family: Nunito;"><span style="white-space: pre-wrap;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span>group 추가 내용이 반영되려면, logout 후 재 login해 주어야 한다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="white-space: pre-wrap;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild-keygen -a -i</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> Generating public/private rsa key pair for abuild</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito; font-size: x-small;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Enter file in which to save the key [/home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa]: </span><span style="color: #f1c232; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><Enter></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">Generating RSA private key, 2048 bit long modulus (2 primes)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">......+++++</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">......................................................................+++++</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">e is 65537 (0x010001)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">writing RSA key</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> Installing /home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa.pub to /etc/apk/keys...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> </span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> Please remember to make a safe backup of your private key:</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> /home/chyi/.abuild/chunghan.yi@gmail.com-61331fa6.rsa</span></span></p><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="color: #990000; font-size: medium; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><b style="font-family: Nunito; white-space: normal;">2) Kernel build 하기 1 - 한번에 build 하기</b></span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;">$</span><span style="font-family: Nunito;"> </span><b style="font-family: Nunito;">git clone https://github.com/alpinelinux/aports</b></div><div style="-webkit-text-stroke-width: 0px; font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito; font-size: medium;">$ cd aports<br /></span><span style="font-family: Nunito; font-size: medium;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">ls -la<br /></span></span><span style="font-size: x-small;"><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">total 344<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 12 chyi chyi 4096 Sep 4 07:19 .<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 3 chyi chyi 4096 Sep 4 07:16 ..<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 1631 Sep 4 07:19 .drone.yml<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 371 Sep 4 07:19 .editorconfig<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 8 chyi chyi 4096 Sep 4 07:19 .git<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .githookssudo<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .github<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 105 Sep 4 07:19 .gitignore<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 .gitlab<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 2101 Sep 4 07:19 .gitlab-ci.yml<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 1115 Sep 4 07:19 .mailmap<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 5973 Sep 4 07:19 CODINGSTYLE.md<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 5821 Sep 4 07:19 COMMITSTYLE.md<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 881 Sep 4 07:19 README.md<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 4047 chyi chyi 135168 Sep 4 07:19 community<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 1530 chyi chyi 49152 Sep 4 07:19 main<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 21 chyi chyi 4096 Sep 4 07:19 non-free<br /></span></span><span style="color: black; font-family: "Noto Sans CJK KR"; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 4 07:19 scripts<br /></span></span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2318 chyi chyi 69632 Sep 4 07:19 testing<br /></span></span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 261 chyi chyi 12288 Sep 4 07:19 unmaintained</span></span></span></div><div style="-webkit-text-stroke-width: 0px; font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></div><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">cd ~/aports/main/linux-lts</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span id="docs-internal-guid-3fc12484-7fff-9797-99f6-eb551f25e9d9"><span style="font-family: Nunito;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild -r</span></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">abuild는 현재 디렉토리에 있는 APKBUILD 파일을 이용하여 build를 진행한다. -r option을 줄 경우, source download & patch 부터 kernel build 후 package 생성까지를 모두 처리한다. Build가 끝난 후에는 build 과정에서 생성한 src/ 디렉토리를 통째로 날려 버린다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><span id="docs-internal-guid-bf9089b2-7fff-0c2f-5f8c-4fbcf5dce3e2"></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;"><a href="https://wiki.alpinelinux.org/wiki/APKBUILD_Reference" style="text-decoration-line: none;"><span style="color: #1155cc; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">https://wiki.alpinelinux.org/wiki/APKBUILD_Reference</span></span></a></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Building main/linux-lts 5.10.61-r0 (using abuild 3.8.0_rc4-r0) started Sat, 04 Sep 2021 08:25:02 +0000</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Checking sanity of /home/chyi/aports/main/linux-lts/APKBUILD...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Analyzing dependencies...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Installing for build: build-base mkinitfs perl gmp-dev elfutils-dev bash flex bison sed installkernel bc linux-headers linux-firmware-any openssl-dev diffutils findutils</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">WARNING: Ignoring /home/chyi/packages//main: No such file or directory</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(1/128) Installing lddtree (1.26-r2)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(2/128) Installing xz-libs (5.2.5-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(3/128) Installing zstd-libs (1.4.9-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(4/128) Installing kmod (29-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(5/128) Installing libblkid (2.37-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(6/128) Installing argon2-libs (20190702-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(7/128) Installing device-mapper-libs (2.02.187-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(8/128) Installing json-c (0.15-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(9/128) Installing libuuid (2.37-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(10/128) Installing cryptsetup-libs (2.3.6-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(11/128) Installing kmod-libs (29-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(12/128) Installing mkinitfs (3.5.0-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">Executing mkinitfs-3.5.0-r0.post-install</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(13/128) Installing libbz2 (1.0.8-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(14/128) Installing perl (5.32.1-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(15/128) Installing libgmpxx (6.2.1-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(16/128) Installing gmp-dev (6.2.1-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(17/128) Installing fts (1.2.7-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(18/128) Installing libelf (0.182-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(19/128) Installing xz-dev (5.2.5-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(20/128) Installing zlib-dev (1.2.11-r3)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(21/128) Installing elfutils-dev (0.182-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(22/128) Installing readline (8.1.0-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(23/128) Installing bash (5.1.4-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">Executing bash-5.1.4-r0.post-install</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(24/128) Installing m4 (1.4.18-r2)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(25/128) Installing flex (2.6.4-r2)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(26/128) Installing bison (3.7.6-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(27/128) Installing sed (4.8-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(116/128) Purging kmod-libs (29-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(117/128) Purging xz-libs (5.2.5-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(118/128) Purging zstd-libs (1.4.9-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(119/128) Purging cryptsetup-libs (2.3.6-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(120/128) Purging libblkid (2.37-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(121/128) Purging argon2-libs (20190702-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(122/128) Purging device-mapper-libs (2.02.187-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(123/128) Purging json-c (0.15-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(124/128) Purging libuuid (2.37-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(125/128) Purging libbz2 (1.0.8-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(126/128) Purging fts (1.2.7-r1)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(127/128) Purging zlib-dev (1.2.11-r3)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">(128/128) Purging readline (8.1.0-r0)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">Executing busybox-1.33.1-r3.trigger</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">OK: 233 MiB in 58 packages</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Updating the main/x86_64 repository index...</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Signing the index...</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><span id="docs-internal-guid-b3a73f3f-7fff-8418-7b36-1183649ea54a"></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">Build 결과는 ~/packages 디렉토리에 자동으로 생성된다.</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ <b>cd ~/packages/</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ ls -la</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">total 12</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 .</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 7 pufbox pufbox 4096 Jan 30 20:09 ..</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 main</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ <b>cd main/</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ ls -la</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">total 12</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 .</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 ..</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 2 pufbox pufbox 4096 Jan 30 20:09 x86_64</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ <b>cd x86_64/</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">$ ls -la</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">total 93356</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 2 pufbox pufbox 4096 Jan 30 20:09 .</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">drwxr-sr-x 3 pufbox pufbox 4096 Jan 30 20:09 ..</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">-rw-r--r-- 1 pufbox pufbox 904 Jan 30 20:09 APKINDEX.tar.gz</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">-rw-r--r-- 1 pufbox pufbox 74925531 Jan 30 20:09 <b>linux-lts-5.15.24-r0.apk</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;">-rw-r--r-- 1 pufbox pufbox 20655011 Jan 30 20:09 <b>linux-lts-dev-5.15.24-r0.apk</b></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: #e69138;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 </span>최종 build 결과물은 apk(zip 파일) 파일 형태로 생성된다.</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><br /></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><b style="font-family: Nunito;"><span style="color: #990000; font-size: medium;">3) Kernel build 하기 2 - 단계별 build 하기</span></b></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">APKBUILD를 사용할 경우 맨 마지막에 cleaup( ) 과정을 거치게 되므로, build를 위해 download한 source code가 자동 삭제되는 문제가 있다. 앞으로 WireGuard source code를 자유롭게 compile하려면 kernel source를 삭제해서는 안된다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;"><span style="color: #e69138; font-family: Nunito;"><span style="white-space: pre-wrap;"><span style="background-color: white; color: #b45f06; font-size: 14.85px; text-align: left;">📌 </span>아래 내용 중 linux kernel version이 약간씩 다르게(linux-5.10 or linux-5.15) 기술된 부분이 있는데, 이는 정리한 내용의 시간 차에 기인한 것이므로 양해를 바란다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><APKBUILD 과정></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.56; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">sanitycheck() -> clean()-> fetch() -> verify() -> unpack() -> prepare() -> mkusers() -> build() -> check() -> package() -> subpackages() -> language packs -> apk -> cleanup()</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">지금 부터는 이 방법을 소개해 보고자 한다. </span></span><span style="font-family: Nunito; white-space: pre-wrap;">먼저 kernel build가 원할히 진행되기 위해서는 몇가지 apk package를 먼저 설치해야 한다.</span></p><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><br /></div><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><b><package 설치></b></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add perl</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add gmp-dev</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add elfutils-dev</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add bash</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add flex</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add bison</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add sed</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add installkernel</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add bc</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add linux-headers</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add linux-firmware-any</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add openssl-dev</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add diffutils</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">sudo apk add findutils</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ APKBUILD 내용 참조 </span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ 이 부분을 생략하면 kernel build가 안되니 반드시 설치하도록 한다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ abuild -r로 full build를 할 경우에는 마지막 단계에서 설치한 package를 uninstall 한다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">아, 그런데 위의 절차가 매우 번거롭다. 이를 한방에 처리할 수는 없을까 ?</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild deps</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ 앞서 한 작업을 대신한다. :)</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild fetch</span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ source code download하여 /var/cache/distfiles 디렉토리에 위치시킨다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ 물론 이미 받아두었다면, 다시 받지는 않는다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Fetching https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.xz</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;"> % Total % Received % Xferd Average Speed Time Time Time Current</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;"> Dload Upload Total Spent Left Speed</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">100 111M 100 111M 0 0 10.9M 0 0:00:10 0:00:10 --:--:-- 11.1M</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">>>> linux-lts: Fetching https://cdn.kernel.org/pub/linux/kernel/v5.x/patch-5.10.61.xz</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;"> % Total % Received % Xferd Average Speed Time Time Time Current</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;"> Dload Upload Total Spent Left Speed</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito; font-size: x-small;">100 1904k 100 1904k 0 0 2450k 0 --:--:-- --:--:-- --:--:-- 2448k</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild verify</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ patch file과 kernel config file에 대한 checksum을 verification하는 단계</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild unpack</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ /var/cache/distfiles/linux-5.10.tar.xz 파일을 src/ 디렉토리 아래에 푼다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild prepare</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ kernel patch 적용 후, kernel .config 까지 생성</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ build-lts.x86_64/.config</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">c3d01af6643e:~/workspace/aports/main/linux-lts$ ls -l src/build-lts.x86_64/.config</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">-rw-r--r-- 1 chyi chyi 224952 Sep 15 05:29 src/build-lts.x86_64/.config</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild build</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ kernel build</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">---------<내부 동작>--------------------------------------------------------------------</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">abuild build를 하면 내부적으로 대략 아래와 같은 일을 수행한다(실제 menuconfig 단계는 수행하지 않음).</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">cd src/linux-5.10</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">make -C ../build-lts.x86_64 </span><span style="color: #b45f06; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">menuconfig</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 339px; overflow: hidden; width: 523px;"><span style="font-family: Nunito;"><img height="339" src="https://lh3.googleusercontent.com/ZBTXFj6ug9_AP4WLpKrIaLQNbanJRtnggCUdrgQx2SF6s2DafCx5eN4nWOErMVYAV8zpkIIwbVDygRReV8rEWFCYiczL5omOuZCTgjqtlHBTZPNr5fzpkLYahN9nIn1VdNxvYbcwX1LIMNv9BYHQKw" style="margin-left: 0px; margin-top: 0px;" width="523" /></span></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">[그림 6.2] linux kernel menuconfig</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">make ARCH=x86_64 CC=gcc KBUILD_BUILD_VERSION=1-Alpine -C ../build-lts.x86_64</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ kernel image 생성하기</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><i><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ (아주 오랜 시간 경과 후) </span></span><span style="font-family: Nunito;"> ../</span><span style="font-family: Nunito;">src/build-lts.x86_64 디렉토리 아래에</span><span style="font-family: Nunito; white-space: pre-wrap;"> vmlinux 파일이 생성된다.</span></i></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="font-family: Nunito; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">make ARCH=x86_64 CC=gcc KBUILD_BUILD_VERSION=1-Alpine -C /home/chyi/workspace/aports/main/linux-lts/src/build-lts.x86_64 </span><span style="color: #b45f06; font-family: Nunito; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">modules</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;"></p><div style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><div><span style="font-family: Nunito;">⇒ kernel module build 하기</span></div></span></div><p style="font-family: "Noto Sans CJK KR"; text-align: left;"></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">----------------------------------------------------------------------------------------</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #e69138;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span>수</span></span><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #e69138;">동으로 Kernel build하는 방법을 알아둘 필요가 있다. 그래야 새로운 kernel module을 추가하거나, kernel code를 수정할 경우 좀 더 편해질 수 있다.</span></span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></p><p style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="white-space: pre-wrap;">__________________________________________</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><여기서 잠깐></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito; white-space: pre-wrap;">실제 linux kernel site에서 download한 kernel source code는 어디에 있을까 ? 실제로 우리가 kernel code를 수정한다면 어디에서 하는게 맞을까 ?</span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><b><span style="font-family: Nunito;"><span style="font-weight: normal;">$ </span>cd /var/cache/distfiles</span></b></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ ls -la</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">total 115896</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxrwxr-x 1 root abuild 4096 Sep 15 01:51 .</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-xr-x 1 root root 4096 Sep 6 01:05 ..</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-rw-r--r-- 1 chyi chyi 116606704 Sep 6 08:11 </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">linux-5.10.tar.xz</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-rw-r--r-- 1 chyi chyi 1950496 Sep 6 08:11 </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">patch-5.10.61.xz</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-xr-x 3 chyi chyi 4096 Sep 9 01:52 src</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito; white-space: pre-wrap;">__________________________________________</span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild rootpkg</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ Kernel과 kernel module이 포함된 package 생성</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">$ ls -la </span></span><span style="font-family: Nunito;"><span style="white-space: pre-wrap;">pkg/</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">total 44</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 10 chyi chyi 4096 Sep 15 02:46 .</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 1 chyi chyi 4096 Sep 15 02:42 ..</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 15 02:48 .control.linux-lts</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">drwxr-sr-x 2 chyi chyi 4096 Sep 15 02:47 .control.linux-lts-dev</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">drwxr-sr-x 5 chyi chyi 4096 Sep 15 02:46 </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">linux-lts</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">drwxr-sr-x 4 chyi chyi 4096 Sep 15 02:43 </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">linux-lts-dev</span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">만일 초기화한 상태에서 처음부터 다시 build를 하고자 한다면, 아래 명령을 수행할 수 있다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild clean</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ linux-tls/src 디렉토리를 통째로 날린다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">abuild cleancache</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">⇒ /var/cache/disfiles 아래에 download해 두었던 kernel & patch source를 모두 삭제한다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-left: 36pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><참고 사항></span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;">abuild 관련 주요 명령 option을 정리해 보면 다음과 같다.</span></span></p><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="color: black; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Nunito;"><br /></span></span></p><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKldjzHFVz-DcYsXKQ1SUG1W3UmrXGzUknT-_OBwmMnzO5hnugsOvOUsFqCsiLiJo01NNvbjNElpQ3JPCN0J4LScX2Px-gjWL2g9J7GWrzDvWasTc3c8MkwRgU4nML4EsJdlbAC__y7x9oacnz9ZiNvVg54Rdi01gQ4eiUdkPCaGc2wy6kHCBWXeQTmA/s867/abuild_usage.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="867" data-original-width="701" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKldjzHFVz-DcYsXKQ1SUG1W3UmrXGzUknT-_OBwmMnzO5hnugsOvOUsFqCsiLiJo01NNvbjNElpQ3JPCN0J4LScX2Px-gjWL2g9J7GWrzDvWasTc3c8MkwRgU4nML4EsJdlbAC__y7x9oacnz9ZiNvVg54Rdi01gQ4eiUdkPCaGc2wy6kHCBWXeQTmA/w324-h400/abuild_usage.png" width="324" /></a></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR"; text-align: center;"><span style="font-family: Nunito; white-space: pre-wrap;">[그림 6.3] </span><span style="font-family: Nunito; text-align: left; white-space: pre-wrap;">abuild 사용법</span></div><p style="font-family: "Noto Sans CJK KR"; line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;"><span style="font-family: Nunito;"><span style="font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #e69138;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 </span>abuild 알면 알수록 꽤 괜찮은 tool이다. Yocto project의 bitbake와 유사하다고나 할까 ...</span></span></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><b style="font-family: Nunito;"><span style="color: #38761d; font-size: large;">c) WireGuard에 Kyber KEM 추가하기</span></b></p><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;">이번 절에서는 5장에서 작업한 내용을 Alpine linux(정확히는 Intel x86_64 server)에 porting하는 과정을 소개하고자 한다. Intel x86_64에서는 AVX2(Avanced Vector eXtentions) 기능이 있다. 자세한 사항은 [참고문헌 13]을 참조하도록 하자.</span></div><div style="text-align: left;">AVX programming에 관해서는 아래 site에 쉽게 정리되어 있으니, 참고하기 바란다.</div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://yunmorning.tistory.com/31">https://yunmorning.tistory.com/31</a></span></div><div style="text-align: left;"><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">나머지 부분은 5장의 내용과 동일하다. pass~ 😜</div><div style="font-family: Nunito;"><br /></div><div><div style="font-family: Nunito;"><div><b><span style="color: #38761d; font-size: large;">d) Porting 절차 요약</span></b></div><div>Wireguard에 CRYSTALS Kyber KEM을 적용하기 위해 필요한 porting 절차를 정리해 보기로 한다. Porting을 위해 사용한 code는 역시 PQClean이 되겠다.</div></div><div style="font-family: Nunito; text-align: center;"><a href="https://github.com/PQClean/PQClean">https://github.com/PQClean/PQClean</a>/crypto_kem/kyber768/avx2</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b><porting 절차></b></div><div style="font-family: Nunito;">1) Makefile을 수정하여 아래 내용을 추가한다.</div><div><div><i><span style="font-size: x-small;">ccflags-y += -O3 -fvisibility=hidden -msse2avx -mavx2 -mbmi2 -mpopcnt</span></i></div><div><i><span style="font-size: x-small;">ccflags-y += -Wframe-larger-than=3072</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/cbd.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/consts.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/fips202.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/sha2.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/fips202x4.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/indcpa.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/kem.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/poly.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/polyvec.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/rejsample.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/symmetric-shake.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/verify.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/kex.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/basemul.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/fq.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/invntt.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/ntt.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/shuffle.o</span></i></div><div><i><span style="font-size: x-small;">wireguard-y += kyber/avx2/keccak4x/KeccakP-1600-times4-SIMD256.o</span></i></div></div><div style="font-family: Nunito;"><div><br /></div></div><div style="font-family: Nunito;">2) userspace용 C header를 제거하고, kernel header로 교체한다.</div><div style="font-family: Nunito;"><i><span style="font-size: x-small;">#include <stdint.h> => #include <linux/types.h></span></i></div><div style="font-family: Nunito;"><i><span style="font-size: x-small;">#include <stddef.h></span></i></div><div style="font-family: Nunito;"><i><span style="font-size: x-small;">#include <string.h> => #include <linux/string.h></span></i></div><div><i><span style="font-size: x-small;"><div>//#include <stdint.h> -> #include <linux/types.h></div><div>//#include <stddef.h></div></span></i></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">3) fips202.[ch] 파일을 common에서 복사해 온다. malloc/free code를 kmalloc/kfree code로 전환한다. exit 함수를 제거한다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">4) sha2.[ch] 파일을 common에서 복사해 온다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">5) randombytes.h 파일을 common에서 복사해 온다. </div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">6) keccak4x/* 파일을 common에서 복사해 온다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><div>7) [중요] #include <immintrin.h> 앞 뒤에 define 문을 추가한다.</div><div>#define _MM_MALLOC_H_INCLUDED</div><div>#include <immintrin.h></div><div>#undef _MM_MALLOC_H_INCLUDED</div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">8) [중요] error: unknown type name 'size_t'</div><div>#include <linux/types.h>를 맨 앞 line으로 이동시킨다.</div><div><br /></div><div>9) restrict 관련 code 제거한다.</div><div><br /></div><div style="font-family: Nunito;">10) [중요] local buffer size가 큰 경우, array 관련 코드를 kmalloc 등으로 교체한다. 이 작업을 안할 경우 system이 그냥 뻗어 버린다.</div><div style="font-family: Nunito;"> - stack buffer size 2048 이상의 경우 kmalloc으로 교체 검토</div><div style="font-family: Nunito;"> - indcpa.c의 keypair, enc, dec 3개 함수 polyvec, poly 부분 kmalloc으로 전환</div><div style="font-family: Nunito;"> - 아래 header를 추가한다.</div><div style="font-family: Nunito;"><div><i><span style="font-size: x-small;">#include <linux/gfp.h></span></i></div><div><i><span style="font-size: x-small;">#include <linux/slab.h></span></i></div><div><i><span style="font-size: x-small;">#include <linux/mm.h></span></i></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">11) 기타 compile을 하면서 자잔한 warning & error를 수정해 나간다.</div><div style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 참고: linux kernel은 C90 compiler를 기본으로 하고 있기 때문에 C99 기반의 코드 사용시 error가 발생하니 주의한다.</span></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">12) message.h를 수정하여 kyber public key와 ciphertext를 message에 포함시킨다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">13) noise.[ch] 파일일 수정하여, [그림 5.3]의 내용을 구현한다.</div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b><span style="color: #38761d; font-size: large;">e) Intel Server와 Nano Pi간 동작 시험</span></b></div><div style="font-family: Nunito; text-align: left;">지금까지 작업한 내용을 아래와 같이 Intel Server에 올리고, 5장에서 구현한 NanoPi와 연동시켜, Quantum Safe WireGuard가 정상 동작하는지를 확인해 보도록 한다.</div><div style="font-family: Nunito; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGvKLOULLcu-yEld8jKIlyFY8BDwlhuFFUVToiF1GHjf1npsgk3toW5PbhIm0H0EAPmPJce4yve0MUXMHGTMzjMBto-_exfMIu-BeE3J7nOAYYavQ-x6vfeXQ_49pZKdPFBapWgFexhqpECx3RNVqYzJcneRVxRl_N858Xawb4i_iyb3DOiJgNzay52uYM/s4000/20211124_134337.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3000" data-original-width="4000" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGvKLOULLcu-yEld8jKIlyFY8BDwlhuFFUVToiF1GHjf1npsgk3toW5PbhIm0H0EAPmPJce4yve0MUXMHGTMzjMBto-_exfMIu-BeE3J7nOAYYavQ-x6vfeXQ_49pZKdPFBapWgFexhqpECx3RNVqYzJcneRVxRl_N858Xawb4i_iyb3DOiJgNzay52uYM/s320/20211124_134337.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left; white-space: pre-wrap;">[그림 6.4] Intel Server</span></div><div style="font-family: Nunito; text-align: left;"><br /></div><div style="font-family: Nunito; text-align: left;"><br /></div><div style="font-family: Nunito; text-align: left;"><b style="background-color: #fff2cc;"><Alpine linux가 탑재된 Intel Server></b></div></div></div><div style="text-align: left;">$ <b>cat start_wg.sh </b></div><div style="text-align: left;">#!/bin/sh<br />#wg genkey | tee ./privatekey | wg pubkey > ./publickey<br />sudo rmmod wireguard<br />sudo insmod avx2/wireguard.ko<br />sudo ip link add dev wg0 type wireguard<br />sudo ip address add dev wg0 10.1.1.5/24<br />sudo ip link set up dev wg0<br />sudo wg set wg0 listen-port 51820 private-key ./privatekey peer 9MXZLGChppVQ3oEcuQHz+axs6sU4sE9FJCn27jGqVQk= allowed-ips 10.1.1.0/24 endpoint 192.168.1.79:51820</div><div style="text-align: left;"><br />$ <b>sudo wg show</b></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div>interface: wg0</div><div> public key: l5C3jiGLBXoMUAVaAU+BbQaukRWJamlHfkBfsADcqhY=</div><div> private key: (hidden)</div><div> listening port: 51820</div><div><br /></div><div>peer: 9MXZLGChppVQ3oEcuQHz+axs6sU4sE9FJCn27jGqVQk=</div><div> endpoint: 192.168.1.79:51820</div><div> allowed ips: 10.1.1.0/24</div><div><br /></div><div><div>$ <b>ping 10.1.1.200</b></div><div>PING 10.1.1.200 (10.1.1.200): 56 data bytes</div><div>64 bytes from 10.1.1.200: seq=0 ttl=42 time=3968.722 ms</div><div>64 bytes from 10.1.1.200: seq=4 ttl=42 time=2.387 ms</div><div>64 bytes from 10.1.1.200: seq=5 ttl=42 time=2.652 ms</div><div>64 bytes from 10.1.1.200: seq=6 ttl=42 time=2.290 ms</div></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;">OK, nano pi 1(10.1.1.200)으로 정상 ping이 된다. Great~ 😎</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div>이상으로 CRYSTALS Kyber 알고리즘을 WireGuard Protocol과 접목하고, 이를 NanoPi R4S 보드와 Intel Server(Alpine linux 탑재)에서 동작시켜 보았다. 끝까지 읽어 주셔서 감사 드리며, 부족한 부분은 (언제나 그렇듯) 다음을 기약해 본다. <b style="background-color: white; color: #333333; font-size: 14.85px;">"May the Source be with You" </b><span style="background-color: white; color: #333333; font-size: 14.85px;">😋</span></div><div><br /></div></div><p style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"></span></p><div style="text-align: left;"><b><TODO></b></div><div style="text-align: left;">1) WireGuard Windows Client에 CRYSTALS Kyber KEM 적용하기</div><div style="text-align: left;">2) WireGuard Android App에 CRYSTALS Kyber KEM 적용하기</div><div style="text-align: left;">3) WireGuard MacOS Client에 CRYSTALS Kyber KEM 적용하기</div></span></div><div>4) AVX2 Kyber code를 AVX512로 변경하기</div><div><span>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span></div><div><br /></div><div style="font-family: "Noto Sans CJK KR";"><span><b><span style="color: #cc0000;"><br /></span><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">7. References</span></b></span><br /><span style="font-family: Nunito;"><b>[1] </b>https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Install_OS</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito; text-align: center;"><b>[2]</b> https://namu.wiki/w/ARM%20big.LITTLE%20%EC%86%94%EB%A3%A8%EC%85%98</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="text-align: center;"><span style="font-family: Nunito;"><b>[3] </b></span></span><span style="font-family: Nunito;">https://www.ubergizmo.com/2013/01/what-is-arm-big-little/</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[4]</b> https://www.wireguard.com/</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[5]</b> Post-quantum WireGuard, </span><span style="font-family: Nunito;">Andreas Hülsing, Kai-Chun Ning, Peter Schwabe, Florian Weber, Philip </span><span style="font-family: Nunito;">R. Zimmermann</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[6]</b> https://sar.informatik.hu-berlin.de/research/publications/SAR-PR-2020-03/SAR-PR-2020-03_.pdf</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[7] </b>https://www.minzkn.com/moniwiki/wiki.php/AboutNetLinkSocket</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><span><b>[8] </b></span><span style="background-color: white;">Master’s Thesis - Analysis of the WireGuard protocol, Peter Wu</span></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="background-color: white;"><span style="font-family: Nunito;"><b>[9] </b></span></span><span style="font-family: Nunito;">https://en.wikipedia.org/wiki/SipHash</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[10] </b>Understanding Linux Network Internals, O'REILLY, Christian Benvenuti</span></div><div><b>[11] </b>Active Implementation of End-to-End Post-Quantum Encryption, Anton Tutoveanu</div><div><b>[12]</b> https://www.youtube.com/watch?v=zsEj28SFyCs&ab_channel=MojtabaBishehNiasar</div><div><b>[13]</b> https://namu.wiki/w/%EA%B3%A0%EA%B8%89%20%EB%B2%A1%ED%84%B0%20%ED%99%95%EC%9E%A5</div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>[14]</b> And Google~</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /><br /><br /><div style="text-align: right;"><b><span style="color: #3d85c6; font-size: large;">Slowboot</span></b></div></span></div></span></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-64180039350764276082023-02-14T20:04:00.008+09:002023-10-01T15:34:45.985+09:00NanoPi R4S로 PQ-Wireguard VPN Router 만들기<div><span style="font-family: Nunito;">이번 시간에는 <a href="https://www.friendlyelec.com/index.php?route=product/product&product_id=284">NanoPi R4S board</a>를 가지고 PQC Wireguard 기반 초소형 VPN router를 만드는 과정을 소개해 보고자 한다. 😎</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzA63CNtMR8tiktuOtwKEZ1DjdyZfbecKlb1uaJT25phs0ntYwy6FbsGW01fvLXa8rZcHpozBFy4bfEN0fcTM4w10VISWwCbweuZ7g0uxI2NzulfpNsNEPqAIhUALC0ANXXAj6ClPMn1U4zWS-qi5jWYmSArfPnz0nH8oeTjO-DPISCV2nyPpBmD9CPQ/s349/pq_wireguard.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="49" data-original-width="349" height="45" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzA63CNtMR8tiktuOtwKEZ1DjdyZfbecKlb1uaJT25phs0ntYwy6FbsGW01fvLXa8rZcHpozBFy4bfEN0fcTM4w10VISWwCbweuZ7g0uxI2NzulfpNsNEPqAIhUALC0ANXXAj6ClPMn1U4zWS-qi5jWYmSArfPnz0nH8oeTjO-DPISCV2nyPpBmD9CPQ/s320/pq_wireguard.png" width="320" /></a></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAKn2egW9GnzX2EMo0z1QHWZ-YY6nmHI9Cu1xLOoAXhbkM75GZ-b3jR8F55NTRr-VU-5E52V8gH5jWzUvwBghHeHMwpV7j229P55TiSqeETjIxcKz_dDv72Fu_1cZv4BbIHpGrRuCHGYxqHLz9TK70ctW_DLK1tpKykc3V1rrWkLpOnoqbfJGpLuVK_Q/s500/NanoPi_R4S-4GB_Front.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="500" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAKn2egW9GnzX2EMo0z1QHWZ-YY6nmHI9Cu1xLOoAXhbkM75GZ-b3jR8F55NTRr-VU-5E52V8gH5jWzUvwBghHeHMwpV7j229P55TiSqeETjIxcKz_dDv72Fu_1cZv4BbIHpGrRuCHGYxqHLz9TK70ctW_DLK1tpKykc3V1rrWkLpOnoqbfJGpLuVK_Q/s320/NanoPi_R4S-4GB_Front.jpg" width="320" /></a></div><span style="font-family: Nunito;">목차<br /><i>1. NanoPi R4S board 소개<br />2. OpenWrt build하기<br />3. WireGuard Kernel 코드 분석하기</i><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><i><span style="color: #9fc5e8;">4. CRYSTALS Kyber PQC 알고리즘 소개</span></i></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><i><span style="color: #9fc5e8;">5. NanoPi R4S 용 Quantum Safe WireGuard 구현하기</span></i></span></div><div style="font-family: "Noto Sans CJK KR";"><i style="font-family: Nunito;"><span style="color: #9fc5e8;">6. Alpine Linux 용 Quantum Safe WireGuard 구현하기</span></i></div></span></div><div><span style="font-family: Nunito;"><i>7. References</i></span></div><div><span style="color: #b45f06; font-family: Nunito;">Keyword: NanoPi R4S, OpenWrt, WireGuard, PQC(Post Quantum Cryptography)</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #ff00fe; font-family: Nunito;"><i>보통은 board 하나를 소개하면서 device tree & device driver 부분을 먼저 언급하는 것이 순서이겠으나, 이번에는 wireguard kernel code 분석 및 PQC 알고리즘 porting에 집중해 보고자 한다.</i></span></div><div><span style="font-family: Nunito;"><br /><b><span style="color: #0b5394; font-size: x-large;">1. NanoPi R4S board 소개</span></b><br />최근에 FriendlyElec사가 개발한 <a href="https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Compile_FriendlyWrt">NanoPi R4S </a>보드를 하나 구입했다. NanoPi R4S의 h/w 스펙을 확인해 보니, 놀랍게도 CPU core가 6개나 되며, ARM big.LITTLE 아키텍쳐를 사용하는 것이 눈길을 끈다.</span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5gAqiiy0p2ZEHNG95AstG68HYPq_B-bmskGU5h4T_zJN-gZ_jTvNAFQwAmXK4XYr6O53co6chIN1ygvmk3KKepceHlNMYH_2tr_HGO9Nib9kbC00X4KDYKqk1mUYdUjqi9QsAI6-kf2IksmlFRz7B1e1NOuIyBAuKtLuEnLUn0iywE9e8R_c4eBd5zg/s500/NanoPi_R4S-1GB_Overview.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="500" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5gAqiiy0p2ZEHNG95AstG68HYPq_B-bmskGU5h4T_zJN-gZ_jTvNAFQwAmXK4XYr6O53co6chIN1ygvmk3KKepceHlNMYH_2tr_HGO9Nib9kbC00X4KDYKqk1mUYdUjqi9QsAI6-kf2IksmlFRz7B1e1NOuIyBAuKtLuEnLUn0iywE9e8R_c4eBd5zg/s320/NanoPi_R4S-1GB_Overview.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.1] NanoPi R4S board(1)</span></div></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_BV0g04pnrbOdGx_5WDlGNg1iQVZjcwTN36nUadr-YPwNy0uBT4iiqMQ5mi4nn0SpNQnH7MZIUa7Ro3WckOBRv6ucUUlGBNSyunGNZweyD58TLvJjVqNUOHDOIttBsPx7tDLiu_Zpj686RdoBhmyifDsBqG_j7mVcBgZhFN1ohbVz_8idyEQ2C2uXPg/s900/NanoPi_R4S_Layout.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="900" data-original-width="750" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_BV0g04pnrbOdGx_5WDlGNg1iQVZjcwTN36nUadr-YPwNy0uBT4iiqMQ5mi4nn0SpNQnH7MZIUa7Ro3WckOBRv6ucUUlGBNSyunGNZweyD58TLvJjVqNUOHDOIttBsPx7tDLiu_Zpj686RdoBhmyifDsBqG_j7mVcBgZhFN1ohbVz_8idyEQ2C2uXPg/w334-h400/NanoPi_R4S_Layout.jpg" width="334" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.2] NanoPi R4S board(2)</span></div><div><br /></div><div style="text-align: center;"><span style="font-family: Nunito; font-size: medium;"><b><span style="color: #45818e;">(big) ARM Cortex-A72(Dual core) + </span><span style="color: #ea9999;">(LITTLE) ARM Cortex-A53(Quad core)</span></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">NanoPi R4S를 선택한 이유는, 지난 시간에 소개한 OrangePi의 경우와 마찬가지로 LAN port가 2개라서 Security Gateway 구성이 가능하기 때문인데, <a href="https://slowbootkernelhacks.blogspot.com/2023/01/orangepi-r1-plus-lts-pqc-wireguard-vpn.html">Orange Pi R1 Plus LTS</a>와는 다르게 2개의 MAC이 장착된 점이 아주 마음에 든다(Cool~). 아래에 </span><span style="font-family: Nunito;">NanoPi R4S의 주요 hardware spec을 옮겨 보았으니, 확인해 보기 바란다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Compile_FriendlyWrt">https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Compile_FriendlyWrt</a></span></div><div><br /></div><div><span style="font-family: Nunito;">___________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><b><NanoPi R4S 보드의 h/w 스펙></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpN0WhlVMmhvyLo1JZztHZUGmmYXnglpxSYpf821rF2HT32883V8OXvLGRiqiuq6yJsyP2wC3b78uuOzJWJ18Al-mBvHOyeE57O0aNjUaSbvzMbSReMI0uj1kmhVnIjkx8x67fzUtVqEjPHTPWN597wyRFev8wbJlZYvjMqNNHFT4HRwmj1erWbt6lgQ/s606/nanopi_r4s_hw_spec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="606" data-original-width="572" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpN0WhlVMmhvyLo1JZztHZUGmmYXnglpxSYpf821rF2HT32883V8OXvLGRiqiuq6yJsyP2wC3b78uuOzJWJ18Al-mBvHOyeE57O0aNjUaSbvzMbSReMI0uj1kmhVnIjkx8x67fzUtVqEjPHTPWN597wyRFev8wbJlZYvjMqNNHFT4HRwmj1erWbt6lgQ/w378-h400/nanopi_r4s_hw_spec.png" width="378" /></a></div><span style="font-family: Nunito;">___________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;"><b><여기서 잠깐></b></span></div><div><span style="color: #b45f06; font-family: Nunito;"><b>ARM big.LITTLE 아키텍쳐란 ?</b></span></div><div><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/ARM%20Holdings" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="ARM Holdings">ARM Holdings</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">에서 개발하는 </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/CPU" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="CPU">CPU</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;"> </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="마이크로아키텍처">마이크로아키텍처</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">인 </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/ARM%20Cortex-A%20%EC%8B%9C%EB%A6%AC%EC%A6%88" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="ARM Cortex-A 시리즈">ARM Cortex-A 시리즈</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">가 시간이 지나면서 점차 고성능화되자, 전통적인 </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/ARM(CPU)" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="ARM(CPU)">ARM</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;"> CPU 설계에서의 가장 큰 특징이라 부를 수 있는 전력 대 성능비가 저하되고 CPU 대기 시간 동안의 누설전류 문제가 점차 증가하게 되었다. big.LITTLE은 이러한 단점을 개선하고자 개발되었다. ARM CPU의 전통에서 벗어나서 </span><strong data-v-824e6f3a="" style="background-color: white; box-sizing: inherit; color: #373a3c; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px;">미칠 듯한 발열</strong><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">과 </span><strong data-v-824e6f3a="" style="background-color: white; box-sizing: inherit; color: #373a3c; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px;">자비없는 전력 소모율</strong><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">을 보여주기 시작하는 </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/ARM%20Cortex-A15" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="ARM Cortex-A15">ARM Cortex-A15</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">와 </span><a class="DCLJQsNO" data-v-824e6f3a="" href="https://namu.wiki/w/ARM%20Cortex-A7" style="background-color: white; box-sizing: inherit; color: #0275d8; cursor: pointer; font-family: "Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif; font-size: 14.4px; text-decoration-line: none;" title="ARM Cortex-A7">ARM Cortex-A7</a><span face=""Open Sans", arial, "Apple SD Gothic Neo", "Noto Sans CJK KR", 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, "Malgun Gothic", sans-serif" style="background-color: white; color: #373a3c; font-size: 14.4px;">을 하나의 칩 안에서 쓰기 위한 인터커넥트인 CCI-400이 발표되면서 big.LITTLE을 본격적으로 도입하기 시작했다. <b>[출처 - 참고문헌 2]</b></span></div><div><span face="Open Sans, arial, Apple SD Gothic Neo, Noto Sans CJK KR, 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, Malgun Gothic, sans-serif" style="color: #373a3c;"><span style="font-size: 14.4px;"><br /></span></span></div><div><span face="Open Sans, arial, Apple SD Gothic Neo, Noto Sans CJK KR, 본고딕, KoPubDotum, 나눔바른고딕, 나눔고딕, NanumGothic, 맑은고딕, Malgun Gothic, sans-serif" style="color: #373a3c;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQbooUVpKAI1jI0TvNUgoyD-2DTv58Syh2OE_bPkFn1YDv5RTJIcF2gel1TZzDz6PQmPjuuum_GDXO55J8QgAZSSdOcjX6o-fm8HN64HgTW7RxwwgH4qNAFNt_vCyf6TgWTst23T9-PzSNvDIo09bjyx2oW4R4lvVRNovR9Dt-E4yKnzmV8IZEiXTBXA/s380/Big.Little-logo.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="380" data-original-width="200" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQbooUVpKAI1jI0TvNUgoyD-2DTv58Syh2OE_bPkFn1YDv5RTJIcF2gel1TZzDz6PQmPjuuum_GDXO55J8QgAZSSdOcjX6o-fm8HN64HgTW7RxwwgH4qNAFNt_vCyf6TgWTst23T9-PzSNvDIo09bjyx2oW4R4lvVRNovR9Dt-E4yKnzmV8IZEiXTBXA/s320/Big.Little-logo.webp" width="168" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.3] ARM big.LITTLE 아키텍쳐 [출처 - 참고문헌 3]</div></span><br /><br /><br /><span style="color: #0b5394; font-family: Nunito; font-size: x-large;"><b>2. OpenWrt build하기</b></span><br /><span style="font-family: Nunito;">이번 장에서는 NanoPi R4S용 openwrt code를 build해 보고, 이를 target board에 올려 보는 과정을 소개해 보기로 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #38761d; font-family: Nunito; font-size: large;"><b>a) NanoPi R4S용 openwrt build 하기</b></span></div><div><br /></div><div><span style="font-family: Nunito;">$ mkdir nanopi_r4s</span></div><div><span style="font-family: Nunito;">$ cd nanopi_r4s</span></div><div><span style="font-family: Nunito;">$ <b>repo init -u https://github.com/friendlyarm/friendlywrt_manifests -b master-v21.02 -m rk3399.xml --repo-url=https://github.com/friendlyarm/repo --no-clone-bundle</b></span></div><div><span style="font-family: Nunito;">$ <b>repo sync -c --no-clone-bundle</b></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 정확한 명령은 위의 wiki page를 참조하기 바란다(내용이 계속 갱신되고 있는 듯 하다).</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div><b><여기서 잠깐></b></div><div><span style="background-color: white;"><span style="font-family: Nunito;">repo init 시 아래와 같은 python permission 에러가 발생한다면, repo를 수동으로 설치한 후, repo init 명령을 수행해 주기 바란다.</span></span></div><div><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white;">_________________________________________</span></span></div><div><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white;">...</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;"><div style="color: #b45f06;">…</div><div style="color: #b45f06;">sl = self._semlock = _multiprocessing.SemLock(kind, value, maxvalue)</div><div style="color: #b45f06;">OSError: [Errno 13] Permission denied</div><div style="color: #b45f06;">_________________________________________</div><div><div>$ mkdir -p ~/.bin</div><div>$ PATH="${HOME}/.bin:${PATH}"</div><div>$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo</div><div>$ chmod a+rx ~/.bin/repo</div></div></span></span></div><div><span style="font-family: Nunito;">___________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b><friendlywrt source code build 하기></b></span></div><div><span style="font-family: Nunito;">$ <b>./build.sh nanopi_r4s.mk</b></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>...</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i><div>using config device/friendlyelec/rk3399/nanopi_r4s.mk</div><div>============Start building uboot============</div><div>SRC<span style="white-space: pre;"> </span>= /home/chyi/workspace/boards/nanopi_r4s/friendlywrt-rk3399/u-boot</div><div>TARGET_ARCH<span style="white-space: pre;"> </span>= arm64</div><div>TARGET_PLAT<span style="white-space: pre;"> </span>= rk3399</div><div>TARGET_UBOOT_CONFIG=rk3399_defconfig</div><div>TARGET_OSNAME<span style="white-space: pre;"> </span> = friendlywrt</div><div>=========================================</div><div>uboot src: /home/chyi/workspace/boards/nanopi_r4s/friendlywrt-rk3399/u-boot</div><div>Reading package lists... Done</div><div>Building dependency tree </div><div>Reading state information... Done</div><div>Package android-tools-fsutils is not available, but is referred to by another package.</div><div>...</div><div> Suggest size: 25165824</div><div>Created filesystem with 11/6400 inodes and 1438/25600 blocks</div><div>-----------------------------------------</div><div>rootfs dir:</div><div><span style="white-space: pre;"> </span>/home/chyi/workspace/boards/nanopi_r4s/friendlywrt-rk3399/scripts/sd-fuse/out/rootfs.hDG7FTWcP</div><div>boot dir:</div><div><span style="white-space: pre;"> </span>/home/chyi/workspace/boards/nanopi_r4s/friendlywrt-rk3399/scripts/sd-fuse/out/boot.M7I0SPsyp</div><div>-----------------------------------------</div><div>Creating RAW image: out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img (1000 MB)</div><div>---------------------------------</div><div>0+0 records in</div><div>0+0 records out</div><div>0 bytes copied, 2.6134e-05 s, 0.0 kB/s</div><div>----------------------------------------------------------------</div><div>[out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img] capacity = 953MB, 999999488 bytes</div><div>current out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img partition:</div><div>----------------------------------------------------------------</div><div>parsing ./friendlywrt21/parameter.txt:</div><div>create new GPT 9:</div><div>----------------------------------------------------------------</div><div>copy from: ./friendlywrt21 to out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img</div><div> [RAW. 0]: 198 KB | ./friendlywrt21/idbloader.img > 100% : done.</div><div> [RAW. 1]: 4096 KB | ./friendlywrt21/uboot.img > 100% : done.</div><div> [RAW. 2]: 4096 KB | ./friendlywrt21/trust.img > 100% : done.</div><div> [RAW. 3]: 48 KB | ./friendlywrt21/misc.img > 100% : done.</div><div> [RAW. 4]: 1 KB | ./friendlywrt21/dtbo.img > 100% : done.</div><div> [RAW. 5]: 2560 KB | ./friendlywrt21/resource.img > 100% : done.</div><div> [RAW. 6]: 31948 KB | ./friendlywrt21/kernel.img > 100% : done.</div><div> [RAW. 7]: 7308 KB | ./friendlywrt21/boot.img > 100% : done.</div><div> [RAW. 8]: 351034 KB | ./friendlywrt21/rootfs.img > 100% : done.</div><div> [RAW. 9]: 5752 KB | ./friendlywrt21/userdata.img > 100% : done.</div><div>----------------------------------------------------------------</div><div>---------------------------------</div><div>RAW image successfully created (15:50:54).</div><div>-rw-rw-r-- 1 chyi chyi 999999488 Nov 16 15:50 out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img</div><div>Tip: You can compress it to save disk space.</div><div>-----------------------------------------</div><div>Run the following command for sdcard install:</div><div><span style="white-space: pre;"> </span>sudo dd if=out/friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img bs=1M of=/dev/sdX</div></i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #38761d; font-family: Nunito; font-size: large;"><b>b) Image file 설치 후, 부팅하기</b></span></div><div><span style="font-family: Nunito;">앞서 build한 image 파일의 압축을 푼 후, dd 명령 등을 사용하여 microSD에 설치하도록 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #bf9000; font-family: Nunito;"><b><microSD에 image writing하기></b></span></div><div><span style="font-family: Nunito;">$ cd out</span></div><div><span style="font-family: Nunito;">$ <b>gzip -d friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img.gz</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo dd if=./friendlywrt_21.02_20221116_nanopi-r4s_arm64_sd.img bs=1M of=/dev/sdX</b></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 당연한 거지만, /dev/sdX는 실제 인식된 값으로 수정하도록 하자. 예) sdb</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6mj24s5im_f9qzA4ziqZwD1HgSoLrs7JfBNvaohslDbOB5f1zBeRFOvEg-L6lzn3-p_cg1pt7ZJhMDm3A_ec4LeK_77iLCdOp1ip1Y6kE0vBo0DDwWoTPkTRipXlDmN8C7Njgz6i2_UP0mMMM5uDxtItkvsg72O4S2xgGUIORIpid1qp2AT5e1K7vg/s411/nanopi_r4s_running.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="411" data-original-width="307" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF6mj24s5im_f9qzA4ziqZwD1HgSoLrs7JfBNvaohslDbOB5f1zBeRFOvEg-L6lzn3-p_cg1pt7ZJhMDm3A_ec4LeK_77iLCdOp1ip1Y6kE0vBo0DDwWoTPkTRipXlDmN8C7Njgz6i2_UP0mMMM5uDxtItkvsg72O4S2xgGUIORIpid1qp2AT5e1K7vg/s320/nanopi_r4s_running.png" width="239" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.1] NanoPi R4S Case 장착한 상태에서 구동한 모습</span></div></div><div><span style="font-family: Nunito; text-align: left;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 NanoPi R4S는 case도 함께 제공한다. 나름 촌스럽지 않고 괜찮다~</span></span></div><div><span style="font-family: Nunito; text-align: left;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div><span style="font-family: Nunito;">이제, 케이스 뚜껑을 연 상태에서 serial console cable을 연결하고, 부팅하는 모습을 들여다 보자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERde_OIkzguMMGq3FtWYTHZyrY3P7CET0at0EcNeeDTNEOu8VmOhXB6ddO7fTGWiV_tDLsDqJoqsytO059IWqlwn_Lx-pZ0_ltESoYAfmN11F_CsEthI8SXaPvJliEDqDB97Sq_TMmu4edNmZMgu_KqdkyTmbbm0A2mpYWoFnpAN57UHqRAwyekHgXA/s4000/20230210_100128.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3000" data-original-width="4000" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiERde_OIkzguMMGq3FtWYTHZyrY3P7CET0at0EcNeeDTNEOu8VmOhXB6ddO7fTGWiV_tDLsDqJoqsytO059IWqlwn_Lx-pZ0_ltESoYAfmN11F_CsEthI8SXaPvJliEDqDB97Sq_TMmu4edNmZMgu_KqdkyTmbbm0A2mpYWoFnpAN57UHqRAwyekHgXA/w400-h300/20230210_100128.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.2] Target board에 Serial Console 케이블 연결 후, 구동한 모습</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>minicom -b 1500000 -D /dev/ttyUSB0</b></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 minicom 명령 끝에 -s option을 주어, minicom 설정 화면에서 Hardware Flow Control 설정을 No로 해 주어야 keyboard 입력이 안되는 문제가 해결될 것이다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlu8EQQaD1W-vGfSKmxXPhbEvTF_o8EQOP-M5JOh-UZMHbxsNyLKmyNfvX2OL2YVXg5OtS7u2kL36Php9c5zJn8p3M0ZTcyP-qNoTKozrwVjSsS3wXXQl6GJJA5EhsG6Kb3b3JC2zCvpk_t3bQ2o5W34HRX1QYwl__kBkdyRNLGg49QSkIHYTfHjAIhg/s944/nanopi_r4s_boot1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="735" data-original-width="944" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlu8EQQaD1W-vGfSKmxXPhbEvTF_o8EQOP-M5JOh-UZMHbxsNyLKmyNfvX2OL2YVXg5OtS7u2kL36Php9c5zJn8p3M0ZTcyP-qNoTKozrwVjSsS3wXXQl6GJJA5EhsG6Kb3b3JC2zCvpk_t3bQ2o5W34HRX1QYwl__kBkdyRNLGg49QSkIHYTfHjAIhg/s320/nanopi_r4s_boot1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4lZy8kkd-UlELbgzwR0aSEAqKK9gd0cc_od08p0Y6ETOGM2mWGwv6QQTrMjGc8dzrmhAe_My2jQ3DPAsAwX2XUH-lumU2C2VeCbOVPLjcEexE5QwnY3f6fY6OIfP-zDcx_0rGIJD6slwDpiE2k31q0rr6RpOvBE8zjUJXu5Ex1F3C3WlPAzqQiD8G3g/s948/nanopi_r4s_boot2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="948" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4lZy8kkd-UlELbgzwR0aSEAqKK9gd0cc_od08p0Y6ETOGM2mWGwv6QQTrMjGc8dzrmhAe_My2jQ3DPAsAwX2XUH-lumU2C2VeCbOVPLjcEexE5QwnY3f6fY6OIfP-zDcx_0rGIJD6slwDpiE2k31q0rr6RpOvBE8zjUJXu5Ex1F3C3WlPAzqQiD8G3g/s320/nanopi_r4s_boot2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 2.3] NanoPi R4S 부팅 모습(ROM code => u-boot => kernel 순)</span></span></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYqei032sotMgWljZz8w2So9VI4YM3zFTsFl1oztYjLdDIUi0RF75ID95wkdpORgrH97C7s8JM91JG9BDhFXcut2vYf3qGGoQX83EQascm_bF2M9F-Xc-OlZfJKfoTJUorIbVo8jHLZrn4HAzWv3tNMbd2rLbeRmEEXbruLp_nHdzH8mwZFW2SJgiviA/s1011/nanopi_r4s_ps.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="839" data-original-width="1011" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYqei032sotMgWljZz8w2So9VI4YM3zFTsFl1oztYjLdDIUi0RF75ID95wkdpORgrH97C7s8JM91JG9BDhFXcut2vYf3qGGoQX83EQascm_bF2M9F-Xc-OlZfJKfoTJUorIbVo8jHLZrn4HAzWv3tNMbd2rLbeRmEEXbruLp_nHdzH8mwZFW2SJgiviA/s320/nanopi_r4s_ps.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.4] NanoPi R4S - ps w 명령 실행 모습</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2_xQx51fzxTACt83jswnCC_M67WKjl5MOsM4lRHuGitV_Vp5DEj1drBKBFyTvPssvSGSUFPFa7r2FlC708MXcTElnSsN0jP637wjqzNSkZvyvmTca1Qbh6B3QNf5kABxoe-lnjJCAHz4zTMU9KjFMg-cBox4KM7QRDskaWAgURWAPYuutkic6kcEMYw/s1124/nanopi_r4s_interrupts.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="726" data-original-width="1124" height="207" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2_xQx51fzxTACt83jswnCC_M67WKjl5MOsM4lRHuGitV_Vp5DEj1drBKBFyTvPssvSGSUFPFa7r2FlC708MXcTElnSsN0jP637wjqzNSkZvyvmTca1Qbh6B3QNf5kABxoe-lnjJCAHz4zTMU9KjFMg-cBox4KM7QRDskaWAgURWAPYuutkic6kcEMYw/s320/nanopi_r4s_interrupts.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.5] NanoPi R4S - cat /proc/interrupts</span></div></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 CPU가 6개가 맞다.</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">c) NanoPi R4S용 u-boot & kernel build 하기</span></b></div><div><span style="font-family: Nunito;">NanoPi R4S에서는 u-boot과 kernel을 별도로 build하는 것이 가능하다. NanoPi R4S용 u-boot code와 kernel code의 특징을 파악해 보고 싶은 마음은 굴뚝같으나, (다음을 기약하며) 여기서는 각각을 build하는 선에서 마무리하고, 다음 장으로 넘어가도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b><u-boot></b></span></div><div><span style="font-family: Nunito;">$ <b>./build.sh uboot</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b><kernel></b></span></div><div><span style="font-family: Nunito;">$ <b>./build.sh kernel</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">(kernel build의 경우) 위의 script를 사용하는 대신, 당연히 아래와 같이 수동 build도 가능하다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$<b> export PATH=/opt/FriendlyARM/toolchain/11.3-aarch64/bin/:$PATH</b></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 kernel 4.19 이상인 경우에는 toolchain 11.3을 사용해야 한다.</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div><span style="font-family: Nunito;"><div>$ <b>export ARCH=arm64</b></div><div>$ <b>export CROSS_COMPILE=aarch64-linux-gnu-</b></div><div><br /></div><div>$ <b>export CC=aarch64-linux-gnu-gcc</b></div><div>$ <b>export LD=aarch64-linux-gnu-ld</b></div><div><br /></div><div>$ <b>make clean</b></div><div>$<b> make nanopi4_linux_defconfig</b></div><div>$ <b>make menuconfig</b></div></span></div><div><span style="font-family: Nunito;">$ <b>make -j16</b></span></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div><span style="font-family: Nunito;"><div>$<b> mkdir -p out-modules && rm -rf out-modules/*</b></div><div>$<span style="font-weight: bold;"> make INSTALL_MOD_PATH="$PWD/out-modules" modules -j$(nproc)</span></div><div>$<span style="font-weight: bold;"> make INSTALL_MOD_PATH="$PWD/out-modules" modules_install</span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">____________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><b><여기서 잠깐></b></span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;">NanoPi R4S용 device tree 파일은 어떤 파일을 살펴 보면 알 수 있을까 </span><span style="font-family: Nunito;"> ?</span></span></div><div><br /></div><div><span style="font-family: Nunito;"><div>$ cd arch/arm64/boot/dts/rockchip</div><div><span style="color: #b45f06;"><br /></span></div><div style="text-align: center;"><b>rk3399.dtsi, <span style="color: #666666;">rk3399-opp.dtsi</span></b></div><div style="text-align: center;"><b>^</b></div><div style="text-align: center;"><b>|</b></div><div style="text-align: center;"><b>rk3399-nanopi4.dtsi</b></div><div style="text-align: center;"><b>^</b></div><div style="text-align: center;"><b>|</b></div><div style="text-align: center;"><b>rk3399-nanopi-r4s.dts</b></div><div>____________________________________________________________________________</div><div><br /></div></span></div><div><br /><span style="color: #0b5394; font-family: Nunito; font-size: x-large;"><b>3. WireGuard Kernel 코드 분석하기</b></span><br /><span style="font-family: Nunito;">WireGuard kernel code 분석과 관련해서는 <a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">일전(4장 참조)</a>에 한차례 간략히 정리했던 기억이 있다. 이번에는 지난번 분석에서 다소 미진했던 부분과 <b>최신 kernel 5.15를 대상으로 하여 추가 분석</b>을 진행하고자 한다. 따라서 이번에 분석하는 내용과 이전 blog posting의 내용을 같이 참조하는 것이 wireguard를 전체적으로 이해하는 데에 도움이 될 것이다. 😎</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="goog_1592757987"><br /></a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html</a></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDTgmtbw70-MpGuPrskH_67Uh6G36Y2umuwbk9uiJhu1P8RkNRkiOdRTYadFX1cAB3TCsCF6TYifFRrwTQK6aphNjsEZrLXyaypQIvfGtox3jQIQhgiXuf0TCif76rB1yyH8MKF_qLR04QT25kCPltJevfzf4O-50xyu52SmivEBUAy2AhxWU9EylQ8A/s400/wireguard_logo-freelogovectors.net_-400x212.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="212" data-original-width="400" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDTgmtbw70-MpGuPrskH_67Uh6G36Y2umuwbk9uiJhu1P8RkNRkiOdRTYadFX1cAB3TCsCF6TYifFRrwTQK6aphNjsEZrLXyaypQIvfGtox3jQIQhgiXuf0TCif76rB1yyH8MKF_qLR04QT25kCPltJevfzf4O-50xyu52SmivEBUAy2AhxWU9EylQ8A/s320/wireguard_logo-freelogovectors.net_-400x212.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.1] WireGuard logo</span></div><div><br /></div><div style="text-align: center;"><span style="color: #ff00fe; font-family: Nunito;"><b>WireGuard를 제대로 파헤쳐 보자. 가즈아~ 🔍</b></span></div><div><br /></div><div><div><span style="color: #45818e; font-family: Nunito;"><b><WireGuard code 분석 Point></b></span></div><div><span style="color: #38761d; font-family: Nunito;">[1] wg tool을 이용힌 get/set 흐름(netlink socket) - </span><span style="color: #38761d; font-family: Nunito;">wg0 device 및 </span><span style="color: #38761d; font-family: Nunito;">peer 설정 흐름</span></div><div><span style="color: #38761d; font-family: Nunito;">[2] device, peer 초기화 과정</span></div><div><span style="color: #38761d; font-family: Nunito;">[3] noise handshaking 과정</span></div><div><span style="color: #38761d; font-family: Nunito;">[4] peer lookup 과정</span></div><div><span style="color: #38761d; font-family: Nunito;">[5] handshake & data packet send/receive 흐름</span></div><div><span style="color: #38761d; font-family: Nunito;">[6] udp tunnel(encapsulation & decapsulation)</span></div><div><span style="color: #38761d; font-family: Nunito;">[7] ARM NEON 기반 암호 가속(or Intel AVX2 기반 암호 가속)</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">WireGuard kernel code를 이해하는데 걸림돌이 되는 부분으로는 (물론 독자에 따라 편차는 있겠으나) 다음과 같은 것들이 될 수 있을 것 같다. Wireguard의 코드량은 많지 않지만, 미리 숙지해야 할 사항이 만만치 않은 것이 사실이다. 😋</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #cc0000; font-family: Nunito;"><b><넘어야 할 장애물></b></span></div><div><span style="color: #b45f06; font-family: Nunito;">[1] </span><span style="color: #b45f06; font-family: Nunito;">Noise handshaking protocol: ECDH, HKDF, HMAC, Blake2s, ChaCha20Poly1305 AEAD ...</span></div><div><span style="color: #b45f06; font-family: Nunito;">[2] SipHash2-4 기반의 hashtable(peer hashtable, index hashtable)</span></div><div><span style="color: #b45f06; font-family: Nunito;">[3] netlink socket(userspace와의 interface)</span></div><div><span style="color: #b45f06; font-family: Nunito;">[4] skb와 Linux tcp/ip stack, netdevice, udp tunnel, socket structure</span></div><div><span style="color: #b45f06; font-family: Nunito;">[5] ptr ring(crypt queue)</span></div><div><span style="color: #b45f06; font-family: Nunito;">[6] workqueue, timer, list, hash list 등 다양한 kernel 기능 사용</span></div><div><span style="color: #b45f06; font-family: Nunito;">[7] 다양한 lock 함수 호출(rcu, rw semaphore, mutex, spinlock ...)</span></div><div><span style="color: #b45f06; font-family: Nunito;">[8] kernel memory 사용 관련</span></div></div><div><span style="color: #b45f06; font-family: Nunito;">[9] ...</span></div><div><br /></div><div><span style="color: #38761d; font-family: Nunito; font-size: large;"><b>a) WireGuard source code 위치</b></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;">WireGuard가 </span></span><span style="font-family: Nunito;">Kernel(5.6)에 통합되면서 기본 코드는 <b>drivers/net/wireguard</b> 아래에 있으나, crypto 및 기타 코드는 linux kernel에서 기존에 사용하던 위치에 배치되어 있으므로 이들을 일일이 찾아내는 것도 여간 쉽지가 않다.</span><div style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;">____________________________________________</div><div style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;"><br /></div><div style="background-color: white;"><span style="color: #45818e; font-family: Nunito;"><b>WireGuard base codes : drivers/net/wireguard</b></span></div><div style="background-color: white;"><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;"><br /></span></b></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">allowedips.[ch] </span></b></div><div><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i style="color: #333333; font-size: 14.85px;"><span style="font-family: Nunito;">allowed ips 관련 코드, </span></i><span style="color: #333333; font-family: Nunito;"><span style="font-size: 14.85px;"><i>struct allowedips_node로 구성된 table을 관리한다.</i></span></span></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">cookie.[ch] </span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">cookie 관련 코드</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">device.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">net_device 관련 코드 - wg_open/wg_stop/wg_xmit/wg_setup/wg_newlink ...</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">main.c</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">main routine - mod_init/mod_exit</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">netlink.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">userspace tool인 wg와의 netlink socket 통신 코드, device(net_device) 자신 및 peer에 대한 설정</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">noise.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">wireguard key handshaking protocol code(결국 이 부분이 핵심)</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">peer.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">peer 생성/삭제 관련 코드</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">peerlookup.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">2개의 hash table(public key 기반 hash table, index 기반 hash table)에 대한 operation(alloc, add, remove, lookup) 정의</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">queueing.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">(중간 중간에) packet을 담아두는 queue(ptr_ring buffer) 관련 operation(alloc, init, free) 정의</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">ratelimiter.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">rate limit 관련 코드</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">receive.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">패킷 수신 관련 코드(복호화 포함)</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">send.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">패킷 송신 관련 코드(암호화 포함)</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">socket.[ch]</span></b></div><div style="color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">send4/6( ) 함수 호출하여 패킷 송신(송신 시 udp tunnel 처리함), .encap_rcv = wg_receive 통해 udp tunnel 패킷 수신부 정의</span></i></li></ul></div><div style="color: #333333; font-size: 14.85px;"><b><span style="font-family: Nunito;">timers.[ch]</span></b></div></div><div style="background-color: white; color: #333333; font-size: 14.85px;"><ul style="line-height: 1.4; list-style-image: initial; list-style-position: initial; margin: 0.5em 0px; padding: 0px 2.5em;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;"><i><span style="font-family: Nunito;">wireguard에서 사용하는 각종 timer 정의</span></i></li></ul></div><span style="font-family: Nunito;"><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #45818e; font-family: Nunito;"><b>SIPHASH codes</b></span></div><div><span style="font-family: Nunito;">include/linux/siphash.h</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #45818e; font-family: Nunito;"><b>UDP Tunnel codes</b></span></div><div><span style="font-family: Nunito;">net/ipv4/udp_tunnel_core.c</span></div><div><span style="font-family: Nunito;">include/net/udp_tunnel.h</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="color: #45818e;">Random number 생성 codes</b></span></div><div><span style="font-family: Nunito;">drivers/char/random.c</span></div><div><span style="font-family: Nunito;"><br /></span></div><span style="color: #45818e;"><b>Crypto files</b></span><br />lib/crypto/chacha20poly1305.c</span></div><div><span style="font-family: Nunito;">arch/arm/crypto/curve25519-glue.c<br />lib/crypto/curve25519-fiat32.c</span></div><div><span style="font-family: Nunito;">arch/arm/crypto/chacha-glue.c</span></div><div><span style="font-family: Nunito;">arch/arm/crypto/poly1305-glue.c</span></div><div><span style="font-family: Nunito;">lib/crypto/poly1305.c<br />...</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">물론 이 외에도 더 있다... 찾는 대로 추가해 보도록 하자. 😝</span></div><div><span style="font-family: Nunito;"><b>__________________________________________________________________________</b></span></div><div><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-size: large;"><span style="font-family: Nunito;"><b style="color: #38761d;">b) wg tool을 이용한 get/set 흐름(netlink socket) - </b></span><b style="color: #38761d; font-family: Nunito;">wgX device 및 peer 설정 흐름</b></span></div><div><span style="font-family: Nunito;"><div>WireGuard는 아래 그림과 같이 wg라는 user space tool과 wireguard kernel module로 구성되어 있다. 이 둘은 <b>netlink socket</b>을 통해 연결되어 있다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 아래 그림 및 실제 wireguard code를 제대로 이해하기 위해서는 linux netlink socket의 개념을 먼저 파악해 두어야 한다. Netlink socket에 관해서는 <a href="https://www.minzkn.com/moniwiki/wiki.php/AboutNetLinkSocket">[참고 문헌 7]</a>에 잘 정리가 되어 있으니 참조하기 바란다.</span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIhjhYbk_8wvdQFCPnyQTef3aettSvGFSPAstc5u6x1muX5ryadujGhY1PGK0ECJBkJPxHoMfyUpaqTNNdQB8IwjpI1fHfiSC_w7wTD2WJxieOdzPKzyi4_GVTq1l2tziBYWdAWVge884TSrt9_THPHfTQm4hlSIURa5WDZuldwhU-3h0jCEJt2kjVqQ/s400/wg_tool_kernel.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="231" data-original-width="400" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIhjhYbk_8wvdQFCPnyQTef3aettSvGFSPAstc5u6x1muX5ryadujGhY1PGK0ECJBkJPxHoMfyUpaqTNNdQB8IwjpI1fHfiSC_w7wTD2WJxieOdzPKzyi4_GVTq1l2tziBYWdAWVge884TSrt9_THPHfTQm4hlSIURa5WDZuldwhU-3h0jCEJt2kjVqQ/w400-h231/wg_tool_kernel.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.2] wg tool과 kernel 간의 netlink interface</span></div></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><wg tool set operation></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihM2VURanB8MvM9kyhvl2ULpKXF42hHAdiTE0jLFdK9HUa5nLASiZeRcSvHMQJ8Do-UX-HvFGlfAWgjWr5L11aKlWCAiHJczdmeh-7GgPnOubQRKZciYudZw0bXQxUfrIr9Hd9gwUJNo_NGgPM6_UyYD0gOEi7W5O51e1PgezXB3kSQC9ro8_P_bdnaw/s524/wg_too_set_operation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="449" data-original-width="524" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihM2VURanB8MvM9kyhvl2ULpKXF42hHAdiTE0jLFdK9HUa5nLASiZeRcSvHMQJ8Do-UX-HvFGlfAWgjWr5L11aKlWCAiHJczdmeh-7GgPnOubQRKZciYudZw0bXQxUfrIr9Hd9gwUJNo_NGgPM6_UyYD0gOEi7W5O51e1PgezXB3kSQC9ro8_P_bdnaw/w400-h343/wg_too_set_operation.png" width="400" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.3] wg tool의 set 명령 수행시의 코드 흐름</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><kernel module netlink set operation></b></span></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdh3KaiJxu5AvAhrGmkssB6Yl3V7xajyimihzTBZmuDPuuzhedbkpIRkbHaEGRqzdvEf6VDXw0K5QYJ-C8-2H76ZvQQOy6syEPrxoZ2FbaqQh69hXkBB-JGeEnyET--IWF5TpOdC1VhKNjdHPYAqt1-M5BCzUFDmKAMrqwn1QlERLfUr9jtymQXUkRhA/s1097/wireguard_netlink_set.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="906" data-original-width="1097" height="528" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdh3KaiJxu5AvAhrGmkssB6Yl3V7xajyimihzTBZmuDPuuzhedbkpIRkbHaEGRqzdvEf6VDXw0K5QYJ-C8-2H76ZvQQOy6syEPrxoZ2FbaqQh69hXkBB-JGeEnyET--IWF5TpOdC1VhKNjdHPYAqt1-M5BCzUFDmKAMrqwn1QlERLfUr9jtymQXUkRhA/w640-h528/wireguard_netlink_set.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] wg tool의 set 명령 수행시, 커널에서 받아주는 코드 흐름</span></div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Userspace wg 명령으로 부터 set 명령이 netlink socket을 타고 kernel로 전달되면, kernel code에서는 netlink message를 적절히 parsing한 후, wgX interface 관련 속성을 변경해 주는 것은 물론이고, peer 관련 설정을 해주게 된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><wg tool get operation></b></span></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlPIBxtOPsM_IARFm8Bp23NctK0pCwEqz_lg1fizAU6UOTiXCqRJ8M_U2t27F7-1SXEAGGGP5UeICEk3zY40pMtVxuGAZcAyw241SXdXixMzAX_oANVveG7R_Qt9E33l2cU3YxcGPJRoFzHSDMO5PNgnGIdOCoPCqcYWOq1BZwYy-SIjX3W3TOjv0-3w/s713/wg_too_get_operation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="713" data-original-width="526" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlPIBxtOPsM_IARFm8Bp23NctK0pCwEqz_lg1fizAU6UOTiXCqRJ8M_U2t27F7-1SXEAGGGP5UeICEk3zY40pMtVxuGAZcAyw241SXdXixMzAX_oANVveG7R_Qt9E33l2cU3YxcGPJRoFzHSDMO5PNgnGIdOCoPCqcYWOq1BZwYy-SIjX3W3TOjv0-3w/w295-h400/wg_too_get_operation.png" width="295" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] wg tool의 get 명령 수행시의 코드 흐름</span></div><br /><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><kernel module netlink get operation></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhztUsxZQELRmRfjIFR9fIJwM4JOTTWfUUffhhywJghsZy0ABhXB8mcs_vO92yUXeGn0WYcBYCLVE89iigvJZDZeZ1d6eWPAtVWPZ2MjPsME7czN2fJXvAD2LYcIqyZ4CtoWYs3YJ-WOJ0s3AjXQmjRV6QiTWmb2jsMSv41Z-6ZVGuGMuZ7C7xsF0T0-A/s954/wireguard_netlink_get.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="830" data-original-width="954" height="557" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhztUsxZQELRmRfjIFR9fIJwM4JOTTWfUUffhhywJghsZy0ABhXB8mcs_vO92yUXeGn0WYcBYCLVE89iigvJZDZeZ1d6eWPAtVWPZ2MjPsME7czN2fJXvAD2LYcIqyZ4CtoWYs3YJ-WOJ0s3AjXQmjRV6QiTWmb2jsMSv41Z-6ZVGuGMuZ7C7xsF0T0-A/w640-h557/wireguard_netlink_get.png" width="640" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] wg tool의 get 명령 수행시, 커널에서 받아주는 코드 흐름</span></div><div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Userspace wg 명령으로 부터 get 명령이 netlink socket을 타고 kernel로 전달되면, kernel code는 device(wgX) 및 peer의 정보를 </span><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">netlink message에 </span><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">모두 실어서 userspace로 전달해주게 된다.</span></div></div><div><br /></div><div><span style="font-family: Nunito;">wg tool과의 interface(netlink socket) 부분을 살펴 보았으니, 그 다음 순서는 <b>wg device 초기화 및 peer 초기화 코드</b>를 분석하는 것이다. 이 부분은 noise handshaking과 packet send/receive와 연관되는 아주 중요한 부분이라고 볼 수 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">c) device(wgX) 초기화 과정</b></span></span></div><div><span style="font-family: Nunito;">Wireguard code를 보다 보면 어떤 일을 반복적으로 수행하는 코드가 눈에 많이 띈다. 이를 kernel에서 처리하는 대표적인 예로는 timer와 work queue를 생각해 볼 수 있다. Timer는 일정 시간이 경과할 때마다 지정된 작업을 수행하는 특징이 있으며, work queue는 언제 실행될지는 정확히 예측할 수는 없으나, 하고자 하는 work을 queue에 넣어두면, (scheduling이 되는 시점에) 이를 worker thread가 처리하도록 하는 특징을 갖는다. 이와 관련(Timer, Work Queue, Tasklet, Interrupts 등)해서는 일전에 작성한 아래 글(3장)을 참고하기 바란다.</span></div><div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="goog_296809123"><br /></a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/07/linux-kernel-programming-gpio-interrupt.html">https://slowbootkernelhacks.blogspot.com/2020/07/linux-kernel-programming-gpio-interrupt.html</a></span></div><div><span style="font-family: Nunito;"> </span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;"><span style="background-color: white;">📌 우리가 익히 잘 알고 있는 RTOS(예: FreeRTOS, Zephyr 등)는 </span></span><span style="font-family: Nunito;">하고자 하는 work을 정확히 원하는 시간에 수행하는 특징을 갖고 있기 때문에 Real Time OS라고 부른다. Linux 변형 배포판 중에는 RT-Linux라는 것도 있다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white;"><br /></span></span></span></div><div><span style="font-family: Nunito;"><span style="font-family: Nunito;"><span style="background-color: white;"><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><div>________________________________________________________________________________</div><div><span style="color: #b45f06;"><b><여기서 잠깐></b></span></div><div><span style="color: #b45f06;">Work Queue의 동작 원리에 관하여...</span></div></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">Work queue는 앞서 설명한 대로 deferring work(지연 처리하고 싶은 work)을 처리하기 위한 linux kernel 기능 중의 하나로 work(work function 포함), queue, worker thread의 3가지 요소로 구성되어 있다. work queue의 실체는 <b><u>struct workqueue_struct의 instance</u></b>로 이해하면 될 것 같다. </span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><br /></div><div style="text-align: center;"><b><span style="font-family: Nunito;">(1) struct work_struct(<span style="color: #6fa8dc;">work</span>) + (2) </span>struct workqueue_struct(<span style="color: #6fa8dc;">workqueue)</span> + (3) </b><span style="text-align: left;"><b>struct worker(</b></span><b><span style="color: #6fa8dc;">worker thread</span>)</b></div><div><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">일반적인 사용 방법을 예시와 함께 간략히 정리해 보았는데, 이 개념</span><span style="font-family: Nunito;">이 이해가 되어야 wireguard의 현란한 work queue 코드를 이해하는데 부담이 없을 것으로 보인다.</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><br /></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>1. work과 work queue를 선언한다.</b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">struct workqueue_struct *myqueue;</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">struct work_struct thework;</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>2. work function(즉, handler 함수)를 선언한다. 여기에 지연 처리에 필요한 코드를 작성해 둔다.</b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">void dowork(void *data) { /* work function codes here */ };</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>3. work queue를 초기화하고, 앞서 선언한 work function을 work에 끼워 넣는다.</b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">myqueue = create_singlethread_workqueue("mywork"); //사용자 정의 worker thread 생성</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">INIT_WORK(&thework, dowork, <data-pointer>); //work과 work function을 연결</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>4. 적당한 시점에 work 함수가 실행되도록 schedule 함수를 호출한다.</b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">queue_work(myqueue, &thework); //queue에 work을 넣어줌.</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>5. (이 부분은 필요시 호출) queue에 적재된 모든 work이 실행을 마칠 때까지 기다린다. </b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">void flush_workqueue(struct workqueue_struct *wq);</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b>6. workqueue를 종료한다.</b></span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">cancel_work_sync() or cancel_delayed_work_sync() 함수 등을 호출한다.</span></div><div style="color: black; font-family: "Noto Sans CJK KR";"><br /></div><div style="color: black; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">________________________________________________________________________________</span></div><div style="color: #b45f06;"><span style="font-family: Nunito;"><br /></span></div></span></span></span></div><div><span style="font-family: Nunito;"><span style="font-family: Nunito;"><span style="background-color: white;">Wireguard에는 work queue 관련 코드가 많이 포함되어 있어, 코드를 이해하는데 어려움이 있지만, 앞서 설명한 내용과 몇가지 사실만 이해한다면 그리 어려운 것만도 아니다.</span></span></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTVpRxZQIcQCk97UbE6L1Rta3Pc4I9dHX1od-3opWW4MAyGASNThxR38Idrw1SZU7v97ckMpolrJLyxxr3DObdF2qlHudxjDMADQfR3IEkMRZxrztLHxtC3rGrLMayp-dWfnX8NDdciS5o1Kgy9WxjfmlYfvYmZq0uVBVEkqGZu1-hAjhVFjXIv3AfNA/s799/wireguard_device_wg_newlink.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="799" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTVpRxZQIcQCk97UbE6L1Rta3Pc4I9dHX1od-3opWW4MAyGASNThxR38Idrw1SZU7v97ckMpolrJLyxxr3DObdF2qlHudxjDMADQfR3IEkMRZxrztLHxtC3rGrLMayp-dWfnX8NDdciS5o1Kgy9WxjfmlYfvYmZq0uVBVEkqGZu1-hAjhVFjXIv3AfNA/w400-h270/wireguard_device_wg_newlink.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span style="text-align: center;">[그림 3.7] device.c 파일의 </span></span><span style="font-family: Nunito; text-align: left;">wg_newlink() 함수 중 work queue 관련 초기화 코드</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">device.c 파일의 wg_newlink() 함수</span><span style="font-family: Nunito;">에는 아래와 같이 3개의 <b>workqueue 할당 코드</b>(</span><span style="font-family: Nunito;">alloc_workqueue)</span><span style="font-family: Nunito;">와 3개의 </span><b style="font-family: Nunito;">wg_packet_queue_init 함수</b><span style="font-family: Nunito;">가 보인다. </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">__________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><div><b><wg_newlink() 함수></b></div><div><br /></div><div>wg-><b><span style="color: #b45f06;">handshake_receive_wq</span></b> = alloc_workqueue("wg-kex-%s", WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);</div><div><br /></div><div><div>wg-><b><span style="color: #b45f06;">handshake_send_wq</span></b> = alloc_workqueue("wg-kex-%s", WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);</div></div><div><br /></div><div><div>wg-><span style="color: #3d85c6;"><b>packet_crypt_wq</b> </span>= alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name);</div></div><div><br /></div><div><div>ret = <b><span style="color: #6aa84f;">wg_packet_queue_init</span></b>(&wg-><span style="color: #3d85c6;"><b>encrypt_queue</b>,</span> <b>wg_packet_encrypt_worker</b>, MAX_QUEUED_PACKETS);</div></div><div><br /></div><div><div>ret = <b><span style="color: #6aa84f;">wg_packet_queue_init</span></b>(&wg-><b><span style="color: #3d85c6;">decrypt_queue</span>,</b> <b>wg_packet_decrypt_worker</b>, MAX_QUEUED_PACKETS);</div></div><div><br /></div><div><div>ret = <b><span style="color: #6aa84f;">wg_packet_queue_init</span></b>(&wg-><b><span style="color: #b45f06;">handshake_queue</span></b>, <b>wg_packet_handshake_receive_worker</b>, MAX_QUEUED_INCOMING_HANDSHAKES);</div></div><div>__________________________________________________________________________</div><div><br /></div><div>먼저 handshake_receive_wg와 wg_packet_queue_init(...handshake_queue...) 함수와의 연관 관계를 먼저 따져 보는 것부터 시작해 보도록 하자.</div><div><br /></div><div><b style="background-color: #d9ead3;">[1] handshake_receive_wq와 wg_packet_queue_init() 함수의 상관 관계</b></div><div><span style="background-color: white; color: #b45f06;">📌 아래 내용을 보시면 아시겠지만, handshake_receive_wq의 목적은 handshake packet을 (cpu별로) 수신 처리하는 것이다.</span></div><div><span style="background-color: white; color: #b45f06;"><br /></span></div><div><div>1) work queue 할당 단계: handshake_receive_wg라는 이름의 work queue를 하나 만든다.</div><div>wg-><b><span style="color: #ff00fe;">handshake_receive_wq</span></b> = alloc_workqueue("wg-kex-%s", WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);</div></div><div><br /></div><div><div>2) cpu 별 work 선언 및 work function 할당 단계 : 아래 함수를 이용하여 cpu 당 1개씩 필요한 work(struct work_struct)을 만들고 초기화 해 준다.</div><div><b>wg_packet_queue_init</b>(&wg->handshake_queue, <b><span style="color: #e06666;">wg_packet_handshake_receive_worker</span></b>, MAX_QUEUED_INCOMING_HANDSHAKES);</div></div><div><span style="color: #b45f06;"><span style="background-color: white;">📌 </span>이 함수에서는 실제로 아래 노란색 표시 부분을 설정해 주는 역할을 하게 된다.</span></div><div>___________________________________________________</div><div>//cpu별로 할당하여 사용하는 multicore_worker structure(= work queue와 work의 조합) 정의 </div><div><div>struct multicore_worker {<span style="white-space: pre;"> </span><i><span style="color: #999999;">... device.h</span></i></div><div><span style="background-color: #fff2cc;"> <b><span style="color: #6aa84f;"> </span><span style="color: #6aa84f;">void *ptr;</span></b><span style="white-space: pre;"> </span></span> <= &wg->handshake_queue이 값이 할당됨.</div><div><span style="background-color: #fff2cc;"><span> </span><span style="color: #6aa84f;"><b>struct work_struct work;</b></span> </span> <= 이게 cpu별 work임.</div><div>};</div></div><div><br /></div><div>//</div><div><div>struct crypt_queue { </div><div> struct ptr_ring ring;</div><div> struct multicore_worker __percpu *worker;</div><div> int last_cpu;</div><div>};</div></div><div>___________________________________________________</div><div><br /></div><div>아래에 wg_packet_queue_init( ) 함수를 펼쳐 보았다.</div><div><div><b>wg_packet_queue_init</b>(struct crypt_queue *queue, work_func_t function, ...)</div><div>{</div><div> <b> </b><b>ptr_ring_init</b>(&queue->ring, len, GFP_KERNEL) //ptr ring(queue)를 하나 할당한다.</div><div><span> </span><span> </span>queue->worker = <b>wg_packet_percpu_multicore_worker_alloc</b>(function, queue)</div><div><span> </span><span> </span>{</div><div><span> </span><span> </span><span> </span>struct multicore_worker __percpu *worker = alloc_percpu(struct multicore_worker)</div><div><span> </span><span> </span><span> </span>for_each_possible_cpu(cpu) {</div><div> <span style="background-color: white;"> <span> </span></span><span style="background-color: #fff2cc;"> </span><span style="background-color: #fff2cc;"><b>per_cpu_ptr(worker, cpu)->ptr = ptr</b>;</span><span style="background-color: white;"> //wg->handshake_queue의 주소를 대입</span></div><div><span><span style="background-color: white;"><span> </span><span> </span><span> </span></span><span><span style="background-color: white;"> </span><span style="background-color: #fff2cc;"> </span></span><b style="background-color: #fff2cc;">INIT_WORK</b><span style="background-color: #fff2cc;">(</span><b style="background-color: #fff2cc;"><span style="color: #6aa84f;">&per_cpu_ptr(worker, cpu)->work</span></b><span style="background-color: #fff2cc;">, </span><b style="background-color: #fff2cc;"><span style="color: #e06666;">function</span></b><span style="background-color: #fff2cc;">);</span></span> // cpu 별로 function 즉, wg_packet_handshake_receive_worker를 work과 연결해 줌.</div><div><span> </span><span> </span><span> </span>}</div><div><span> </span><span> </span>}</div><div>}</div></div><div><br /></div><div>3) cpu별 해당 work 수행 요청 단계: 아래 schedule 함수를 호출하여 <b>handshake_receive_wq work queue</b>에 대한 <b>work(wg_packet_handshake_receive_worker 함수)</b>이 적당한 시점에 지정된 cpu에서 실행(schedule)되도록 해준다.</div><div><br /></div><div><div><b>queue_work_on</b>(cpu, wg-><b><span style="color: #ff00fe;">handshake_receive_wq</span></b>, <b>&per_cpu_ptr(wg->handshake_queue.worker, cpu)->work</b>)<span style="white-space: pre;"> </span><i><span style="color: #999999;">... receive.c</span></i></div></div><div><br /></div><div>이 함수가 호출되면, 결국 <b style="color: #ff00fe;">handshake_receive_wq work queue</b>에 대해<b style="color: #ff00fe;"> </b><b>&per_cpu_ptr(wg->handshake_queue.worker, cpu)->work</b>이 선택된 cpu에서 schedule 되게 된다. 좀 더 쉽게 말해 <span style="color: #e06666; font-weight: bold;">wg_packet_handshake_receive_worker() </span>함수가 실행된다고 보면 된다.</div><div><br /></div><div>다음으로 handshake_send_wg와 wg_packet_queue_init(...handshake_queue...) 함수와의 연관 관계를 먼저 따져 보도록 하자.</div><div><br /></div><div><b style="background-color: #d9ead3;">[2] handshake_send_wq와 wg_packet_queue_init() 함수의 상관 관계</b></div><div><span style="background-color: white; color: #b45f06;">📌 handshake_send_wq의 목적은 handshake packet을 송신 처리하는 것이다.</span></div><div><span style="background-color: white;"><br /></span></div><div><span style="background-color: white;">handshake_send_wq 코드는 handshake_receive_wq code와는 약간 다른 구조로 되어 있다.</span></div><div>1) work queue 할당 단계: handshake_send_wg라는 이름의 work queue를 하나 만든다.</div><div>wg-><b><span style="color: #b45f06;">handshake_send_wq</span></b> = alloc_workqueue("wg-kex-%s", WQ_UNBOUND | WQ_FREEZABLE, 0, dev->name);</div><div><br /></div><div>2) work 선언 및 work function 할당 단계: 아래 함수를 이용하여 work(struct work_struct)을 선언하고, 여기에 work 함수를 붙인다.</div><div>INIT_WORK(&peer-><b><span style="color: #a64d79;">transmit_handshake_work</span></b>, wg_packet_handshake_send_worker)<span style="white-space: pre;"> </span><i><span style="color: #999999;">... peer.c</span></i></div><div><span style="background-color: white; color: #b45f06;">📌 INIT_WORK macro는 work과 work 함수를 연결시키는 역할을 한다. 그럼, 여기서 사용된 work은 어떻게 work queue와 연결될 것인가 ? 이는 다음 step을 보면 알 수 있다. 즉, queue_work( ) 함수를 이용하여 연결이 된다.</span></div><div><span style="background-color: white; color: #b45f06;"><br /></span></div><div>3) 해당 work 수행 요청 단계: schedule 함수를 호출하여 <b>handshake_send_wq work queue</b>에 대한 <b>work(wg_packet_handshake_send_worker 함수)</b>를 실행하도록 해준다.</div><div><br /></div><div><div>queue_work(peer->device->handshake_send_wq, &peer-><b><span style="color: #a64d79;">transmit_handshake_wor</span></b><span style="color: #a64d79;"><b>k</b></span>))</div></div><div><span style="background-color: white; color: #b45f06;">📌 handshake_receive_wq와는 달리 _on이 뒤에 붙질 않는다. 즉, 특정 cpu를 지정하지 않고 current CPU에서 처리한다는 의미이다.</span></div><div><span style="background-color: white; color: #b45f06;"><br /></span></div><div>조금 복잡하지만, handshake_send_wq work queue는 transmit_handshake_work work과 연결되고, 이 work 안에는 wg_packet_handshake_send_worker 함수가 포함되어 있으므로, 최종적으로는 이 함수가 호출되게 된다.</div><div><br /></div><div>다음으로 packet_crypt_wg work queue와 wg_packet_queue_init(...encrpyt...) 함수와의 연관 관계를 먼저 따져 보도록 하자.</div><div><br /></div><div><span style="background-color: #d9ead3;"><b>[3] </b><b>packet_crypt_wq</b><b>와 wg_packet_queue_init(encrypt) 함수의 상관 관계</b></span></div><div><span style="color: #b45f06;"><span style="background-color: white;">📌 packet_crypt_wg work queue의 목적은 data를 encrypt하는 것이다. 따라서 선택된 cpu에서 </span>wg_packet_encrypt_worker 함수가 worker thread(kworker)에 의해서 수행된다.</span></div><div><span style="background-color: white;"><div style="color: black;"><span style="color: #b45f06;">📌 이 함수를 호출하면 아래와 같이 [wg-crypt-wg0]라는 thread가 만들어지는데, 실제로는 그 아래에 보이는 kworker thread가 cpu를 달리하면서 work function을 실행하게 된다.</span></div><div><span><div><span style="color: #674ea7;">root@FriendlyWrt:/proc/13916# ps w|grep wg</span></div><div><span style="color: #674ea7;">11690 root 0 IW< [wg-crypt-wg0]</span></div><div><span style="color: #674ea7;">15705 root 0 IW [kworker/3:0-wg-]</span></div><div><span style="color: #674ea7;">17514 root 0 IW [kworker/1:1-wg-]</span></div><div><span style="color: #674ea7;">17675 root 0 IW [kworker/0:0-wg-]</span></div><div><span style="color: #674ea7;">17756 root 0 IW [kworker/1:2-wg-]</span></div><div><span style="color: #674ea7;">18273 root 0 IW [kworker/1:0-wg-] // string이 잘려서 그런 것이지, 실제로는 </span><span style="color: #674ea7;">[kworker/1:0-wg-</span><span style="color: #674ea7;">crypt-wg0] 임.</span></div><div style="color: black;"><span style="color: #674ea7;"><br /></span></div></span></div></span></div><div>1) work queue 할당 단계: packet_crypt_wq라는 이름의 work queue를 하나 만든다.</div><div>wg-><span style="color: #3d85c6;"><b>packet_crypt_wq</b> </span>= alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name);</div><div><br /></div><div>2) cpu 별 work 선언 및 work function 할당 단계 : 아래 함수를 이용하여 cpu 당 1개씩 필요한 work(struct work_struct)을 선언한다.</div><div>ret = <b><span style="color: #6aa84f;">wg_packet_queue_init</span></b>(&wg-><span style="color: #3d85c6;"><b>encrypt_queue</b>,</span> <b>wg_packet_encrypt_worker</b>, MAX_QUEUED_PACKETS);</div><div><br /></div><div>3) cpu별 해당 work 수행 요청 단계: schedule 함수를 호출하여 <b>packet_crypt_wq work queue</b>에 대한 work 함수 즉, wg_packet_encrypt_worker 함수를 지정된 cpu에서 실행하도록 해준다.</div><div style="text-align: justify;">wg_queue_enqueue_per_device_and_peer(&wg-><b><span style="color: #bf9000;">encrypt_queue</span></b>, &peer->tx_queue, first,</div><div><div style="text-align: justify;"> wg-><b>packet_crypt_wq</b>, &wg->encrypt_queue.last_cpu); <i><span style="color: #999999;">... send.c -> queueing.h</span></i></div></div><div style="text-align: justify;"><span>{</span></div><div style="text-align: justify;"><span><span> ...</span><br /></span></div><div style="text-align: justify;"><span> </span><span style="text-align: left;">queue_work_on(cpu, wq, <b>&per_cpu_ptr(<span style="color: #bf9000;">device_queue</span>->worker, cpu)->work</b>)</span></div><div style="text-align: justify;"><span>}</span></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><span style="text-align: left;">마지막으로 packet_crypt_wg work queue와 wg_packet_queue_init(...decrypt...) 함수와의 연관 관계를 먼저 따져 보도록 하자.</span></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><span style="background-color: #d9ead3;"><b style="text-align: left;">[4] </b><b style="text-align: left;">packet_crypt_wq</b><b style="text-align: left;">와 wg_packet_queue_init(decrypt) 함수의 상관 관계</b></span></div><div><div><span style="color: #b45f06;"><span style="background-color: white;">📌 packet_crypt_wg work queue의 목적은 data를 decrypt하는 것이다. 따라서 선택된 cpu에서 </span>wg_packet_decrypt_worker 함수가 </span><span style="color: #b45f06;">worker thread(kworker)에 의해서 수행된다.</span></div><div><span style="background-color: white; color: #b45f06;"><br /></span></div><div>1) work queue 할당 단계: packet_crypt_wq라는 이름의 work queue를 하나 만든다.</div><div>wg-><span style="color: #3d85c6;"><b>packet_crypt_wq</b> </span>= alloc_workqueue("wg-crypt-%s", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name);</div><div><br /></div><div>2) cpu 별 work 선언 및 work function 할당 단계 : 아래 함수를 이용하여 cpu 당 1개씩 필요한 work(struct work_struct)을 선언한다.</div><div>ret = <b><span style="color: #6aa84f;">wg_packet_queue_init</span></b>(&wg-><b><span style="color: #3d85c6;">decrypt_queue</span>,</b> <b>wg_packet_decrypt_worker</b>, MAX_QUEUED_PACKETS);</div><div><br /></div><div>3) cpu별 해당 work 수행 요청 단계: schedule 함수를 호출하여 <b>packet_crypt_wq work queue</b>에 대한 work 함수 즉, wg_packet_decrypt_worker 함수를 지정된 cpu에서 실행하도록 해준다.</div><div><div>wg_queue_enqueue_per_device_and_peer(&wg-><b><span style="color: #bf9000;">decrypt_queue</span></b>, &peer->rx_queue, skb,</div><div> wg-><b>packet_crypt_wq</b>, &wg->decrypt_queue.last_cpu) <i><span style="color: #999999;"> ... receive.c -> queueing.h</span></i></div></div><div>{</div><div><span> </span>queue_work_on(cpu, wq, &per_cpu_ptr(<b><span style="color: #bf9000;">device_queue</span></b>->worker, cpu)->work);</div><div>}</div><div style="text-align: justify;"><br /></div></div><div style="text-align: justify;">지금까지 wireguard에서 사용하는 주요 work queue code의 동작 원리를 살펴 보았다. 이 부분이 제대로 파악이 된다면, (이후 설명할) packet send/receive 흐름도 쉽게 이해가 될 것으로 믿는다.</div><div><br /></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">d) Peer 초기화 과정</b></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #333333;">peer.c의 </span><b style="background-color: white; color: #333333;">wg_peer_create( )</b><span style="background-color: white;"><span style="color: #333333;"> 함수는 </span><b><span style="color: #b45f06;">"wg set peer ..."</span> </b><span style="color: #333333;">명령 실행시 호출되는 함수로 peer를 create하는데 필요한 각종 설정을 초기화하고, peer를 hash table에 등록하는 역할을 한다. 또한 packet을 외부로 내보내기 위한 worker를 초기화하고,</span></span><span style="background-color: white; color: #333333;"> napi 함수를 등록하는 일도 수행한다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL2aFUeS5LJuhaNXCowwSTXG3CTtD7ZVuvyobUj2KEC1XywgRXdE_FMAoCD9UQ_tYbLZo5qE6n85ZL-bUbMk3Z2lSduJtMfIHRivsTLI9Zgge_KXGzTMlXPwVKvshhPSvjeKP3_A6xq5cksdYhs4CcFVyUsNW6dCJp8e9Mhmn2QluhptgTfIgMcxfpcg/s950/wg_peer_create1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="727" data-original-width="950" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL2aFUeS5LJuhaNXCowwSTXG3CTtD7ZVuvyobUj2KEC1XywgRXdE_FMAoCD9UQ_tYbLZo5qE6n85ZL-bUbMk3Z2lSduJtMfIHRivsTLI9Zgge_KXGzTMlXPwVKvshhPSvjeKP3_A6xq5cksdYhs4CcFVyUsNW6dCJp8e9Mhmn2QluhptgTfIgMcxfpcg/w400-h306/wg_peer_create1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX_rkQXAJskrrr_bdUVZVOUJ51_trTywlzqGL6uhv04JM100gtfEchnD6JHNLUl3jgHfBrLOm1-EHLk5ePeY9IAQawGyx2ENr_BvdhumQ9epubhJsSsDgB3HyXwxFDIJleIsbwNaLd3GB1fyW1K5jPe9a9FFhGhYtvkDhvRAmRztuNGndcVkuh0XLPtw/s947/wg_peer_create2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="426" data-original-width="947" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX_rkQXAJskrrr_bdUVZVOUJ51_trTywlzqGL6uhv04JM100gtfEchnD6JHNLUl3jgHfBrLOm1-EHLk5ePeY9IAQawGyx2ENr_BvdhumQ9epubhJsSsDgB3HyXwxFDIJleIsbwNaLd3GB1fyW1K5jPe9a9FFhGhYtvkDhvRAmRztuNGndcVkuh0XLPtw/w400-h180/wg_peer_create2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span style="text-align: center;">[그림 3.8] peer.c의 </span></span><span style="font-family: Nunito; text-align: left;">wg_peer_create( ) 함수의 주요 내용</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">e) Noise handshaking 흐름</b></span></div><div><span style="font-family: Nunito;">결국 WireGuard protocol의 핵심은 <b>noise handshaking</b>에 있다. H</span><span style="font-family: Nunito;">andshaking이 제대로 설명되기 위해서는 WireGuard packet의 format을 면밀히 검토해야 한다. 이와 관련해서는 이전 글에 상세히 설명해 두었으니, 여기서는 2개의 message 즉, Initiation 및 Response의 format만 보여주고 넘어가는 것으로 하겠다.</span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitgmkr7gQqPS0CddDpMrlfR0fS6pTy--VW2xXFjk0wnuyKILUP8pEbYrfMS7n-2_wZJN6LBFiv2iW5X1bLwa4nl5wO7hA99HNPrh5hMIfGcgG16OnrQmnQrLc38Fmx8OZCHj8cHiOG3EsOY6b-doW0ydOFD4G1_jqk6gbniiO2ylNMQ3wWTKs8WSMyFg/s772/wireguard_handshake_initiation_message.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="514" data-original-width="772" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitgmkr7gQqPS0CddDpMrlfR0fS6pTy--VW2xXFjk0wnuyKILUP8pEbYrfMS7n-2_wZJN6LBFiv2iW5X1bLwa4nl5wO7hA99HNPrh5hMIfGcgG16OnrQmnQrLc38Fmx8OZCHj8cHiOG3EsOY6b-doW0ydOFD4G1_jqk6gbniiO2ylNMQ3wWTKs8WSMyFg/w400-h266/wireguard_handshake_initiation_message.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.9] WireGuard Handshake Initiation Message Format(148 bytes) [출처: 참고문헌 8]</span></div></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtsAcF9VHkUbOGsCIGdMGnozx83Er1j3thoU_aL6S7Px06Cmq1ZIXlgkfkM7xL1pCpezii17PAddVXeMBo0Fuyi3B4lPBP1vSFxvsI4aTJJ38ryv-tLhPYIBshMQk_EJeWvG7UY04BJ-71oELvVCz4iljaDVd24RJARXsGw6Cd8gxnwr4AoRXW7Gz03g/s759/wireguard_response_message_format.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="340" data-original-width="759" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtsAcF9VHkUbOGsCIGdMGnozx83Er1j3thoU_aL6S7Px06Cmq1ZIXlgkfkM7xL1pCpezii17PAddVXeMBo0Fuyi3B4lPBP1vSFxvsI4aTJJ38ryv-tLhPYIBshMQk_EJeWvG7UY04BJ-71oELvVCz4iljaDVd24RJARXsGw6Cd8gxnwr4AoRXW7Gz03g/w400-h179/wireguard_response_message_format.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.10] WireGuard Handshake Response Message Format(92 bytes) </span><span style="font-family: Nunito; text-align: left;">[출처: 참고문헌 8]</span></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">아래 그림은 참고문헌 5 및 6에서 발췌한 것으로 WireGuard handshaking 과정을 한눈에 파악할 수 있도록 해준다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzHqvFx2whxTYm9-JsH-I5HWZOIJ2ocF8Nlf_NavYEuL3dC8NjbKCcQ99OOKDHfo7RA2O-asgAx1G2NRS7NiVAKXWyidH8Q-uYgb5s-lQM894Iu7r_vWPf76IDFUrA4Liz8EvtKcRGpTye8ZlH1lAYBTOsVh2AyUcnHmSjxQtyZ8SOHoQ8TBAJb01fcw/s1016/wireguard_handshaking.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="752" data-original-width="1016" height="474" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzHqvFx2whxTYm9-JsH-I5HWZOIJ2ocF8Nlf_NavYEuL3dC8NjbKCcQ99OOKDHfo7RA2O-asgAx1G2NRS7NiVAKXWyidH8Q-uYgb5s-lQM894Iu7r_vWPf76IDFUrA4Liz8EvtKcRGpTye8ZlH1lAYBTOsVh2AyUcnHmSjxQtyZ8SOHoQ8TBAJb01fcw/w640-h474/wireguard_handshaking.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.11] WireGuard handshaking [출처 - 참고문헌 5]</span></div></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 사실 WireGuard protocol 자체에 InitHello, RespHello라는 표현은 없다. 위의 그림에서는 이해를 돕기 위해 이러한 표현을 사용한 것으로 보인다.</span></span></div><div><br /></div><div><span style="font-family: Nunito;">또한, 아래 2개의 그림은 위의 wireguard handshaking 과정을 Initiation과 Response 각각으로 나누어 본 것이다. 이는 실제로 noise.c 파일의 내용과도 맥을 같이 하는데, 아래 실제 코드(4개의 함수)를 분석한 내용([step 1] ~ [step 4])을 보면서 자세한 의미를 파악해 보기 바란다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6poP2Ky4kyisTocXeC9hVixvCUU6uA3OXQjpbztgSRyiR1_H-wlIr0hDFMEOmk-Q2lyj9RDlnKOIJtihqdhQyyzQ5YoHrWC6Xc6RnNNsUEtv6Dm3hEUYYS1vgpTIiEyeDFItYbke2G2sRAZgo4WLpnTDlbXXRv7I97Nebz-HLGnWJIW01Kp4YxcojMA/s916/wireguard_ikpsk2_initiation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="459" data-original-width="916" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6poP2Ky4kyisTocXeC9hVixvCUU6uA3OXQjpbztgSRyiR1_H-wlIr0hDFMEOmk-Q2lyj9RDlnKOIJtihqdhQyyzQ5YoHrWC6Xc6RnNNsUEtv6Dm3hEUYYS1vgpTIiEyeDFItYbke2G2sRAZgo4WLpnTDlbXXRv7I97Nebz-HLGnWJIW01Kp4YxcojMA/w400-h200/wireguard_ikpsk2_initiation.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.12] WireGuard IKpsk2 Initiation [출처 - 참고문헌 6]</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZaKfFjiYsBCn-Gzerfy0mazDDY_LXN63zrLNZZJyYDcM2oJHT8AokE8nHwF8Wu2XAR_p41761UCU509Q7IVx07NXtkxl3_isoxR1UQOqjJuHmM_0asxAG-hRmiWE0WsYWZ1kToMwuXsjShzamqLm17-FiK_WrQnU2IZ4H4UuZ_8TEjXoerjB9c3FREA/s740/wireguard_ikpsk2_response.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="452" data-original-width="740" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZaKfFjiYsBCn-Gzerfy0mazDDY_LXN63zrLNZZJyYDcM2oJHT8AokE8nHwF8Wu2XAR_p41761UCU509Q7IVx07NXtkxl3_isoxR1UQOqjJuHmM_0asxAG-hRmiWE0WsYWZ1kToMwuXsjShzamqLm17-FiK_WrQnU2IZ4H4UuZ_8TEjXoerjB9c3FREA/w400-h244/wireguard_ikpsk2_response.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.13] WireGuard IKpsk2 Response</span><span style="font-family: Nunito; text-align: left;"> [출처 - 참고문헌 6]</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">WireGuard kernel code(noise.c)에서는 Noise Handshaking 즉, <b><span style="background-color: #fce5cd; color: #38761d;">Noise_IKpsk2</span></b>를 아래와 같이 정의하고 있다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div><span style="color: #a64d79; font-family: Nunito;"><b><div>/* This implements Noise_IKpsk2:</div><div> *</div><div> * <- s</div><div> * ******</div><div> * -> e, es, s, ss, {t} // Initiation Message(Initiator => Responder)</div><div> * <- e, ee, se, psk, {} // Response Message(Initator <= Responder)</div><div> */</div></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 사실 IKEv2나 (OpenVPN을 구성하는) TLS1.2/1.3 등은 (만들어진지 오래된 이유로) 대중에게 보다 널리 알려져 있지만, 상대적으로 Wireguard의 경우는 Hanshaking 과정이 많이 노출되어져 있지 않다. 하지만, 위의 내용이 wireguard handshaking의 전부이다. 결코 복잡하지 않다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="color: #e06666; font-family: Nunito;"><b>아주 간결하지만 안전한 Protocol Wireguard ~ 😋</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">Wireguard Handshaking 과정은 크게 보아, 아래 4개의 함수(noise.c 파일)로 설명이 가능하다.</span></div><div><br /></div><div><span style="font-family: Nunito;"><b>[Step 1] Initiator: IKpsk2 initiation</b></span></div><div><span style="font-family: Nunito;"><b><span style="color: #a64d79;">wg_noise_handshake_create_initiation() : </span><span style="color: #3d85c6;">Initiator -> Responder로 Initiation Message 전송시 Initiator가 담당하는 송신 처리 routine</span></b></span></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhSEu6nWVU6sR1gr1C4esqhZxbVqNsJF6QQ4w47KyRCpojYtkzgAjFFp2Zb4WhVCSmsLrq6X1ryPcpl0zFYDD7ZrXBBkacP3OLelJaLd06r0gyDavkDMt2vpZbWfFmax97z0dvqGTTTMnOg0gS8d32dFStZMpIsXhM0Vi7oNRGt2PDe7fqKL7NcZx0eg/s1209/noise_create_initation1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="869" data-original-width="1209" height="460" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhSEu6nWVU6sR1gr1C4esqhZxbVqNsJF6QQ4w47KyRCpojYtkzgAjFFp2Zb4WhVCSmsLrq6X1ryPcpl0zFYDD7ZrXBBkacP3OLelJaLd06r0gyDavkDMt2vpZbWfFmax97z0dvqGTTTMnOg0gS8d32dFStZMpIsXhM0Vi7oNRGt2PDe7fqKL7NcZx0eg/w640-h460/noise_create_initation1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNeum_a-dMq7W1p979GFP87DWlDVv6O4KO-JlQvSSV8zgfC4XIOhdjLyRuQn6V9bbVPydqP6X-udQk7mSXtdP10EnL0sC8nDjRYhpHZun_m-iAq1LWRgZFtE16nkXHGEVEvP08-Hg47CXmnlkxbplwBMUDte8pUsGHDNrdbmrxTRHPbqQJ0BPTqwvRzg/s1161/noise_create_initiation2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="674" data-original-width="1161" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNeum_a-dMq7W1p979GFP87DWlDVv6O4KO-JlQvSSV8zgfC4XIOhdjLyRuQn6V9bbVPydqP6X-udQk7mSXtdP10EnL0sC8nDjRYhpHZun_m-iAq1LWRgZFtE16nkXHGEVEvP08-Hg47CXmnlkxbplwBMUDte8pUsGHDNrdbmrxTRHPbqQJ0BPTqwvRzg/w640-h372/noise_create_initiation2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEpGvXeAEbhMMUj51Or5DN0uVo55quFu55p-p4nOzh3KE0WA8dVzOy8DftW6gi030wiIG_g_WVq-YtSglah_8q1m_KwC7O_9GRp8c8E-CH2bxZ0eRmBYIbzRw0EONfmm3ls8X9c2chLOiWD6McvZyDZf8KRLd4nZxSrW8kY4TOM9LQNle4UcuRPxD41Q/s1036/noise_create_initiation3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="580" data-original-width="1036" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEpGvXeAEbhMMUj51Or5DN0uVo55quFu55p-p4nOzh3KE0WA8dVzOy8DftW6gi030wiIG_g_WVq-YtSglah_8q1m_KwC7O_9GRp8c8E-CH2bxZ0eRmBYIbzRw0EONfmm3ls8X9c2chLOiWD6McvZyDZf8KRLd4nZxSrW8kY4TOM9LQNle4UcuRPxD41Q/w640-h358/noise_create_initiation3.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.14] </span><span style="font-family: Nunito; text-align: left;">wg_noise_handshake_create_initiation() 함수 내부 흐름 분석</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div><b>[Step 2] Responder: IKpsk2 initiation</b></div><div><b><span style="color: #a64d79;">wg_noise_handshake_consume_initiation() </span></b><b style="color: #a64d79;">: </b><b><span style="color: #3d85c6;">Initiator -> Responder로 Initiation Message 전송시 Responder가 담당하는 수신 처리 routine</span></b></div></span><span style="font-family: Nunito;"><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih6jF7690GGMbjSalyhpDsaXPAIqHejBlOSQKq8lfe6PBp9dwXA_2getxQboc30j4dA8EFighlcjk52sB9YL7QfbzoT7xbbi3jAfKBPZnvMfNWJANxpqrHuB-RtnSLDkK7iGnUQUoVuSjQUQS1zvHeILrNGuy1GRyN-X6B8gI4HeDwR-wo4EI0Z2uxlw/s1301/noise_comsume_initiation1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="918" data-original-width="1301" height="452" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih6jF7690GGMbjSalyhpDsaXPAIqHejBlOSQKq8lfe6PBp9dwXA_2getxQboc30j4dA8EFighlcjk52sB9YL7QfbzoT7xbbi3jAfKBPZnvMfNWJANxpqrHuB-RtnSLDkK7iGnUQUoVuSjQUQS1zvHeILrNGuy1GRyN-X6B8gI4HeDwR-wo4EI0Z2uxlw/w640-h452/noise_comsume_initiation1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx1xO2mWuCtXKvWGVslJSJ1Z26LtUtd-yHcIXnvnhLgyrnP4uLhbUGCshagGZDHJ8kmO8qAxHVkjatKLWa1gPhHBlenSGvNa5xVto0ctti9uIiXbPt-2bn6MZjRvsLg0ih1SDM702QZpqGT0kJ7Y_efG0JGkcZd2YIbQSvTDDmMh_7sRvU7DogsITRNQ/s1374/noise_consume_initiation2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="650" data-original-width="1374" height="302" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx1xO2mWuCtXKvWGVslJSJ1Z26LtUtd-yHcIXnvnhLgyrnP4uLhbUGCshagGZDHJ8kmO8qAxHVkjatKLWa1gPhHBlenSGvNa5xVto0ctti9uIiXbPt-2bn6MZjRvsLg0ih1SDM702QZpqGT0kJ7Y_efG0JGkcZd2YIbQSvTDDmMh_7sRvU7DogsITRNQ/w640-h302/noise_consume_initiation2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.15] wg_noise_handshake_consume_initiation() 함수 내부 흐름 분석</span></div><div><br /></div><div><div><b>[Step 3] Responder: IKpsk2 response</b></div><div><b><span style="color: #a64d79;">wg_noise_handshake_create_response() </span></b><b style="color: #a64d79;"> : </b><b><span style="color: #3d85c6;">Responder -> Initiator로 Response Message 전송시 Responder가 담당하는 송신 처리 routine</span></b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRhW77ItmHcX_jlmrCqoR02l6qRrd6LhdJp-qYNNEX7a9MdP6Ox4aiS-_kttpTVKyhmuCMnfl8uCyi4yOQ09b2eeavr5bJFU5leJ_HQxpwsDloVkKI5msy-27vycRwtSEDh3vKVTpdWm9DQvgas-9hUG0_DVp4QIZbCcBG8Qo4MJbi_9MlhgP1eRbVHg/s1321/noise_create_reponse1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="875" data-original-width="1321" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRhW77ItmHcX_jlmrCqoR02l6qRrd6LhdJp-qYNNEX7a9MdP6Ox4aiS-_kttpTVKyhmuCMnfl8uCyi4yOQ09b2eeavr5bJFU5leJ_HQxpwsDloVkKI5msy-27vycRwtSEDh3vKVTpdWm9DQvgas-9hUG0_DVp4QIZbCcBG8Qo4MJbi_9MlhgP1eRbVHg/w640-h424/noise_create_reponse1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9pnv6PEY-pa454tFPdv2zVK1QD7-qE7Ttvyw0aP9XDVTBL1omFO25Wc7hwqWCdPlzVTXUbwKQpYheSBsZPoNjiFe7WeqqXJk0OC1MiOPDVbOo6KNHURo3Xe-atBqbPcO5iF7JuZNwpcU0HXy8fnjDNjXEEmbvdmYQShIGyQkGp2pCR2UHddg0HejUiw/s1264/noise_create_reponse2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="486" data-original-width="1264" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9pnv6PEY-pa454tFPdv2zVK1QD7-qE7Ttvyw0aP9XDVTBL1omFO25Wc7hwqWCdPlzVTXUbwKQpYheSBsZPoNjiFe7WeqqXJk0OC1MiOPDVbOo6KNHURo3Xe-atBqbPcO5iF7JuZNwpcU0HXy8fnjDNjXEEmbvdmYQShIGyQkGp2pCR2UHddg0HejUiw/w640-h246/noise_create_reponse2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.16] wg_noise_handshake_create_response() 함수 내부 흐름 분석</span></div><div><br /></div><div><div><b>[Step 4] Initiator: IKpsk2 response</b></div><div><b><span style="color: #a64d79;">wg_noise_handshake_consume_response() </span></b><b style="color: #a64d79;">: </b><b><span style="color: #3d85c6;">Responder -> Initiator로 Response Message 전송시 Initiator가 담당하는 수신 처리 routine</span></b></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkhw_EiklKDJyElS0qNlCMEmw7MxcYGh1XFr1XxeqvuhEia0_HFXAL95TuatCaJJa66T8vtBYJKdxNaIpOeioXA2bRQTdKNCFN-CRz66zrOzprBmytyK5uCTnEmSPdyohRsFy40B4B0D72mP_7TLc6UjrT9hpUpUuwsKZTTHhGB07N_hTOgISLicsnPw/s1064/noise_consume_response1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="874" data-original-width="1064" height="526" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkhw_EiklKDJyElS0qNlCMEmw7MxcYGh1XFr1XxeqvuhEia0_HFXAL95TuatCaJJa66T8vtBYJKdxNaIpOeioXA2bRQTdKNCFN-CRz66zrOzprBmytyK5uCTnEmSPdyohRsFy40B4B0D72mP_7TLc6UjrT9hpUpUuwsKZTTHhGB07N_hTOgISLicsnPw/w640-h526/noise_consume_response1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnbfyoCSvLqCwKM4gO0zDO6_vzZh5PTSWLkMWo0KBN4o1nhc-NHaucdS_GKYuHu8W6Yx4TuxUWmr7XeDd2_9sU9kkkrSc10U44X3sGT62ydIhlOudFnQxWGa1H1HU0SCEx0z5UafFdf2KgZVpVG7OIERtFuOKGkZxBXZbU88GW2B4WDetWhpTUDjjZxA/s946/noise_consume_response2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="366" data-original-width="946" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnbfyoCSvLqCwKM4gO0zDO6_vzZh5PTSWLkMWo0KBN4o1nhc-NHaucdS_GKYuHu8W6Yx4TuxUWmr7XeDd2_9sU9kkkrSc10U44X3sGT62ydIhlOudFnQxWGa1H1HU0SCEx0z5UafFdf2KgZVpVG7OIERtFuOKGkZxBXZbU88GW2B4WDetWhpTUDjjZxA/w640-h248/noise_consume_response2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.17] </span><span style="font-family: Nunito; text-align: left;">wg_noise_handshake_consume_response() </span><span style="font-family: Nunito; text-align: left;">함수 내부 흐름 분석</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Noise handshaking을 하는 최종 목적은 ChaCha20Poly1305 암호 함수를 돌릴 때 사용하는 대칭키(특별히 sending, receiving용 각각 1개씩 2개 존재함)를 양쪽이 모두 동일하게 공유하기 위해서이다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div></span></div><div><span style="font-family: Nunito;">이렇게 noise handshaking이 완료되고 나면, 최종적으로 양쪽 모두에서 아래 함수(<b>wg_noise_handshake_begin_session</b>)가 호출된다. 이 함수가 하는 일은, noise keypair buffer를 할당하고, derive_keys() 함수를 이용하여 handshake->chaining_key 값으로 부터 sending용 대칭키와 receiving용 대칭키를 유도해 내는 것이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">____________________________________________</span></div><div><span style="font-family: Nunito;"><i><div>struct noise_keypair {</div><div> struct index_hashtable_entry entry;</div><div> struct noise_symmetric_key <span style="color: #cc0000;">sending;</span></div><div> atomic64_t sending_counter;</div><div> struct noise_symmetric_key <span style="color: #cc0000;">receiving</span>;</div><div> struct noise_replay_counter receiving_counter;</div><div> __le32 remote_index;</div><div> bool i_am_the_initiator;</div><div> struct kref refcount;</div><div> struct rcu_head rcu;</div><div> u64 internal_id;</div><div>};</div></i></span></div><div><span style="font-family: Nunito;">____________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmtgS_ILLfbezuufAlSjEkZIEZX5DaURU10QEiY9cT_h_eUC9-cBtw3CfzbUoO-lDuPdkl80W3JNmmkkxVlEAGjDl6bp0HawX88u0KBmfHfVKysVVH8iJTKbyCltl5Zyp3f-sNv6ipXO5dqfrc02TkR7RPsHRQ3kVwT9mWt_mIhvwDFzc9aqbmiJSSng/s835/noise_handshake_begin_session.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="835" data-original-width="707" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmtgS_ILLfbezuufAlSjEkZIEZX5DaURU10QEiY9cT_h_eUC9-cBtw3CfzbUoO-lDuPdkl80W3JNmmkkxVlEAGjDl6bp0HawX88u0KBmfHfVKysVVH8iJTKbyCltl5Zyp3f-sNv6ipXO5dqfrc02TkR7RPsHRQ3kVwT9mWt_mIhvwDFzc9aqbmiJSSng/s320/noise_handshake_begin_session.png" width="271" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.18] </span><span style="font-family: Nunito; text-align: left;">wg_noise_handshake_begin_session() 함수</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #e69138; font-family: Nunito;"><b><여기서 잠깐></b></span></div><div><span style="color: #b45f06; font-family: Nunito;">Wireguard에서 chaining key와 shared secret을 만드는 과정은 ?</span></div><div><span style="font-family: Nunito;">Wireguard는 아래와 같은 과정(실제로는 더 4번보다 많이 함)을 통해 chaining key를 만들고, 이로 부터 shared secret 키 값을 유도해내게 된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjghp8YjGlr9SiLpeAj5JVtkU66w0D-06jvFR0TF7YHUoQ4fFbNCAXH0BnuGPXcobhvMVj9UqnNah3NERK3a5MZ8MO9aNuqnvpYLUo25CIVKeEEEYiguhxer8YFk0FDySxPWJ-yPbc5EyKqp0SesNuT8R8gks8TKX1iJ2QUyQyBQq4h9Jpuob2iXbKpiA/s577/wireguard_kdf.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="577" data-original-width="345" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjghp8YjGlr9SiLpeAj5JVtkU66w0D-06jvFR0TF7YHUoQ4fFbNCAXH0BnuGPXcobhvMVj9UqnNah3NERK3a5MZ8MO9aNuqnvpYLUo25CIVKeEEEYiguhxer8YFk0FDySxPWJ-yPbc5EyKqp0SesNuT8R8gks8TKX1iJ2QUyQyBQq4h9Jpuob2iXbKpiA/s320/wireguard_kdf.PNG" width="191" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.19] Wireguard chaining key 및 shared secret 생성 과정</span></div></div><div><span style="font-family: Nunito;">________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">f) Peer lookup 과정</b></span></div><div><span style="font-family: Nunito;">Wireguard에는 (noise handshaking 과정에서 사용하기 위한) 2개의 hash table이 존재한다. 하나는 <b>peer public key 기반의 hash table</b>이고, 다른 하나는 <b>index(정확하게는 receiver_index)를 기준으로 하는 hash table</b>이 그것이다. </span><span style="font-family: Nunito;">Hash table이 사용되는 경우는 handshaking message를 수신한 후, public key or index를 이용하여 원하는 정보 즉, peer 값 or handshake에 필요한 정보를 찾을 때이다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Wireguard는 hash table을 위해서 siphash라는 방식을 사용한다. SipHash는 PRF(Pseudo Random Function)의 일종이며, 일반적인 hash table의 문제인 flooding attack을 막아주는 hash table로 이해하면 좋을 듯 하다. SipHash는 생각보다 조금 복잡하다. 관심 있는 분들은 아래 site 내용을 참조하도록 하자.</span></div><div style="text-align: center;"><span style="background-color: white; font-size: 14.85px;"><span style="color: #b45f06; font-family: Nunito;"><a href="https://en.wikipedia.org/wiki/SipHash">https://en.wikipedia.org/wiki/SipHash</a></span></span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div><span style="color: #45818e; font-family: Nunito;"><b style="background-color: #fff2cc;"><Public key 기반의 Hash Table></b></span></div><div><span style="font-family: Nunito;">public key 기반의 hash table은 아래와 같은 모습이며, add/remove/lookup과 같은 operation 함수 등을 갖고 있다. 이중 lookup() 함수는 wg_noise_handshake_consume_initiation() 함수 즉, Initiation message를 수신 처리하는 과정에서 사용된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZNk0BYoYUemW_gkdk8MGOiiwK1gB0A3hIoBd0dUkBl29jhFYHFbL7q1VsHOQZr7G9yJPnlmhMWgShIc7lZWIMNz3OhplZy2YWUc_fQ3glIgTTUgMGjoLRa7EpvkIMjtFRYVNOxnvfzhISrWGwSRrjsZAcQYds-tVnn-PDUjn2vRZ-x4HHsHlPrEgZEQ/s346/wireguard_pubkey_hashtable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="127" data-original-width="346" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZNk0BYoYUemW_gkdk8MGOiiwK1gB0A3hIoBd0dUkBl29jhFYHFbL7q1VsHOQZr7G9yJPnlmhMWgShIc7lZWIMNz3OhplZy2YWUc_fQ3glIgTTUgMGjoLRa7EpvkIMjtFRYVNOxnvfzhISrWGwSRrjsZAcQYds-tVnn-PDUjn2vRZ-x4HHsHlPrEgZEQ/s320/wireguard_pubkey_hashtable.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.20] </span><span style="font-family: Nunito; text-align: left;">wireguard public key 기반 hash table</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMmFlOjQ6RlmSIdJim_ZlHgkYJZYvRQT-VJQWV78K2te7iX1jjGRE8wqefhXpPtJZbhjfTR3PCV1nx6U2D1lvGr865uquU_EnH6ajeBb2Gp9B6D7lEfEYaq_iSnzwRil1vEtxb8y-tmozM_Uu6WGM0Ajxkgm0Q7k_urdU2SyosXjyeVEZ40OIZfOAP6w/s656/wireguard_pubkey_hashtable_lookup.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="656" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMmFlOjQ6RlmSIdJim_ZlHgkYJZYvRQT-VJQWV78K2te7iX1jjGRE8wqefhXpPtJZbhjfTR3PCV1nx6U2D1lvGr865uquU_EnH6ajeBb2Gp9B6D7lEfEYaq_iSnzwRil1vEtxb8y-tmozM_Uu6WGM0Ajxkgm0Q7k_urdU2SyosXjyeVEZ40OIZfOAP6w/w400-h214/wireguard_pubkey_hashtable_lookup.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.21] </span><span style="font-family: Nunito; text-align: left;">wireguard public key 기반 hash table lookup</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">참고로, 아래 코드는 public key 기반의 hash table을 위한 pubkey_bucket() 함수의 모습이며, 이 안에서 <b>siphash()</b> 함수가 호출된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX_L3MtuaM3aIZfJjrmRSgDj8jAAzKkStNmUqsq-l3s0r3TWlSvuRCi1-MG7Fwwm4PZgVsyxxnNlDTlCc-Y2b7nWbi_DigI0Fcfm93zzfXDWREqf7LAAGKU0KkvzixP8kd1zZJnJESuCofmsTlq2iTszaFVdmWsALLKPuIVV4Mkia4A331pe6yPg2iHg/s693/wireguard_pubkey_hashtable_bucket.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="216" data-original-width="693" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX_L3MtuaM3aIZfJjrmRSgDj8jAAzKkStNmUqsq-l3s0r3TWlSvuRCi1-MG7Fwwm4PZgVsyxxnNlDTlCc-Y2b7nWbi_DigI0Fcfm93zzfXDWREqf7LAAGKU0KkvzixP8kd1zZJnJESuCofmsTlq2iTszaFVdmWsALLKPuIVV4Mkia4A331pe6yPg2iHg/w400-h125/wireguard_pubkey_hashtable_bucket.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.22] </span><span style="font-family: Nunito; text-align: left;">wireguard public key 기반 hash table - </span><span style="font-family: Nunito; text-align: left;">pubkey_bucket() 함수</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="color: #45818e; font-family: Nunito;"><b style="background-color: #fff2cc;"><Index 기반의 Hash Table></b></span></div><div><span style="font-family: Nunito;">한편, index 기반의 hash table은 아래와 같은 모습이며, insert/replace/</span><span style="font-family: Nunito;">remove/lookup 등과 같은 operation 함수를 갖고 있다.</span><span style="font-family: Nunito;"> 이중 lookup() 함수는 </span><span style="font-family: Nunito;">wg_noise_handshake_consume_response() 함수 즉, Response message를 수신 처리하는 과정에서 사용된다.</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFzWLLbpuGykSbpAqIRraZTIaaGfkR_a-75bg2ZAQHaawZpcY3CS7kkm_HG0xI4-Fmshus5mydlhEvte_4X15HJ24esaOFksCFGn7WCWk2aci1D5Dqo0yOZ8WvNWhpKWdbVmUxrtE7D4k8B3zcxiz80SSUpQhFFKGq8WcdyYEDiazUDIw_NKurtEJiHQ/s353/wireguard_index_hashtable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="114" data-original-width="353" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFzWLLbpuGykSbpAqIRraZTIaaGfkR_a-75bg2ZAQHaawZpcY3CS7kkm_HG0xI4-Fmshus5mydlhEvte_4X15HJ24esaOFksCFGn7WCWk2aci1D5Dqo0yOZ8WvNWhpKWdbVmUxrtE7D4k8B3zcxiz80SSUpQhFFKGq8WcdyYEDiazUDIw_NKurtEJiHQ/s320/wireguard_index_hashtable.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.23] </span><span style="font-family: Nunito; text-align: left;">wireguard index 기반 hash table</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXzQId3K9qB-dHc-LQ2GjD8IG3jbrrvue85tukvEJh3SZbgNVMZapVdgWd3ZzjCJ4RP3jIc1Z8u8cgzdHvQWDw6jnw79xkgBt1aeda74h2IjRp2k-HxAOt1p-apX0DyhJfr84sfcbXTOSe3SzxSYVT-jkOGP6TNtVyK6YTmGhUd6ITTO0pcgqY0QvJKw/s653/wireguard_index_hashtable_lookup.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="470" data-original-width="653" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXzQId3K9qB-dHc-LQ2GjD8IG3jbrrvue85tukvEJh3SZbgNVMZapVdgWd3ZzjCJ4RP3jIc1Z8u8cgzdHvQWDw6jnw79xkgBt1aeda74h2IjRp2k-HxAOt1p-apX0DyhJfr84sfcbXTOSe3SzxSYVT-jkOGP6TNtVyK6YTmGhUd6ITTO0pcgqY0QvJKw/w400-h288/wireguard_index_hashtable_lookup.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.24] </span><span style="font-family: Nunito; text-align: left;">wireguard index 기반 hash table lookup</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div><div><div><span style="background-color: #fff2cc;"><b><여기서 잠깐 !></b></span></div><div><i style="color: #3d85c6; font-weight: bold;"> => </i><i><b style="color: #3d85c6;">WireGuard message format을 보면 어디에도 peer의 endpoint(ip & port) 정보가 포함되어 있지 않다. 그렇다면 wireguard는 여러 peer(peer table) 중에서 정확하게 원하는 peer 하나를 어떻게 찾아 낼 수 있을까 ? .... </b><span style="color: #999999;">이 내용은 지난 blog post에 게재된 내용이다. 약간의 내용 보강을 해 보도록 하자.</span></i></div></div><div><i><br /></i></div><div>그 해답은 static public key와 index(sender, receiver) 필드에 있다.</div><div><span style="text-align: center;">[그림 3.9, 3.10] Handshake Initiation Message Format을 보면, initiator는 첫번째 DH() 결과로 얻은 key 값 즉, ck2를 이용하여 자신의 static public key를 암호화한 후, </span>random하게 생성된 index(local identifier) 값 등과 함께 handshake initiation message를 구성 후, 이를 responder에게 전달한다.<br /></div></div><div>Message를 수신한 responder는 역시 DH()를 이용해 ck2를 얻은 후, initiator가 암호화해서 보내준 static public key를 복호화하게 되고, <span style="color: #cc0000;">이를 이용해 peer(initiator)가 누구인지를 1차적으로 알게 된다(여기에서 public key 기반 hash table lookup 과정을 수행함).</span> 이후 responder는 initiator로 부터 받은 sender index 값을 receiver index에 넣고, 역시 자신이 random하게 생성한 sender index 값 등으로 Handshake Response Message를 만들어 initiator에게 돌려 보낸다.</div><div>Responder로 부터 handshake response message를 수신한 initiator는 receiver index 필드 값이 자신이 전에 만들어 보낸 index 값인지를 확인하게되고, <span style="color: #cc0000;">이를 통해 peer table에서 원하는 peer를 정확하게 선택할 수 있게 된다(여기에서 index 기반 hash table lookup을 수행함).</span></div><div>따라서, 앞서 설명한 static public key 및 sender/receiver index 값은 initiator 및 responder 각각에서 운용하는 peer table<span style="color: #cc0000;">(pubkey hash table & index hash table)</span>에서 원하는 peer를 lookup하는데 사용하는 값으로 해석될 수 있다.</div><div>_______________________________</div><div><br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;" /></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">g) Handshaking 및 data packet send/receive 흐름</b></span></div><div><span style="font-family: Nunito;">Noise handshaking code 못지 않게 중요한 코드는 <b>tunneling 처리를 위한 송/수신 패킷 handling 부분</b>이 아닐까 싶다. 이 부분은 이전 blog post에 충분히 설명한 내용이긴 하지만, 그래도 몇가지 부족한 부분이 있어 좀 더 보충해 보고자 한다(<span style="color: #f1c232;">앞서 설명한 work queue와도 밀접한 관계가 있다</span>).</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 </span><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white;">참고로, send(encrypt)는 linux netdevice와 udp_tunnel.ko 코드(</span>net/ipv4/udp_tunnel_core.c)에 대한 사전 지식이 필요하며, recv(decrypt) 코드는 socket, skb와 NAPI에 대한 어느 정도의 지식이 필요하다. </span><span style="font-family: Nunito;"><span style="color: #b45f06;">예전에는 linux tcp/ip stack 하부단 구조를 파악하기 위해 아래와 같은 책을 많이 보기도 했다. 근데, 요즘에는 이런 훌륭한 책이 안보인다.</span></span></div><div style="text-align: center;"><b><span style="font-family: Nunito;">Understanding Linux Network Internals 😍</span></b></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="background-color: #fce5cd;"><Handshake packet 송/수신></b></span></div><div><span style="font-family: Nunito;"><b><i>1) handshake packet 송신</i></b></span></div><div><span style="font-family: Nunito;">handshake을 시작하는 부분은 wg_open, wg_xmit, set_peer 함수 등 총 5군데가 있다. 즉, device를 초기화(open, xmit)하거나, peer를 설정하거나, handshaking이 timeout(2분 간격)되거나, keepalive packet을 내보내기 시작하는 순간에 noise handshaking은 시작될 수 있다는 뜻이다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKpAbZ2ZtTTfLmch0pujh-tXlZ7baEHpAbsGmOLr7JAKPBCNY1q2vjY_x6Jz4JNPI33eiHPzBnVvMhCEk81WH_D1P9PIWc1PBZKLGdCu-ne7fa-ml1sUGbydFspGt_qtKE-LNVqSKjChkZR2HuvoJfAoWJh24KsOK3Flga-fX-gd33LCWEgDtLSLwIug/s400/wg_handshake_tx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="246" data-original-width="400" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKpAbZ2ZtTTfLmch0pujh-tXlZ7baEHpAbsGmOLr7JAKPBCNY1q2vjY_x6Jz4JNPI33eiHPzBnVvMhCEk81WH_D1P9PIWc1PBZKLGdCu-ne7fa-ml1sUGbydFspGt_qtKE-LNVqSKjChkZR2HuvoJfAoWJh24KsOK3Flga-fX-gd33LCWEgDtLSLwIug/w400-h246/wg_handshake_tx_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.25] </span><span style="font-family: Nunito; text-align: left;">wireguard handshake tx flow</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><i><b>2) handshake packet 수신</b></i></span></div><div><span style="font-family: Nunito;">socket.c 파일 안에는, 아래와 같이 udp tunnel packet(encapsulation packet) 수신 함수를 등록하는 부분이 나온다.</span></div><div><span style="font-family: Nunito;">_______________________________________________</span></div><div><span style="font-family: Nunito;"><div style="font-style: italic;"> struct udp_tunnel_sock_cfg cfg = {</div><div style="font-style: italic;"> .sk_user_data = wg,</div><div style="font-style: italic;"> .encap_type = 1,</div><div style="font-style: italic;"> .encap_rcv = <b><span style="color: #b45f06;">wg_receive</span></b></div><div style="font-style: italic;"> }</div><div style="font-style: italic;"><br /></div><div style="font-style: italic;"> udp_sock_create(net, &port4, &new4) //wg_socket_init( ) <- wg_open( )</div><div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-style: normal;">📌 </span><span style="color: #b45f06;">kernel에서 udp socket create/bind/connect 호출, wireguard packet은 udp 이므로 수신시 wg_receive가 호출</span></div></span></div><div><span style="font-family: Nunito;"><i> setup_udp_tunnel_sock(net, new4, &cfg)</i></span></div><div><span style="font-family: Nunito;">_______________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">handshake packet 수신 flow는 이 함수(wg_receive)로 부터 시작한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPt9AGH36U_UFG7rvf6GYWZMMbkSSj1NaIanSnOBuoaLGsRdeLrQvxfhJ4UWpCdNtowC-TytEvLjnBPRUx86HiS1hn06N2hMM_rHdJVlE25HwgVGifZjBN221-fpIDum7zj1NrBBkpOIEXwHXVBf6Z3vMvrVw6rD3P87q5G0mYJLeowO2Q7Sqp_RZtg/s986/wg_handshake_rx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="538" data-original-width="986" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPt9AGH36U_UFG7rvf6GYWZMMbkSSj1NaIanSnOBuoaLGsRdeLrQvxfhJ4UWpCdNtowC-TytEvLjnBPRUx86HiS1hn06N2hMM_rHdJVlE25HwgVGifZjBN221-fpIDum7zj1NrBBkpOIEXwHXVBf6Z3vMvrVw6rD3P87q5G0mYJLeowO2Q7Sqp_RZtg/w400-h218/wg_handshake_rx_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.26] </span><span style="font-family: Nunito; text-align: left;">wireguard handshake rx flow</span></div><div><br /></div><div><span style="font-family: Nunito;"><b style="background-color: #fce5cd;"><실제 data 송/수신></b></span></div><div><span style="font-family: Nunito;"><b><i>1) 실제 data 송신(udp 터널 encapsulation)</i></b></span></div><div><span style="font-family: Nunito;">Wireguard는 netdevice(wg0, wg1 ...)형태로 구성되어 있다. 따라서 packet 송신은 xmit 함수에서 부터 시작한다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 netdevice는 network driver를 구현할 때 필수적으로 등장하는 개념이다. Wireguard 역시 virtual interface를 생성하고 운용하는 방식이므로 기본적으로 netdevice 형태를 띈다.</span></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;">________________________________________________</span></span></div><div><div><span style="font-family: Nunito;"><i>static const struct net_device_ops netdev_ops = {</i></span></div><div><span style="font-family: Nunito;"><i> .ndo_open = wg_open,</i></span></div><div><span style="font-family: Nunito;"><i> .ndo_stop = wg_stop,</i></span></div><div><span style="font-family: Nunito;"><i> .ndo_start_xmit = <b>wg_xmit</b>,</i></span></div><div><span style="font-family: Nunito;"><i> .ndo_get_stats64 = dev_get_tstats64</i></span></div><div><span style="font-family: Nunito;"><i>};</i></span></div></div><div><span style="font-family: Nunito;"><span style="background-color: white;">________________________________________________</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFzpH8mBwSwDosOPYTPrdSdaol831CbSmzimkgGq3ynWORo6UvN6jPZ4a3ikT_vmY4u5JEBlkHm6BWQ0Zz7IiZQ6qzUeOi4sVcj0jdwteGYf6nWAG2FZX6XFOvVstuE4pfUU0NaZfBw2av9jUAi_vRRplyVWt0HixAc4rXzw_dRHScKeQxtGjfW0kyVw/s1044/wg_packet_tx_flow1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="884" data-original-width="1044" height="542" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFzpH8mBwSwDosOPYTPrdSdaol831CbSmzimkgGq3ynWORo6UvN6jPZ4a3ikT_vmY4u5JEBlkHm6BWQ0Zz7IiZQ6qzUeOi4sVcj0jdwteGYf6nWAG2FZX6XFOvVstuE4pfUU0NaZfBw2av9jUAi_vRRplyVWt0HixAc4rXzw_dRHScKeQxtGjfW0kyVw/w640-h542/wg_packet_tx_flow1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxubIrDlzzvaBYpjNDLwPanWM2Tn8W6yDQ49_rPrOGdufe7uPbuXEptTDr92G9thBO1SYNewY47c7BOxzKrNV-QCPS-s0Tp03bN77CVStygbWgjhV-T-2sTqY6Rm0emN6uAYnb1MITcKSpOjSqWXnRjnc4l4mz04AGq5j7138ZhkXl39SVjULK7aU1BA/s1055/wg_packet_tx_flow2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="179" data-original-width="1055" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxubIrDlzzvaBYpjNDLwPanWM2Tn8W6yDQ49_rPrOGdufe7uPbuXEptTDr92G9thBO1SYNewY47c7BOxzKrNV-QCPS-s0Tp03bN77CVStygbWgjhV-T-2sTqY6Rm0emN6uAYnb1MITcKSpOjSqWXnRjnc4l4mz04AGq5j7138ZhkXl39SVjULK7aU1BA/w640-h108/wg_packet_tx_flow2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.27] 실제 data에 대한 </span><span style="font-family: Nunito; text-align: left;"> tx flow(1)</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">실제 data에 대한 tx flow를 task(thread) 관점에서 재 정리해 보면 다음과 같다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd0YSjDCSvq_Czg4IrUMPLjhSNkpLW4aJuYYWdaGACYdlxNeHArBpWFgKGYcMfipi_NyO2mOjVM3AItuR063IlZ2CM8UyYNh9MRtbBWwUtXWDJ_QJOr6udsJCVZqEQC_BYxjvaCZQ5Q-GcRq2HzLyW9_3ukiwq6e2b2vLM1Ld4x3QhtNbhHFRPZ4dgrw/s1052/wg_packet_tx_flow_again.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="430" data-original-width="1052" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd0YSjDCSvq_Czg4IrUMPLjhSNkpLW4aJuYYWdaGACYdlxNeHArBpWFgKGYcMfipi_NyO2mOjVM3AItuR063IlZ2CM8UyYNh9MRtbBWwUtXWDJ_QJOr6udsJCVZqEQC_BYxjvaCZQ5Q-GcRq2HzLyW9_3ukiwq6e2b2vLM1Ld4x3QhtNbhHFRPZ4dgrw/w640-h262/wg_packet_tx_flow_again.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.28] 실제 data에 대한 </span><span style="font-family: Nunito; text-align: left;"> tx flow(2)</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><i><b>2) 실제 data 수신(udp 터널 decapsulation)</b></i></span></div><div><span style="font-family: Nunito;">실제 data에 대한 수신 flow 역시 <b>wg_receive( ) </b>함수로 부터 시작한다. 역시 중간 쯤에 있는 queue_work_on( ) 함수가 수행되는 시점 이후에는 (지정된 cpu에서 수행되는) kworker worker thread에 의해 wg_packet_decrypt_worker( ) work function이 실행되는 것을 알 수 있다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7F49H9kLu37ca1RGCN5tpdk9xUbV8L4A93vIc0ZqkTF46BigH78eFklSb68CQjYxzt1JJ2jbjBCkmOoXgngLbB6ZhmxzBBBIHvAIEcuwFfDW97SV8Cr_enloSM6UUwW2oFDEKhxB-Tux7-s-kV0SI4lQjaPVa_W9_VdJc75LC2VxxVH_4LgWbXvFUzA/s1093/wg_packet_rx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="687" data-original-width="1093" height="402" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7F49H9kLu37ca1RGCN5tpdk9xUbV8L4A93vIc0ZqkTF46BigH78eFklSb68CQjYxzt1JJ2jbjBCkmOoXgngLbB6ZhmxzBBBIHvAIEcuwFfDW97SV8Cr_enloSM6UUwW2oFDEKhxB-Tux7-s-kV0SI4lQjaPVa_W9_VdJc75LC2VxxVH_4LgWbXvFUzA/w640-h402/wg_packet_rx_flow.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.29] 실제 data에 대한 </span><span style="font-family: Nunito; text-align: left;"> rx flow</span></div><div><br /></div><div><div><span style="font-family: Nunito;">__________________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><여기서 잠깐></b></span></div><div><span style="color: #b45f06; font-family: Nunito;">peer.c에 보면 wg_peer_create( ) 함수를 호출하면서 <b>netif_napi_add( ) </b>함수가 호출되는데, 여기에 사용된 callback 함수 <b>wg_packet_rx_poll( )</b>와 앞서 설명한 <b>wg_receive( )</b> 함수의 관계는 어떻게 되는가 ?</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;"><b>wg_peer_create()</b><span style="white-space: pre;"> </span><i><span style="color: #999999;">... peer.c</span></i></span></div><div><span style="font-family: Nunito;">|</span></div><div><span style="font-family: Nunito;">V</span></div><div><span style="font-family: Nunito;"><b>netif_napi_add(</b>wg->dev, &peer->napi, <b><span style="color: #cc0000;">wg_packet_rx_poll</span></b>, NAPI_POLL_WEIGHT)</span></div><div><span style="font-family: Nunito;">|</span></div><div><span style="font-family: Nunito;">V</span></div><div><span style="font-family: Nunito;"><b><span style="color: #cc0000;">wg_packet_rx_poll</span></b>() <i><span style="color: #999999;"> ... receive.c</span></i></span></div><div><span style="font-family: Nunito;">{</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>while ((skb = wg_prev_queue_peek(&peer->rx_queue))</span><span style="font-family: Nunito;">) // 암호화된 packet을 하나씩 처리</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>{</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>wg_packet_consume_data_done()</span></div><div><span style="font-family: Nunito;"> {<br /></span></div><div><span style="font-family: Nunito;"> ...<br /></span></div><div><span style="font-family: Nunito;"> routed_peer = wg_allowedips_lookup_src( )</span></div><div><span style="font-family: Nunito;"> <b><span style="color: #38761d;">napi_gro_receive</span></b>(&peer->napi, skb)</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>{</span></div><div><span style="font-family: Nunito;"> ...<br /></span></div><div><span style="font-family: Nunito;"><div> <b>napi_skb_finish</b>(napi, skb, dev_gro_receive(napi, skb))</div><div><span style="white-space: pre;"> </span>|</div><div><span style="white-space: pre;"> </span>V</div><div><span style="white-space: pre;"> </span><b>dev_gro_receive</b>()</div><div><span style="white-space: pre;"> </span>|</div><div><span style="white-space: pre;"> </span>V .... 여기는 좀 보잡함.</div><div><span style="white-space: pre;"> </span><span style="color: #a64d79;">go to tcp/ip stack</span></div></span></div><div><span style="font-family: Nunito;"> }<br /></span></div><div><span style="font-family: Nunito;"> }<br /></span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>}</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span>...</span></div><div><span style="font-family: Nunito;"><span style="white-space: pre;"> </span><b>napi_complete_done</b>(napi, work_done) <i><span style="color: #999999;"> ... net/core/dev.c</span></i></span></div><div><span style="font-family: Nunito;">}</span></div></div><div><span style="font-family: Nunito; font-size: x-small;"><br /></span></div><div><span style="font-family: Nunito;">즉, network device layer(= link layer)에 위치한 <b>wg_packet_rx_poll </b>함수가 먼저 호출되고, socket layer에 위치한 <b>wg_receive </b>함수가 한참 후에 호출되는 구조로 보아야 한다. 아래 그림은 NAPI 방식(new style)을 사용할 때와 그렇지 않을 경우(legacy style)의 linux network 하부단(link layer)의 packet 수신부를 보여준다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyJ9AyNgjhm6sM56BwVuHWp6-83EUOaLd5vjpqWROnzoabfBQ8IPz1WKnVaX9xV-32aM95JENYIVZaSfmynavGV3NYu-KZ30BvHoje0LbYu3ohgOaGOCvwI1SuNMMiWqP88eFKy6GUJYRbp_NTgotGoVBRu005hgUdqcwLE2Bj97Rl9iBJD7kK6U2W9A/s792/linux_netif_rx.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="560" data-original-width="792" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyJ9AyNgjhm6sM56BwVuHWp6-83EUOaLd5vjpqWROnzoabfBQ8IPz1WKnVaX9xV-32aM95JENYIVZaSfmynavGV3NYu-KZ30BvHoje0LbYu3ohgOaGOCvwI1SuNMMiWqP88eFKy6GUJYRbp_NTgotGoVBRu005hgUdqcwLE2Bj97Rl9iBJD7kK6U2W9A/w400-h283/linux_netif_rx.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.30] </span><span style="font-family: Nunito; text-align: left;">linux kernel network 패킷 수신 - NAPI-aware drivers versus non-NAPI-aware devices [출처 - 참고문헌 10]</span></div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">__________________________________________________________________________________</span></div></div><div><br /></div><div><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">h) UDP Tunnel(Encapsulation & Decapsulation)</span></b></div><div><span style="font-family: Nunito;">앞서 packet(실제 data) encrypt/decrypt 부분을 살펴 보았는데, 송신 시 udp tunnel을 만들고, 수신 시 이를 해지하는 부분이 보이질 않는다. 그렇다면 어디에서 할까 ? </span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06;">📌 Handshake message는 encrypt/decrypt 대상이 아니다.</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06;"><br /></span></span></div><div><b><span style="background-color: #fce5cd; font-family: Nunito;"><송신 시 Encapsulation 과정></span></b></div><div><span style="font-family: Nunito;">아래 함수는 socket.c에 있는 <b>send4( ) </b>함수로 encrypt packet이 wireguard code를 빠져 나가면서 마지막으로 호출하는 부분으로 이 안에서 udp header를 추가하는 과정(encapsulation)이 이루어짐을 알 수 있다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1rzxtCRKiAr3f2H_H_0KTMN6lOaVX9G7a5h_3VS8yVNV3dBzhvqBSAifL4BZ7dALdF8MrLBlx8CAE1YMTOFre1KJYttPRxSv4pOyKTty0k_1zrckb46SR2iTx-4mlaKR6IsFowFlTc9BK6_9tmfrIrcrQb62Rn7pdNFJlOUFmW0McOIdgtj-t7sB9Kg/s1114/wireguard_send4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="926" data-original-width="1114" height="533" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1rzxtCRKiAr3f2H_H_0KTMN6lOaVX9G7a5h_3VS8yVNV3dBzhvqBSAifL4BZ7dALdF8MrLBlx8CAE1YMTOFre1KJYttPRxSv4pOyKTty0k_1zrckb46SR2iTx-4mlaKR6IsFowFlTc9BK6_9tmfrIrcrQb62Rn7pdNFJlOUFmW0McOIdgtj-t7sB9Kg/w640-h533/wireguard_send4.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.31] 실제 data에 대한 </span><span style="font-family: Nunito; text-align: left;"> rx flow</span></div><div><br /></div><div><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 Encapsulation은 정확히 말하면, 암호화 후, wireguard messge header를 붙이고, 다시 그 위에 udp header + ip header를 붙이는 과정을 말한다.</span><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white;"> </span></span></div><div><br /></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><b style="font-family: "Noto Sans CJK KR";"><span style="background-color: #fce5cd; font-family: Nunito;"><수신 시 Decapsulation 과정></span></b></span></div><div>그렇다면, 수신 시 decapsulation(ip header, udp header 및 wireguard message header를 제거)하는 과정은 어디에서 진행될까 ? 이와 관련해서는 아래 코드를 확인해 보기 바란다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNvvkJ8q0KrMZtMC1JyEREW58sLxnN4TvDcD-2ONRIRBjrcWrzVXcaaEOb-jDN29WjpQJPAlNT76OSzftUtmDLtW0BSG-RmSuS0gSI8qMdQlddsIFF3G7QCcpPS70qHZu6plxH65Y2fazwOvStJjD--7xYoKMNjwBUeMZZaVW0BVD3fs8WClXz8BYKKw/s807/wireguard_receive_decrypt_packet.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="737" data-original-width="807" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNvvkJ8q0KrMZtMC1JyEREW58sLxnN4TvDcD-2ONRIRBjrcWrzVXcaaEOb-jDN29WjpQJPAlNT76OSzftUtmDLtW0BSG-RmSuS0gSI8qMdQlddsIFF3G7QCcpPS70qHZu6plxH65Y2fazwOvStJjD--7xYoKMNjwBUeMZZaVW0BVD3fs8WClXz8BYKKw/s320/wireguard_receive_decrypt_packet.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 3.32] 복호화전 decapsulation 과정</span></div><div><br /></div><div><span style="background-color: #ead1dc;">이상으로 매우 세련되지 못한 방식으로 Wireguard kernel code를 분석해 보았다.</span> 그래도 이 정도면 어느 정도는 파악은 되지 않았을까 ? 나 혼자만의 생각일까 ? 😁</div></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;">시간 관계상, ChaCha20, Poly1305, Curve25519 등 h/w 기반의 코드(ARM NEON, Intel x86_64 AVX2) 분석이 안된 부분이 좀 아쉬움으로 남지만, (언제나 그렇듯) 다음을 기약하도록 하자.</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;"><br /></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white;">끝으로, WireGuard를 만든 <b>Jason A. Donenfeld</b>에게 감사의 마음을 전한다~ 👍</span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://www.zx2c4.com/">https://www.zx2c4.com/</a></span></div><div><br /></div><div><br /><b style="font-family: Nunito;"><span style="color: #0b5394; font-size: x-large;">4. CRYSTALS Kyber PQC 알고리즘 소개</span></b><br /></div><div><b><span style="color: #cc0000; font-size: medium;">To be continued...</span></b></div><div><span><span style="color: #cc0000;"><br /></span></span></div><div>...</div><div><span><b><br /></b></span></div><div><span><b><span style="color: #cc0000;"><br /></span><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">7. References</span></b></span><br /><span style="font-family: Nunito;"><b>[1] </b>https://wiki.friendlyelec.com/wiki/index.php/NanoPi_R4S#Install_OS</span></div><div><span style="font-family: Nunito; text-align: center;"><b>[2]</b> https://namu.wiki/w/ARM%20big.LITTLE%20%EC%86%94%EB%A3%A8%EC%85%98</span></div><div><span style="text-align: center;"><span style="font-family: Nunito;"><b>[3] </b></span></span><span style="font-family: Nunito;">https://www.ubergizmo.com/2013/01/what-is-arm-big-little/</span></div><div><span style="font-family: Nunito;"><b>[4]</b> https://www.wireguard.com/</span></div><div><span style="font-family: Nunito;"><b>[5]</b> Post-quantum WireGuard, </span><span style="font-family: Nunito;">Andreas Hülsing, Kai-Chun Ning, Peter Schwabe, Florian Weber, Philip </span><span style="font-family: Nunito;">R. Zimmermann</span></div><div><span style="font-family: Nunito;"><b>[6]</b> https://sar.informatik.hu-berlin.de/research/publications/SAR-PR-2020-03/SAR-PR-2020-03_.pdf</span></div><div><span style="font-family: Nunito;"><b>[7] </b>https://www.minzkn.com/moniwiki/wiki.php/AboutNetLinkSocket</span></div><div><span style="font-family: Nunito;"><span><b>[8] </b></span><span style="background-color: white;">Master’s Thesis - Analysis of the WireGuard protocol, Peter Wu</span></span></div><div><span style="background-color: white;"><span style="font-family: Nunito;"><b>[9] </b></span></span><span style="font-family: Nunito;">https://en.wikipedia.org/wiki/SipHash</span></div><div><span style="font-family: Nunito;"><b>[10] </b>Understanding Linux Network Internals, O'REILLY, Christian Benvenuti</span></div><div><span style="font-family: Nunito;"><b>[11]</b> And Google~</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /><br /><br /><div style="text-align: right;"><b><span style="color: #3d85c6; font-size: large;">Slowboot</span></b></div></span></div><p><br /></p>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com1tag:blogger.com,1999:blog-6346200245600677355.post-16162034790180950012023-02-08T15:22:00.001+09:002023-02-08T15:52:42.408+09:00ESP32 기반의 WireGuard, NAT router, 그리고 PQC<p><span style="font-family: Nunito;">이번 시간에는 ESP32 관련 두번째 시간으로, <b>ESP32 board에 WireGuard</b>를 올리고, 이를 <b>VPN Client</b>로 만드는 내용을 다뤄 보고자 한다. 또한 (맛보기 차원에서) <b>ESP32를 NAT router</b>로 만드는 과정과 <b>PQC(Post Quantum Cryptography) 알고리즘을 ESP32에 올리는 과정</b>을 소개해 보고자 한다.</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsnnccIB-iqbi_NuNhf1RWOejEufHVrjXRiFqyl5vrPIMtUfoLS2xD8kKzNQIDZ-8wGjf8j03sy8rZazcJIAQWEpSPk7qEeXKC878viYr5Y8VbXuZQLslX6lSHPolxnHFmOaJ52tpR8A8JTd0g0WLWCTZ4a27VVkxJUuWY14HwR_Zub_i2_pp37bKA9A/s610/wireguard_logo.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="119" data-original-width="610" height="62" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsnnccIB-iqbi_NuNhf1RWOejEufHVrjXRiFqyl5vrPIMtUfoLS2xD8kKzNQIDZ-8wGjf8j03sy8rZazcJIAQWEpSPk7qEeXKC878viYr5Y8VbXuZQLslX6lSHPolxnHFmOaJ52tpR8A8JTd0g0WLWCTZ4a27VVkxJUuWY14HwR_Zub_i2_pp37bKA9A/s320/wireguard_logo.png" width="320" /></span></a></div><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1umgEtvbgBVUAKH4jXM375Ly4PdUxIdUNuhVRF268TqsIxkdgMfd5blPaKVI1YEbRmRa5kVSsoEnY1I62Pg4D0EZcJtl_WU6YWDKGscW-eyX1mJGFhpmdG6wB9kOtRWs1ilZuW9AqVN4APNE-WNLo3Pdm2Nor4urxRvuUr9IHKWLrabGzQiFM9V8tvg/s1250/ESP32.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="775" data-original-width="1250" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1umgEtvbgBVUAKH4jXM375Ly4PdUxIdUNuhVRF268TqsIxkdgMfd5blPaKVI1YEbRmRa5kVSsoEnY1I62Pg4D0EZcJtl_WU6YWDKGscW-eyX1mJGFhpmdG6wB9kOtRWs1ilZuW9AqVN4APNE-WNLo3Pdm2Nor4urxRvuUr9IHKWLrabGzQiFM9V8tvg/s320/ESP32.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #134f5c; font-size: medium;">ESP32 board + WireGuard + PQC w/ I2C or SPI sensor</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><br /></b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b>목차<br /></b></span><span style="font-family: Nunito;"><i>1. ESP32 Reloaded</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>2. ESP32 보드에 i2c & spi 장치 붙여 보기</i><i><br /></i></span><span style="font-family: Nunito;"><i>3. ESP32 보드에 WireGuard 올리기</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>4. ESP32 보드를 NAT Gateway로 만들기<br /></i></span><span style="font-family: Nunito;"><i>5. </i></span><i style="font-family: Nunito;">PQC 알고리즘 Porting하기 - </i><i style="font-family: Nunito;">CRYSTALS Kyber & Dilithium</i></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>6. References</i></span></div><p><span style="color: #b45f06; font-family: Nunito;">Keyword: esp32, wireguard, lwip, NAT, PQC, i2c, spi</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;"><i><span style="color: #134f5c;">필자는 개인적으로 Linux의 광팬이다(Linux여 영원하라~). 하지만 Linux는 벌써 개발된지 30년이 훌쩍 넘었고, (많은 내용을 수용하다보니) 덩치도 상당히 비대해진게 사실이다. uClinux 같은 작은 linux 버젼도 있긴 하지만, 초소용 IoT 환경에는 어울리지 않는 듯하다. 여러가지 선택지가 있겠지만, ESP32가 그 중 좋은 대안이 아닌가 생각본다. 🎯</span></i></span></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>1. ESP32 Reloaded</b></span></p><p><span style="color: #333333; font-family: Nunito;"><span style="background-color: white;">2년 전 쯤에 ESP32 관련 글을 한차례 게재한 적이 있다. </span></span><span style="background-color: white; color: #333333; font-family: Nunito;">이번 시간에는 ESP32 관련 두번째 시간으로, ESP32 board에 Wireguard를 올려 보고,<b><u> 3축 가속도 센서 정보를 wireguard tunnel을 통해 서버로 전송</u></b>하는 내용을 다뤄 보고자 한다.</span></p><p><span style="color: #a64d79;"><span style="background-color: white; font-family: Nunito;">"ESP32는 <a href="https://www.espressif.com/en/products/socs/esp8266" style="text-decoration-line: none;">ESP8266</a>으로 유명한 Espressif 사에서 만든 Wi-Fi & Bluetooth용 저가의 chip(Wi-Fi/BLE SoC)이다. 그런데 저가의 chip이라고 해서 우습게(?) 볼 일이 아닌 것이, ESP32 자체는 <a href="https://mirrobo.ru/wp-content/uploads/2016/11/Cadence_Tensillica_Xtensa_LX6_ds.pdf" style="text-decoration-line: none;">Xtensa LX6(Dual-core 32bit) RISC CPU</a>(</span><span style="background-color: white; font-family: Nunito;">160Mhz or 240Mhz)</span><span style="background-color: white; font-family: Nunito;">를 기반으로 하고 있는 엄연한 32bit microprocessor이다."</span></span></p><p style="text-align: center;"><span style="background-color: white;"><span style="color: #333333; font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/12/">https://slowbootkernelhacks.blogspot.com/2020/12/</a></span></span></p><p><span style="background-color: white; color: #38761d; font-family: Nunito; font-size: medium;"><b>a) Long time no see ~ ESP32 보드</b></span></p><p><span style="background-color: white; color: #333333; font-family: Nunito;">아래 그림과 같이, 잠자고 있던 esp32 board(esp32-s devkit)를 다시 꺼내어 전원을 연결해 보았다. 💤</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9KMDMgt3Fi90K4hkVJz6x81IRyw_xyqE2DBdH3xKSjfNtL81jYUJhUchpeCRZtJdzcQU9Iwp9vIQY-wIqi_ktU4X8Z57ZpMI_jkzRBJxtzPXzJzHvOk2dyYbdGrWcdf8p74o5kZ3wNtTQ61P4LFphvkcnw80NbLiuLmjk27ON7yZKokjAk79vQpSzTw/s4000/20230204_143917.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4000" data-original-width="3000" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9KMDMgt3Fi90K4hkVJz6x81IRyw_xyqE2DBdH3xKSjfNtL81jYUJhUchpeCRZtJdzcQU9Iwp9vIQY-wIqi_ktU4X8Z57ZpMI_jkzRBJxtzPXzJzHvOk2dyYbdGrWcdf8p74o5kZ3wNtTQ61P4LFphvkcnw80NbLiuLmjk27ON7yZKokjAk79vQpSzTw/s320/20230204_143917.jpg" width="240" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: white; font-family: Nunito;">[그림 1.1] esp32 board(ESP32-S/NodeMCU)를 연결한 모습</span></div><p></p><p><span style="font-family: Nunito;"><br /></span></p><p><b style="color: #38761d; font-family: Nunito;"><span style="font-size: medium;">b) ESP-IDF 환경 구축</span></b></p><p><span style="background-color: white; color: #333333; font-family: Nunito;">환경 구축 등과 같은 자세한 사항은 위의 <a href="https://slowbootkernelhacks.blogspot.com/2020/12/">blog post </a>및<a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html"> ESP-IDF programming guide</a>를 참고해 주기 바라며, 여기에서는 오랜만에 esp-idf(v5.1) 개발 환경을 다시 구축해 본 후, 곧 바로 다음 장으로 바로 넘어가도록 하자.</span></p><div style="text-align: left;"><span style="font-family: Nunito;"><b><ESP-IDF 개발 환경 구축><br /></b></span><span style="font-family: Nunito;">$ </span><b style="font-family: Nunito;">git clone --recursive https://github.com/espressif/esp-idf.git</b><br /><span style="font-family: Nunito;">$ <b>cd esp-idf</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>./install.sh esp32</b></span><br /><span style="font-family: Nunito;">$ <b>. ./export.sh</b></span><span style="font-family: Nunito;"><br /></span><br /></div><div style="text-align: left;">간단한 sample code를 하나 build하여 실행해 보도록 하자.</div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">$ <b>cd examples/get-started/hello_world/</b><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">여기에서 환경 설정을 원하는대로 변경한다.</span></div></span><span style="font-family: Nunito;">$<b> idf.py build</b></span><br /><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB0 flash</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ </span><b style="font-family: Nunito;">idf.py -p /dev/ttyUSB0 monitor</b></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLhDxUMzWeYaff-kLqfjxDpwdf5VlxDdwJGl4jGgdNj4nlRvp8AkGMZeJPv2pPQYVYuoyoqFC0UidBj0u0no1vnz-ycEAXJto8XhJPDPQPOJFMrLMsjY1rL3COrATTqsha4GF_Y4XAjgAPzAlFA5frG6ehyae4UmF5xDmXbboA1lv2181qYwrhmjS3A/s1056/esp32_hello_world_monitor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="618" data-original-width="1056" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjLhDxUMzWeYaff-kLqfjxDpwdf5VlxDdwJGl4jGgdNj4nlRvp8AkGMZeJPv2pPQYVYuoyoqFC0UidBj0u0no1vnz-ycEAXJto8XhJPDPQPOJFMrLMsjY1rL3COrATTqsha4GF_Y4XAjgAPzAlFA5frG6ehyae4UmF5xDmXbboA1lv2181qYwrhmjS3A/w400-h234/esp32_hello_world_monitor.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] esp32 board 상에서 hello world binary를 실행한 모습</div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><p style="text-align: left;"><span style="font-family: Nunito;">자, 이제 다음 단계로 넘어갈 준비가 되었는가 ? ⌛</span></p><p style="text-align: left;"><br /></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>2. ESP32 <span>보드</span>에 i2c & spi 장치 붙여 보기</b></span></p><p><span style="font-family: Nunito;">이번 장에서는 3축 가속도 센서(ADXL345)를 esp32 board에 연결하고, 이를 인식시키는 과정을 소개해 보고자 한다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2c.html</a></span></p><p style="text-align: center;"><a href="https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_slave.html"><span style="font-family: Nunito;">https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_slave.html</span></a></p><p style="text-align: center;"><br /></p><p><b style="color: #38761d; font-family: Nunito;"><span style="font-size: medium;">a) ADXL345 3축 가속도(Accelerometer) 센서</span></b></p><p><span style="font-family: Nunito;">시험에 사용할 센서는 아래 그림에서 보는 것과 같이 i2c 및 spi 연결이 가능한 <b>ADXL345 3축 가속도 센서</b>가 되겠다. 우선은 i2c가 간단해 보이니, i2c를 이용해 연결해 보도록 하자.</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0g0uiNWCJ-V1_H1fsl7aE30iSoVSNOCVoBbQeHG2q4jtKjRBIErrKilaDMO7cX9433CvlUWf8T_eCCsJOVHgHy0eGIfL1kqm6zNgdDVBVXKt6_NXSnnFDccMeHT2375fMjvh08Y0wybOlPE_e_EqfIjueWfC6WYa4vHcbc-YpTrNXJy4dzc-ISmJeQ/s422/adxl345_accelerometer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="351" data-original-width="422" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf0g0uiNWCJ-V1_H1fsl7aE30iSoVSNOCVoBbQeHG2q4jtKjRBIErrKilaDMO7cX9433CvlUWf8T_eCCsJOVHgHy0eGIfL1kqm6zNgdDVBVXKt6_NXSnnFDccMeHT2375fMjvh08Y0wybOlPE_e_EqfIjueWfC6WYa4vHcbc-YpTrNXJy4dzc-ISmJeQ/w320-h266/adxl345_accelerometer.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 2.1] ADXL345 3축 가속도(Accelerometer) 센서 브레이크아웃 보드(1)</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px; text-align: left;">📌 </span><span style="color: #b45f06;"><span style="background-color: white; font-family: Nunito; text-align: left;">Breakout 보드는 </span><span style="background-color: white; font-family: Nunito; text-align: left;">IC의 핀들을 커넥터로 연결할 수 있도록 만들어진 PCB 보드</span><span style="background-color: white; font-family: Nunito; text-align: left;">를 의미한다.</span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06;"><span style="background-color: white; font-family: Nunito; text-align: left;"><br /></span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white;">아래 table은 ADXL345 breakout 보드의 pinout을 상세히 설명해 준다.</span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ABT8XAePvQhLQuUBqNVkA8Kx1ZAzZrdXW9EDi03MFTjoUsf1sdiQYzj2OqUmNNfx0icodsAPM0zitwlUVNuRjrkd5rQlcRJQqGvad8G1OIOaMFf95hKWm2j5EindrrQHegnCWEvQq2kLBgn96PfkdpUwhOh-Cm_mYmHCprpvVzYm69uN6pkzB1gZHw/s564/adxl345_breakout_pinout.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="417" data-original-width="564" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1ABT8XAePvQhLQuUBqNVkA8Kx1ZAzZrdXW9EDi03MFTjoUsf1sdiQYzj2OqUmNNfx0icodsAPM0zitwlUVNuRjrkd5rQlcRJQqGvad8G1OIOaMFf95hKWm2j5EindrrQHegnCWEvQq2kLBgn96PfkdpUwhOh-Cm_mYmHCprpvVzYm69uN6pkzB1gZHw/w400-h296/adxl345_breakout_pinout.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="color: black; font-family: Nunito; text-align: left;">[그림 2.2] ADXL345 3축 가속도(Accelerometer) 센서 브레이크아웃 보드(2) [출처 - 참고문헌 5]</span></div><span style="background-color: white; font-family: Nunito; text-align: left;"><br /></span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06;"><span style="background-color: white; font-family: Nunito; text-align: left;"><br /></span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: #eeeeee;"><span style="font-family: Nunito; text-align: center;">"</span><span style="font-family: Nunito; text-align: left;">ADXL345는 Analog Devices에서 출시한 작고 얇은 초저전력 3축 가속도계입니다. 최대 ±16g에서 고해상도(13비트) 측정이 가능합니다. 디지털 출력 데이터는 16비트 2의 보수 형식으로 지정되며 SPI(3선 또는 4선) 또는 I2C 디지털 인터페이스를 통해 액세스할 수 있습니다. ADXL345는 모바일 장치 애플리케이션에 적합합니다. 기울기 감지 애플리케이션에서 중력의 정적 가속도와 움직임이나 충격으로 인한 동적 가속도를 측정합니다. 고분해능(3.9 mg/LSB)으로 1.0° 미만의 기울기 변화를 측정할 수 있습니다. 몇 가지 특수 감지 기능이 제공됩니다. 활동 및 비활동 감지는 모든 축의 가속도를 사용자가 설정한 임계값과 비교하여 움직임의 유무를 감지합니다. 탭 감지는 모든 방향의 단일 및 이중 탭을 감지합니다. 자유낙하 감지는 장치가 떨어지는지 감지합니다. 이러한 기능은 두 개의 인터럽트 출력 핀 중 하나에 개별적으로 매핑될 수 있습니다. 32레벨 FIFO(선입 선출) 버퍼가 있는 통합 메모리 관리 시스템은 호스트 프로세서 활동을 최소화하고 전체 시스템 전력 소비를 줄이기 위해 데이터를 저장하는 데 사용할 수 있습니다. .저전력 모드는 임계값 감지 및 극도로 낮은 전력 손실에서 능동 가속 측정을 통해 지능형 동작 기반 전력 관리를 가능하게 합니다." [출처: 참고문헌 4]</span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxd_gSpmis5fCbqwPrmO5qEi_MdBxFfdl1CsCEdTLaXDivgymgmLTtfHjGMwYIkUU6hRTZ5wLbllp0ezVNalO21j_j_M9JLhECxmoK6n3pqFxbktSFOc-_148xjNGvBhXpN15c7ZHfQN1NHkkbsr7UeycqP885u3jYL_Fd1uMNDb02DchY6HN6vtyNA/s556/adxl345_block_diagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="349" data-original-width="556" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLxd_gSpmis5fCbqwPrmO5qEi_MdBxFfdl1CsCEdTLaXDivgymgmLTtfHjGMwYIkUU6hRTZ5wLbllp0ezVNalO21j_j_M9JLhECxmoK6n3pqFxbktSFOc-_148xjNGvBhXpN15c7ZHfQN1NHkkbsr7UeycqP885u3jYL_Fd1uMNDb02DchY6HN6vtyNA/w400-h251/adxl345_block_diagram.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.3] ADXL345 3축 가속도 센서 block도 [출처: 참고문헌 3]</div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06;"><span style="background-color: white; font-family: Nunito; font-size: 14.85px; text-align: left;">📌 </span><span style="background-color: white; font-family: Nunito; font-size: 14.85px; text-align: left; white-space: pre-wrap;">ADXL345는 Analog Devices 사가 만든 3-Axis, ±2 g/±4 g/±8 g/±16 g Digital Accelerometer이다.</span></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_CPmgul3CDiOzlKUgDgjhFRMTi4XaJmozgSKfHgsn4rEQu8uJfhWZnfuBhRPH8g327p4I9I_VBH5L-l11YazpKAW3KSxbeMUTTPbKog897XLc0Op7gm604NMBhUslvc3i5nrzag9F_dCuSSNUUlnxXMtofzaEvolKy5aOrQhEGzlKjec5HtdkeSA7JA/s432/adxl345_application_diagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="220" data-original-width="432" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_CPmgul3CDiOzlKUgDgjhFRMTi4XaJmozgSKfHgsn4rEQu8uJfhWZnfuBhRPH8g327p4I9I_VBH5L-l11YazpKAW3KSxbeMUTTPbKog897XLc0Op7gm604NMBhUslvc3i5nrzag9F_dCuSSNUUlnxXMtofzaEvolKy5aOrQhEGzlKjec5HtdkeSA7JA/w400-h204/adxl345_application_diagram.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.4] ADXL345 3축 가속도 센서 application block도 [출처: 참고문헌 3]</div><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px; text-align: left;"><div style="text-align: justify;"><span style="color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 재밌게도 </span><span style="font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;">ADXL345는 interrupt를 발생시킬 수 있다.</span></div></span><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimbVR-dX419b3eyosovg-cbYadTILg5f7CkIcGM5cDR_c1mTgNoM47ORwGVYW9gogMYLSiC-aSTT56nxBP3FmWTWwtsKPPvsZJAXeugD-AlZ4SN15DAMP7zV6yr6m0DSIVp53bDPc9VREH5cNWA3qaXN64uFhvDgqQMgCNyhatx0hKFJw8jsIkTE8jvQ/s261/adxl345_spi_3wire.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="135" data-original-width="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimbVR-dX419b3eyosovg-cbYadTILg5f7CkIcGM5cDR_c1mTgNoM47ORwGVYW9gogMYLSiC-aSTT56nxBP3FmWTWwtsKPPvsZJAXeugD-AlZ4SN15DAMP7zV6yr6m0DSIVp53bDPc9VREH5cNWA3qaXN64uFhvDgqQMgCNyhatx0hKFJw8jsIkTE8jvQ/s16000/adxl345_spi_3wire.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.5] ADXL345 SPI 연결도2(connection diagram) - 3 wire [출처: 참고문헌 3]</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Mqe136ZEvuWjs-UEksySLIbSaB33bC-_ZMZVIqbJviwPZb9yhiJ-1b_5d05OVIv_yyps98PDYap_n778pRn1UpvGCpdAu7mT7qSeWGlbNC8EqbKCVCoNqmJjLCGVFadQYnlEeUumCvjQ86dq2EVjd7drqFqxNZfGaUCjFwc1Cfy3a6pSHlBGPkTh0A/s256/adxl345_spi_4wire.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="141" data-original-width="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5Mqe136ZEvuWjs-UEksySLIbSaB33bC-_ZMZVIqbJviwPZb9yhiJ-1b_5d05OVIv_yyps98PDYap_n778pRn1UpvGCpdAu7mT7qSeWGlbNC8EqbKCVCoNqmJjLCGVFadQYnlEeUumCvjQ86dq2EVjd7drqFqxNZfGaUCjFwc1Cfy3a6pSHlBGPkTh0A/s16000/adxl345_spi_4wire.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.6] ADXL345 SPI 연결도2(connection diagram) - 4 wire [출처: 참고문헌 3]</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdVWfqa0a_gpBw8oEEdCUUviKSrLQBXtBx0c9N_HGs8yoRDwKoCGzcqhsqzE5_Zj3lE5A0IB8HLPd_bLafKBz4Gm5O4An1VW5p3OybvK5W8Z0uu8D6vc2sOpcB8rC9WDUKC0v-9fKFP0cphpb1UobU37gr5k_jgAK2xaS-_EXgYDX4JRtKm6f99lcyvw/s294/adxl345_i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="193" data-original-width="294" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdVWfqa0a_gpBw8oEEdCUUviKSrLQBXtBx0c9N_HGs8yoRDwKoCGzcqhsqzE5_Zj3lE5A0IB8HLPd_bLafKBz4Gm5O4An1VW5p3OybvK5W8Z0uu8D6vc2sOpcB8rC9WDUKC0v-9fKFP0cphpb1UobU37gr5k_jgAK2xaS-_EXgYDX4JRtKm6f99lcyvw/s16000/adxl345_i2c.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.7] ADXL345 I2C 연결도(connection diagram) [출처: 참고문헌 3]</span></div></div><div class="separator" style="clear: both; text-align: justify;"><span face="-apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"" style="background-color: white; color: #24292f; font-size: 16px; text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: Nunito;"><b style="color: #38761d;"><span style="font-size: medium;">b) ADXL345 i2c pinmap</span></b></span></div><div><span style="font-family: Nunito;">3축 가속도 센서를 i2c 포트를 통해 연결하기 위해서는, 먼저 ESP32-S devkit의 확장핀 맵을 확인해 보아야 한다. </span><span style="font-family: Nunito;">esp32에는 2개의 i2c port(controller)가 존재하는데, 여기에서는 GPIO22를 pin mux한 port(P22, SCL용)와 GPIO21을 pin mux한 port(P21, SDA용)를 사용해 보도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_nrehvgwCDD4aLfEg8HCLHyxMWfQkWcXfOLdUAGJd9gBZ1-jIYbhL3Cahu5DUi7kIVnJ-odfQJ-yWv4DCRcWP2x_5Uhsy6ytXFUmApO06oMNQZMo862t_cGIzq2HMVpVd10M3u52zQn_iUYa-2aboUjZfnVwFGF45SyFyn3XEknDkwAEH0lbjirLdoA/s1024/ESP32-S-pinout-mischianti-low-resolution-1024x578.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="578" data-original-width="1024" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_nrehvgwCDD4aLfEg8HCLHyxMWfQkWcXfOLdUAGJd9gBZ1-jIYbhL3Cahu5DUi7kIVnJ-odfQJ-yWv4DCRcWP2x_5Uhsy6ytXFUmApO06oMNQZMo862t_cGIzq2HMVpVd10M3u52zQn_iUYa-2aboUjZfnVwFGF45SyFyn3XEknDkwAEH0lbjirLdoA/w640-h362/ESP32-S-pinout-mischianti-low-resolution-1024x578.jpg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: white; font-family: Nunito;">[그림 2.8] esp32 board(ESP32-S/NodeMCU) pinout (Old board)</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-FRhkYVyNQaoapJLgo3fBv3lhsbqSyM3WGsak5uBu9TrOlEfAwJnmgvumcFEsrCaMnhKxwzyo_X60gGpKovZPKOkGDyUem-h5wahJFM6fNz1WP_OnmE8-JiWY2a-fQAjtsNuCO17-h18mIXxkdqIPjVXFLpaEqvzcrRZoUgjhx8y--lkvkvcMdEQSQ/s1532/NodeMCU-32S-details-3.jpg" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="1044" data-original-width="1532" height="436" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-FRhkYVyNQaoapJLgo3fBv3lhsbqSyM3WGsak5uBu9TrOlEfAwJnmgvumcFEsrCaMnhKxwzyo_X60gGpKovZPKOkGDyUem-h5wahJFM6fNz1WP_OnmE8-JiWY2a-fQAjtsNuCO17-h18mIXxkdqIPjVXFLpaEqvzcrRZoUgjhx8y--lkvkvcMdEQSQ/w640-h436/NodeMCU-32S-details-3.jpg" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;">[그림 2.9] esp32 board(ESP32-S/NodeMCU) pinout (New board)</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white;">아래 그림은 esp32 board에 ADXL345 device를 실제로 연결한 모습이다. Jumper cable이 부족하여 (어쩔 수 없이) 일반적이지 않은 색이지만, 아래와 같이 연결해 보았다. 😂</span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white;"><br /></span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white;"><br /></span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqh5zpFEJwjvQqpOAMx7k29sBo3hNdL4JkDqMNZ2lVpZ3J-Q5Eh1Z8T6iq9HuKcV6oZskm557pPMg6MPdIlfxnjnVBKSTzHpkr60U7z1DtqbKd-33ddaC1qEX0ntKuje834UqK2h47ElNx74p-b1vqzpICbBrxs7XXK8wsMQFumLeTk9Zea2zbW01d8w/s4000/20230207_142123.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4000" data-original-width="3000" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqh5zpFEJwjvQqpOAMx7k29sBo3hNdL4JkDqMNZ2lVpZ3J-Q5Eh1Z8T6iq9HuKcV6oZskm557pPMg6MPdIlfxnjnVBKSTzHpkr60U7z1DtqbKd-33ddaC1qEX0ntKuje834UqK2h47ElNx74p-b1vqzpICbBrxs7XXK8wsMQFumLeTk9Zea2zbW01d8w/w300-h400/20230207_142123.jpg" width="300" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.10]ADXL345 3축 가속도(Accelerometer) 센서 </div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;">ESP32 보드와 ADXL345간의 실제 연결 모습은 다음과 같다.</div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #38761d; font-family: Nunito;"><b><ADXL345와 ESP32 확장핀 간 연결 모습></b></span></div><b><span style="color: #0b5394;">GND</span></b>(파란색 - 일반적으로 <b>검정색</b>) ...................................................................... <b>ESP32 GND</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #ffa400;">VCC</span></b>(3.3v)(주황색 - 일반적으로는 <b><span style="color: #cc0000;">빨간색</span></b>) ......................................................... <b>ESP32 3V3</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #38761d;">SDA</span></b>(녹색) .................................................................................................................... <b>ESP32 P21</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #f1c232;">SCL</span></b>(노란색) .................................................................................................................<b> ESP32 P22</b><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjicWhNjOBD_km12lHDhU1FIiVY112OXi4Qi7VAQqTk3DjZTZxnkPy1nT1q82Vy3W7QY6KUPXEw8KchQeSgVEMC7GvzAjDynt5zm_5jhjD1_hO6-bgwZxm3_QPH6Nv8JYARpjMp0zWPdrr7LOktUf8GYpVxfQ2KzK7NrYVG50nQDM9Ns-1RVSHg7B17jw/s4000/20230206_111535.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4000" data-original-width="3000" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjicWhNjOBD_km12lHDhU1FIiVY112OXi4Qi7VAQqTk3DjZTZxnkPy1nT1q82Vy3W7QY6KUPXEw8KchQeSgVEMC7GvzAjDynt5zm_5jhjD1_hO6-bgwZxm3_QPH6Nv8JYARpjMp0zWPdrr7LOktUf8GYpVxfQ2KzK7NrYVG50nQDM9Ns-1RVSHg7B17jw/w300-h400/20230206_111535.jpg" width="300" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.11] esp32 board에 ADXL345 3축 가속도(Accelerometer) 센서를 연결한 모습</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><p></p><p><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>c) esp32 i2c device driver 구현하기</b></span></p><div><span style="font-family: Nunito;">다음으로 할 일은 ADXL345 i2c device driver를 구현하고, 이를 구동시켜 보는 일이다. 아래 그림은 ADXL345 가속도 센서에 대한 i2c 연결도를 보여주고 있다. 잘 알고 있는 바와 같이, i2c slave 설정을 위해서는 i2c device address가 필요하다. 한가지 재밌는 사실은 ADXL345의 경우는 SDO/ALT ADDRESS라는 pin을 High(3.3v)로 하느냐 Low로 하느냐에 따라 i2c 주소가 아래와 같이 2가지로 사용 가능하다는 점이다.</span></div><p style="-webkit-text-stroke-width: 0px;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTfQHUOn5maWezmZpiZW--I4LRo1NLoKp1fPo2YmSdPWk8MBxz7OHwC0QQHHJ4rJGsHbqdgEmebqKn2MV9QpwK7MEKiK46qu_WCo_AUTh_7FpoOMEqDNWjtSYHlmvaIv-Bifxlbat5S8CWbfxfQMdIQXd6iVaZOsdbGR0DrBUkmN1tXYV8Z-6HAWsd8w/s355/adxl345_i2c_conn_diagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="211" data-original-width="355" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTfQHUOn5maWezmZpiZW--I4LRo1NLoKp1fPo2YmSdPWk8MBxz7OHwC0QQHHJ4rJGsHbqdgEmebqKn2MV9QpwK7MEKiK46qu_WCo_AUTh_7FpoOMEqDNWjtSYHlmvaIv-Bifxlbat5S8CWbfxfQMdIQXd6iVaZOsdbGR0DrBUkmN1tXYV8Z-6HAWsd8w/w400-h238/adxl345_i2c_conn_diagram.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.12] ADXL345 가속도 센서의 i2c 연결도 [출처: 참고문헌 3]</div><p></p><div><span style="font-family: Nunito;"><b><span style="color: #b45f06;">[1] SDO/ALT ADDRESS를 High로 할 경우</span></b><br /></span><span style="font-family: Nunito;"><i> 7-bit i2c 주소는 <b>0x1D (0001 1101) </b>이고, 마지막 bit는 R/W bit(0: write, 1: read)로 사용된다. 따라서 write 주소는 0x3A가 되고, read 주소는 0x3B가 된다.</i></span></div><p><span style="font-family: Nunito;"><b><span style="color: #b45f06;">[2] SDO/ALT ADDRESS를 Low로 할 경우</span></b></span></p><p><i style="font-family: Nunito;">7-bit i2c 주소는 <b>0x53(0101 0011)</b>이고, 마지막 bit는 R/W bit(0: write, 1: read)로 사용된다. 따라서 write 주소는 0xA6이 되고, read 주소는 0xA7이 된다.</i></p><p><span style="font-family: Nunito;">Device driver를 직접 구현할까 하다가 인터넷을 좀 뒤져 보니, 아래 예제 코드가 보인다. 직접 만드는 방법도 있겠으나, (제대로 동작하는지) 일단 얘를 먼저 돌려 보도록 한다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/imxieyi/esp32-i2c-adxl345">https://github.com/imxieyi/esp32-i2c-adxl345</a></span></p><div><span style="font-family: Nunito;"><div><span style="font-family: Nunito;">$ <b>cd </b><b>esp32-i2c-adxl345</b></span></div><div><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><i><span style="color: #b45f06; font-size: x-small;">Executing action: menuconfig</span></i></div><div style="font-family: "Noto Sans CJK KR";"><i><span style="color: #b45f06; font-size: x-small;">CMakeLists.txt not found in project directory /mnt/sda/workspace/ESP32/esp32-i2c-adxl345</span></i></div><div style="font-family: "Noto Sans CJK KR";"><br /></div></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">어라, 에러가 난다. 가만히 보니 CMakeLists.txt 파일이 없고, Makefile만 보인다. 아무래도 예전 방식으로 만들어진 코드인 듯 보인다. 그렇다면, 다른 코드를 참조하여 Makefile, component.mk 파일 등을 제거한 후, CMakeLists.txt를 새로 추가해 보도록 하자.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">$ <b>mv Makefile Makefile.ORIG</b></span></div><div>$ <b>vi CMakeLists.txt </b></div><div><i><span style="color: #b45f06; font-size: x-small;"># The following lines of boilerplate have to be in your project's CMakeLists</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"># in this exact order for cmake to work correctly</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;">cmake_minimum_required(VERSION 3.16)</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"><br /></span></i></div><div><i><span style="color: #b45f06; font-size: x-small;">include($ENV{IDF_PATH}/tools/cmake/project.cmake)</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;">project(esp32-i2c-adxl345)</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;">~</span></i></div><div><br /></div><div>$ <b>vi main/CMakeLists.txt </b></div><div><i><span style="color: #b45f06; font-size: x-small;">idf_component_register(SRCS "esp32_i2c_adxl345_main.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"><span style="white-space: pre;"> </span> "adxl345.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"><span style="white-space: pre;"> </span> "i2c.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"><span style="white-space: pre;"> </span> INCLUDE_DIRS "./include")</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;">~</span></i></div><div>$ <b>mv main/component.mk main/component.mk.ORIG</b></div><div><br />$ <span style="font-weight: 700;">idf.py menuconfig</span></div></span><span style="font-family: Nunito;">$<b> idf.py build</b></span></div><div><span style="color: #990000; font-family: Nunito; font-size: x-small;"><b>...</b></span></div><div><span style="color: #990000; font-size: x-small;">arameter -Wno-sign-compare -Wno-enum-conversion -gdwarf-4 -ggdb -Og -fmacro-prefix-map=/mnt/sda/workspace/ESP32/esp32-i2c-adxl345=. -fmacro-prefix-map=/mnt/sda/workspace/ESP32/esp-idf=/IDF -fstrict-volatile-bitfields -fno-jump-tables -fno-tree-switch-conversion -DconfigENABLE_FREERTOS_DEBUG_OCDAWARE=1 -std=gnu17 -Wno-old-style-declaration -MD -MT esp-idf/main/CMakeFiles/__idf_main.dir/esp32_i2c_adxl345_main.c.obj -MF esp-idf/main/CMakeFiles/__idf_main.dir/esp32_i2c_adxl345_main.c.obj.d -o esp-idf/main/CMakeFiles/__idf_main.dir/esp32_i2c_adxl345_main.c.obj -c /mnt/sda/workspace/ESP32/esp32-i2c-adxl345/main/esp32_i2c_adxl345_main.c</span></div><div><span style="color: #990000; font-size: x-small;">/mnt/sda/workspace/ESP32/esp32-i2c-adxl345/main/esp32_i2c_adxl345_main.c: In function 'sensorTask':</span></div><div><span style="color: #990000; font-size: x-small;">/mnt/sda/workspace/ESP32/esp32-i2c-adxl345/main/esp32_i2c_adxl345_main.c:23:35: error: 'portTICK_RATE_MS' undeclared (first use in this function); did you mean 'portTICK_PERIOD_MS'?</span></div><div><span style="color: #990000; font-size: x-small;"> 23 | vTaskDelay(1000 / portTICK_RATE_MS);</span></div><div><span style="color: #990000; font-size: x-small;"> | ^~~~~~~~~~~~~~~~</span></div><div><span style="color: #990000; font-size: x-small;"> | portTICK_PERIOD_MS</span></div><div><span style="color: #990000; font-size: x-small;">/mnt/sda/workspace/ESP32/esp32-i2c-adxl345/main/esp32_i2c_adxl345_main.c:23:35: note: each undeclared identifier is reported only once for each function it appears in</span></div><div><span style="color: #990000; font-size: x-small;">[862/870] Building C object esp-idf/wifi_provisioning/CMakeFiles/__idf_wifi_provisioning.dir/src/manager.c.objninja: build stopped: subcommand failed.</span></div><div><span style="color: #990000; font-size: x-small;">HINT: You are maybe using pre FreeRTOS V8.0.0 APIs. The backward compatibility of such APIs is no longer enabled by default. Please turn on CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY explicitly to use such APIs.</span></div><div><span style="color: #990000; font-size: x-small;">ninja failed with exit code 1, output of the command is in the /mnt/sda/workspace/ESP32/esp32-i2c-adxl345/build/log/idf_py_stderr_output_15455 and /mnt/sda/workspace/ESP32/esp32-i2c-adxl345/build/log/idf_py_stdout_output_15455</span></div><div><span style="color: #990000; font-size: x-small;">...</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">Build를 해보니, 간단한 에러가 발생한다. 아래와 같이 코드 수정을 해 본다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCnMjF-iWBHByHqKmCKTSZxvQ2IFR2ao0VVq1fniurInMxeM8qF16lBYNnZo-REwvQFMtQ2wKiz_oHXEfDzzqi32mGiLMGk0NXwh3wu03brpJr85qnUYYduzKcnlUl-Yb4Ed76YlDqRMG9WBYlJ1ZO94DjLj4wztRt4jZSZySbiD-S_WgxrA9ArqoBQ/s792/esp32_i2c_example_fixed1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="492" data-original-width="792" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMCnMjF-iWBHByHqKmCKTSZxvQ2IFR2ao0VVq1fniurInMxeM8qF16lBYNnZo-REwvQFMtQ2wKiz_oHXEfDzzqi32mGiLMGk0NXwh3wu03brpJr85qnUYYduzKcnlUl-Yb4Ed76YlDqRMG9WBYlJ1ZO94DjLj4wztRt4jZSZySbiD-S_WgxrA9ArqoBQ/s320/esp32_i2c_example_fixed1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.13] esp32_i2c_adxl345_main.c 코드 수정</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">다시 build해 보니, 이번에는 성공적으로 build가 된다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3IDxPgz0KciajQtqBH_NFlb4FFw_eZuDvIxyLfzhB_qunXmk8alpNlD3WF3yKRDIb4cyDd846m12Y7rE6_sjkno59DQK9GyxtzbYsb5szHliAIwiY4bWqML2Xepe7CI1tTMFfA8okzZWlu3-6p3yMCLpGRS7ogfnqX8IQHP9Y2rAZ38vfYffpAnszRw/s1011/esp32_i2c_build_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="385" data-original-width="1011" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3IDxPgz0KciajQtqBH_NFlb4FFw_eZuDvIxyLfzhB_qunXmk8alpNlD3WF3yKRDIb4cyDd846m12Y7rE6_sjkno59DQK9GyxtzbYsb5szHliAIwiY4bWqML2Xepe7CI1tTMFfA8okzZWlu3-6p3yMCLpGRS7ogfnqX8IQHP9Y2rAZ38vfYffpAnszRw/w400-h153/esp32_i2c_build_ok.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.14] adxl345 i2c example 정상 build 모습</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito;">flash writing하여 동작을 확인해 본다.</span></div><div><span style="font-family: Nunito;">$</span><span style="font-family: Nunito;"> </span><b style="font-family: Nunito;">idf.py -p /dev/ttyUSB0 flash</b></div><div><span style="font-family: Nunito;">$ </span><b style="font-family: Nunito;">idf.py -p /dev/ttyUSB0 monitor</b></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">(놀랄 것도 없이) I2C read error가 보인다.</span></div><p><span style="font-family: Nunito;"></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggAgsri2Xua0IYxkkAyQyq6AIcH428P_VzjKy0iAwxFnJItl_TRjUtoLZt06CjjEvxfTLErOOr7OUPYr40XhwKkqPoYQr1nLx-kwLrDrtlJeq94ETugubMnteywNmtGSjRyUIXOX1oh9Re8YbwoEgY6ON44yqu2a3nlGKIjSnvsel8W3PmrxIpXnU38Q/s658/esp32_adxl345_i2c_error.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="658" data-original-width="446" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggAgsri2Xua0IYxkkAyQyq6AIcH428P_VzjKy0iAwxFnJItl_TRjUtoLZt06CjjEvxfTLErOOr7OUPYr40XhwKkqPoYQr1nLx-kwLrDrtlJeq94ETugubMnteywNmtGSjRyUIXOX1oh9Re8YbwoEgY6ON44yqu2a3nlGKIjSnvsel8W3PmrxIpXnU38Q/w271-h400/esp32_adxl345_i2c_error.png" width="271" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.15] ADXL345 가속도 센서 동작 모습 - i2c 실패</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: justify;"><span style="text-align: left;"><span style="font-family: Nunito;">코드를 들여다 보니, GPIO 설정이 시험 내용과 맞지 않다. 이 부분을 아래와 같이 수정해 보자.</span></span></div><div style="text-align: justify;"><span style="font-family: Nunito; text-align: left;"><i><br /></i></span></div><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#if 0 /* ORIG_CODE */</div></span><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#define SCL_PIN GPIO_NUM_17</div></span><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#define SDA_PIN GPIO_NUM_16</div></span><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#else</div></span><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#define SCL_PIN <b>GPIO_NUM_22</b></div></span><span style="font-family: Nunito; font-style: italic; text-align: left;"><div style="text-align: justify;">#define SDA_PIN <b>GPIO_NUM_21</b></div></span><span style="font-family: Nunito; text-align: left;"><div style="font-style: italic; text-align: justify;">#endif</div><div style="font-style: italic; text-align: justify;"><br /></div><div style="text-align: justify;">OK, 이번에는 제대로 동작한다.</div></span></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn5Qe5z9WaS9ZedUAppEuQ09PVueS-06-qQSCX_jQZQFh311Z5F7xFcx1znhoVd2MbxhZy05r2AuMLis-W9Qnrq07f2T1UYtxLdRqVO1q0KKtzp3IKwRFYq_9epcQqX4xtEUK5JpvSz9ngb7r3ZojkdKyDsGlwqEu949gKtS9VrYdcs3woYwu4wXvHhg/s818/esp32_adxl345_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="653" data-original-width="818" height="319" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn5Qe5z9WaS9ZedUAppEuQ09PVueS-06-qQSCX_jQZQFh311Z5F7xFcx1znhoVd2MbxhZy05r2AuMLis-W9Qnrq07f2T1UYtxLdRqVO1q0KKtzp3IKwRFYq_9epcQqX4xtEUK5JpvSz9ngb7r3ZojkdKyDsGlwqEu949gKtS9VrYdcs3woYwu4wXvHhg/w400-h319/esp32_adxl345_run.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.16] ADXL345 가속도 센서 동작 모습</div><div class="separator" style="clear: both; text-align: center;"><br /></div><p><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>d) ADXL345를 spi 포트에 연결하기</b></span></p><p><span style="font-family: Nunito;"></span></p><div><span style="font-family: Nunito;">지금까지 adxl345 i2c 드라이버의 동작을 확인해 보았으니, 이번에는 ADXL345를 SPI 확장 핀에 연결한 후, SPI driver를 구현해 볼 차례이다. 이 부분은 독자 여러분의 몫이다. <b><span style="background-color: #fcff01; color: #990000;">[ESP32 Course 과제 1]</span></b> 😛</span></div><div><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbxOYwjoz5ias9Pw-AdIt_rulkLEtNQ9ICKcI4OsK3hjxgFdGAE8evf_DytDdbdAQnB-eIbyRgMf5d22Y97xXkawrTriIgOW8beKzYBSIWgWQtJpvY5FrYsYZwoHGY4RgsCab2XgoqBLqcwL6jEuolcg2MbC73YYoDzrGJBBoCUQIGMr9akOf1iL53lg/s768/esp32-doit-dev-kit-v1-adxl345-SPI_bb.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="414" data-original-width="768" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbxOYwjoz5ias9Pw-AdIt_rulkLEtNQ9ICKcI4OsK3hjxgFdGAE8evf_DytDdbdAQnB-eIbyRgMf5d22Y97xXkawrTriIgOW8beKzYBSIWgWQtJpvY5FrYsYZwoHGY4RgsCab2XgoqBLqcwL6jEuolcg2MbC73YYoDzrGJBBoCUQIGMr9akOf1iL53lg/w400-h216/esp32-doit-dev-kit-v1-adxl345-SPI_bb.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.17] ESP32-WROOM-32 보드와 ADXL345를 SPI로 연결한 모습 [출처: 참고문헌 6]</div><br /><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b><참조 site></b></span></div><div><span style="font-family: Nunito;">[1] <a href="https://github.com/hepingood/adxl345">https://github.com/hepingood/adxl345</a></span></div><div><span style="font-family: Nunito;">[2] <a href="https://www.youtube.com/watch?v=XSzRwJNJ4u8&ab_channel=smTronics">https://www.youtube.com/watch?v=XSzRwJNJ4u8&ab_channel=smTronics</a></span></div><div><span style="font-family: Nunito;">[3] https://www.mischianti.org/2022/08/13/gy-291-adxl345-i2c-spi-accelerometer-with-interrupt-for-esp32-esp8266-stm32-and-arduino/</span></div><div><span style="font-family: Nunito;">[4] ...</span></div><div><span style="font-family: Nunito;"><br /></span></div><p style="text-align: left;"><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>3. ESP32 보드에 WireGuard 올리기</b></span></p><div style="text-align: left;"><span style="font-family: Nunito;">이번 장에서는 esp32 보드에 wireguard를 올리는 과정을 소개해 보고자 한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito; font-size: medium;"><b style="color: #38761d;">a) FreeRTOS & LWIP용 Wireguard </b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">FreeRTOS & lwip tcp/ip stack 기반의 초소형 chipset용 wireguard open source를 찾던 중, 반가운 것을 하나 발견했다. </span><span style="font-family: Nunito;">😍 </span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/smartalock/wireguard-lwip">https://github.com/smartalock/wireguard-lwip</a></span></div><div style="text-align: center;"><br /></div><div style="text-align: justify;"><span style="font-family: Nunito;"><span style="text-align: left; white-space: pre-wrap;">바로, Daniel Hope이 2021년에 </span><span style="background-color: white; color: #24292f; font-size: 16px; text-align: left;">작성한 코드로 wireguard를 lwip 기반 위에서 돌아가도록 해 주고 있다. 아래 두 link는 이 코드를 기반으로 약간의 변형을 가한 example들이다.</span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><span style="background-color: white; color: #24292f; font-size: 16px; text-align: left;"><br /></span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://registry.platformio.org/libraries/zmeiresearch/Wireguard%20client%20for%20LwIP%20on%20ESP32">https://registry.platformio.org/libraries/zmeiresearch/Wireguard%20client%20for%20LwIP%20on%20ESP32</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/trombik/esp_wireguard">https://github.com/trombik/esp_wireguard</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="background-color: #fff2cc; font-family: Nunito;">이 중 마지막 source(esp_wireguard)가 esp32에 맞게 porting된 코드인지라, 얘를 가지고 esp32 board에서 동작 시험을 진행해 보도록 하자.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #e69138;"><span style="white-space: pre-wrap;"><br /></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #e69138;"><span style="white-space: pre-wrap;"><span style="background-color: white; color: black; font-size: 14.85px; white-space: normal;">________________________________________________________________________________</span></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;"><b><여기서 잠깐></b></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="color: #b45f06; white-space: pre-wrap;">Linux 사용자 영역에서 동작하는 C 기반의 wireguard를 만들고자 한다면 ?</span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;"><span style="background-color: white; font-family: Nunito; font-size: 14.85px; white-space: normal;"><span style="color: #38761d;">Linux용 wireguard는 kernel version과 Go version이 이미 구비되어 있다. 하지만 상황이 여유치 않을 경우, 즉 linux kernel header를 구하기 어렵거나, flash memory 공간이 부족(Go로 만든 wireguard binary 크기가 큼)한 경우 등에는 사용자 영역에서 동작하는 C로 구현된 wireguard가 필요할 수도 있다. 이 경우, 위의 코드를 Linux tcp/ip stack에서 돌아가도록 변형하는 것이 하나의 대안이 될 수 있다. 관심 있는 분들은 도전해 보시길... </span>😱</span></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;"><span style="background-color: white; font-family: Nunito; font-size: 14.85px; white-space: normal;"><br /></span></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj17IbhPX8cIUa2QUylxN8RmxQVGOtYmNH3yHeeEPOr6LF4RjpXRO672ThLOhM3X4MYVTEqKC3vfjSL6EMzLizet2eXOjjssC6U2gZyZEjF6fWvJzcPJPDWq39cOZjxo98KDYdKI2uuRN6gm4cwmX97z2V_F-amEl05D3So6cjTBRVyCP-eqnxM8eo2Qw/s957/wireguard-c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="957" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj17IbhPX8cIUa2QUylxN8RmxQVGOtYmNH3yHeeEPOr6LF4RjpXRO672ThLOhM3X4MYVTEqKC3vfjSL6EMzLizet2eXOjjssC6U2gZyZEjF6fWvJzcPJPDWq39cOZjxo98KDYdKI2uuRN6gm4cwmX97z2V_F-amEl05D3So6cjTBRVyCP-eqnxM8eo2Qw/w400-h310/wireguard-c.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] C 언어로 작성한 Linux 사용자 영역에서 동작하는 wireguard daemon 구동 모습</div></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;"><span style="background-color: white; font-family: Nunito; font-size: 14.85px; white-space: normal;">________________________________________________________________________________</span></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #e69138;"><span style="white-space: pre-wrap;"><br /></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><span style="white-space: pre-wrap;">자, 먼저 source를 내려 받은 후, build를 해 보도록 한다.</span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #e69138;"><span style="white-space: pre-wrap;"><br /></span></span></span><span style="font-family: Nunito;">$ <b>git clone https://github.com/trombik/esp_wireguard</b><br /></span><span style="font-family: Nunito;">$ <b>cd esp_wireguard/</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$<b> cd examples/demo</b><br /></span><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"> -> Component config -> WireGuard 선택</span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpFB1TO7SyAxakq0N09C3kSnWyhtyYyf3lQjDmuhG7FtfiJVqOMPulFOHvzp3GPmsksFeC4vvEVWcv32o4Cy_rewNJ8Sand9_Lixt1xKBiSkrSv2QHcUhNPKqLyeGHbQ7qwa2IYpmALalueBegA1u9S7IJ9jLPHLmJJaXtjB0sOT2wGdYemcjyDsqE0Q/s1110/esp32_wireguard.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="767" data-original-width="1110" height="442" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpFB1TO7SyAxakq0N09C3kSnWyhtyYyf3lQjDmuhG7FtfiJVqOMPulFOHvzp3GPmsksFeC4vvEVWcv32o4Cy_rewNJ8Sand9_Lixt1xKBiSkrSv2QHcUhNPKqLyeGHbQ7qwa2IYpmALalueBegA1u9S7IJ9jLPHLmJJaXtjB0sOT2wGdYemcjyDsqE0Q/w640-h442/esp32_wireguard.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.2] idf.py menuconfig - wireguard 설정 확인</span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">$ <b>idf.py build</b></span><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB0 flash</b></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;">Wireguard code를 build 한 후, flash writing을 해 보면, (제일 먼저) 아래와 같은</span><span style="font-family: Nunito; white-space: pre-wrap;"> RF calibration 관련 에러가 발생한다. 인터넷을 좀 뒤져 보니 이는 board로 들어가는 전원(power)이 딸려서 그런 것이란다. USB hub을 notebook(or PC)이 아니라, 5V 전원을 공급하는 것으로 교체 후, 다시 시도해 보니, 문제가 바로 해결되었다.</span></div><div style="text-align: left;"><span style="color: #e69138; font-family: Nunito;"><span style="white-space: pre-wrap;"><br /></span></span></div><div style="text-align: left;"><span style="color: #e69138; font-family: Nunito;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9u4-TIUp-X8QKTQSsgChoEY0GTtU0aCtQjQWiWrTfxwopjlPu52XbjwqI905dWhWUEAfYOj4BQN4jLCEoj5WtC9yrOgxXuvacrQ6VpW9mB6LpVNaYVVoeLEiVVkJAkOpuxCGSE06OGUHZSLISkuFndc461EtrBk9zen0f88h4TwJEU3JB5OgfmM3piA/s1110/esp32_wifi_error.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="808" data-original-width="1110" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9u4-TIUp-X8QKTQSsgChoEY0GTtU0aCtQjQWiWrTfxwopjlPu52XbjwqI905dWhWUEAfYOj4BQN4jLCEoj5WtC9yrOgxXuvacrQ6VpW9mB6LpVNaYVVoeLEiVVkJAkOpuxCGSE06OGUHZSLISkuFndc461EtrBk9zen0f88h4TwJEU3JB5OgfmM3piA/w400-h291/esp32_wifi_error.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="color: black;">[그림 3.3] wireguard binary를 적용 후 부팅하는 모습 - RF calibration 적재 실패 에러</span></div></span><span style="font-family: Nunito;"><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div>근데, 다시 아래와 같은 wifi AP(Access Point)에 연결할 수 없다는 에러가 보인다.</span></div><div style="text-align: left;"><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_LwSbl6jw8HVHDGIkmo_tvPsEIb2zOTEkbFzn3hmDDWDxLkXchW4Wmdo5jftOovmeG6FsKMqE3iS7qRr_8kGF7Mll3YWvEoholGSCwoHvadFDnzYbuQq9Wy5Rqb88nryqJ8OIYmrYZxSBGnvJxHcaIB-TMrG_D5ZI2p_5oUYMh6sHGNDAl5j6N6QRXg/s1051/esp32_wireguard_boot_error.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="657" data-original-width="1051" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_LwSbl6jw8HVHDGIkmo_tvPsEIb2zOTEkbFzn3hmDDWDxLkXchW4Wmdo5jftOovmeG6FsKMqE3iS7qRr_8kGF7Mll3YWvEoholGSCwoHvadFDnzYbuQq9Wy5Rqb88nryqJ8OIYmrYZxSBGnvJxHcaIB-TMrG_D5ZI2p_5oUYMh6sHGNDAl5j6N6QRXg/w400-h250/esp32_wireguard_boot_error.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] wireguard binary를 적용 후 부팅하는 모습 - wifi 연결 관련 에러 발생</span></div><div><br /></div><div><span style="font-family: Nunito;">아직, wi-fi SSID 등을 설정한 사실이 없으니, 이건 당연히 발생할 수 밖에 없는 에러이다. 그렇다면 Wi-Fi SSID 등은 어디에서 설정해 줄까 ?</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><b style="font-family: Nunito;">idf.py menuconfig </b><span style="font-family: Nunito;">명령을 실행</span><span style="font-family: Nunito;">해 보면, 아래와 같이 </span><b style="font-family: Nunito;">example configuration 설정 화면</b><span style="font-family: Nunito;">이 보인다. 가만히 보니 이곳에 wi-fi 설정은 물론이고, wireguard 설정에 필요한 모든 내용이 담겨 있다. </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">그렇다면 아래 network 구성도를 참조하여, 여기에 있는 값 들을 적절히 수정해 보도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><참고 - WireGuard 구성></b></span></div><div style="text-align: center;"><span style="color: #134f5c; font-family: Nunito;"><b style="background-color: #d9ead3;">ESP32 board(vpnip: 10.1.1.252) => Wi-Fi AP(GL-MV-1000-581) => Internet => AWS EC2(vpnip: 10.1.1.1)</b></span></div><div><span style="font-family: Nunito;"><br /></span></div></div><div><span style="font-family: Nunito;">$ idf.py menuconfig</span></div><div><span style="font-family: Nunito;"> -> Example Configuration</span></div><div><br /></div></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdeVxDe10iCAYxO0tf6KQLP0FrtIavs1ucfCh32J8W5tXpxxyPTxHNasl_5AOeO2D_ZAs07JmcRt1MUYTaXXbjPUWjkSmd9PUu37-l2aTkuicGJx-njs6aiY-7O-JGeJGg7wmoUbX7BT-sU33gkkSZNTTSoKI_VVQMt7zvSCB-WVJ_Lui3Azp-atDR-g/s937/esp32_wireguard_config_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="651" data-original-width="937" height="445" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdeVxDe10iCAYxO0tf6KQLP0FrtIavs1ucfCh32J8W5tXpxxyPTxHNasl_5AOeO2D_ZAs07JmcRt1MUYTaXXbjPUWjkSmd9PUu37-l2aTkuicGJx-njs6aiY-7O-JGeJGg7wmoUbX7BT-sU33gkkSZNTTSoKI_VVQMt7zvSCB-WVJ_Lui3Azp-atDR-g/w640-h445/esp32_wireguard_config_ok.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] wireguard example configuration 모습</span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 </span><span style="color: #e69138; font-family: Nunito; white-space: pre-wrap;">esp32용 curve25519 keypair는 Ubuntu PC 등에서 아래와 같이 생성하여 사용하면 된다.</span></div><div style="text-align: center;"><span><span><span style="font-family: Nunito; white-space: pre-wrap;"><b>wg genkey | tee ./privatekey | wg pubkey > ./publickey</b></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">다시 source code를 full build 후, flash writing을 해 보도록 한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>idf.py fullclean</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="font-family: Nunito;">$ <b>idf.py build</b></span><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB0 flash</b></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;">flash memory에 bin file을 writing한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">이후 아래 명령을 사용하여 동작 과정을 모니터링해 보자.</span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ </span><b style="font-family: Nunito;">idf.py -p /dev/ttyUSB0 monitor</b></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 </span><span style="background-color: white; color: #e69138; font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;">위의 방법 대신 minicom(115200, 8N1)을 이용해도 된다.</span></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI5Q7keW7jHvYNwpj9Kh8VjSd5HshBbJzeT5qVkxYNb7nSt3qVWB_nig0qugqFpr0WaEnJ6Hys4mKuiWwGc-Xm0RXt0WG0uBmtL29lPiUM2WOiZwLbqa3IAbZlW6VEWrGOnSKumNSWtHQbJgS9iuWuzKt90vNfeToJiirxVf0p18KzikRlbRII4H531Q/s953/esp32_wifi_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="855" data-original-width="953" height="359" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgI5Q7keW7jHvYNwpj9Kh8VjSd5HshBbJzeT5qVkxYNb7nSt3qVWB_nig0qugqFpr0WaEnJ6Hys4mKuiWwGc-Xm0RXt0WG0uBmtL29lPiUM2WOiZwLbqa3IAbZlW6VEWrGOnSKumNSWtHQbJgS9iuWuzKt90vNfeToJiirxVf0p18KzikRlbRII4H531Q/w400-h359/esp32_wifi_ok.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] Wi-Fi AP에 정상 연결된 모습</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;">어라, 근데, wifi 연결 이후에 아래와 같은 panic 에러가 발생하면서 시스템이 반복적으로 reset이 된다. 왜 그럴까 ?</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx9CDTVEtLkBv2rfPlr5F1aDRj0h_7EcD3G5zGJi71vvodNGx3pglqfL_Wz1u2Xo6xZbNV46NqezvFWXYyjj4wtTVIeWHZtrl5mmjA-7AwIFkjJnFhGUe9vt5fq70nc6S9IghB-B_sAIDXEiDQFydCmhOfGzZwg-ZUZ-rcHmejxmEzHq6zcgJ4fGOhBA/s1089/esp32_wireguard_panic_error.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="844" data-original-width="1089" height="496" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx9CDTVEtLkBv2rfPlr5F1aDRj0h_7EcD3G5zGJi71vvodNGx3pglqfL_Wz1u2Xo6xZbNV46NqezvFWXYyjj4wtTVIeWHZtrl5mmjA-7AwIFkjJnFhGUe9vt5fq70nc6S9IghB-B_sAIDXEiDQFydCmhOfGzZwg-ZUZ-rcHmejxmEzHq6zcgJ4fGOhBA/w640-h496/esp32_wireguard_panic_error.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.7] wireguard panic error 발생 모습</span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="text-align: center;"><span style="background-color: white; color: #b45f06; font-size: 14.85px; text-align: left;">📌 </span><span style="color: #e69138; text-align: left; white-space: pre-wrap;">esp-idf는 위와 같이 back trace 정보를 자동 출력해 주므로 debugging하는데 많은 도움이 된다.</span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="text-align: center;"><br /></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;">내용을 자세히 보면, lwip/esp_netif_lwip.c 파일 esp_netif_internal_dhcpc_cb 함수에서 뜬금 없이 죽는다. 왜 일까 ?</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito; font-size: x-small;"><span style="color: #38761d; text-align: center;"><div style="text-align: left;">0x400f7662: esp_netif_internal_dhcpc_cb at /home/chyi/workspace/ESP32/esp-idf/components/esp_netif/lwip/esp_netif_lwip.c:1195</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400f7736: netif_callback_fn at /home/chyi/workspace/ESP32/esp-idf/components/esp_netif/lwip/esp_netif_lwip.c:117</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400e4adf: netif_invoke_ext_callback at /home/chyi/workspace/ESP32/esp-idf/components/lwip/lwip/src/core/netif.c:1819</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400e4b8a: netif_set_addr at /home/chyi/workspace/ESP32/esp-idf/components/lwip/lwip/src/core/netif.c:733</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400e4cce: netif_add at /home/chyi/workspace/ESP32/esp-idf/components/lwip/lwip/src/core/netif.c:376</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400d6ff8: esp_wireguard_netif_create at /home/chyi/workspace/ESP32/esp_wireguard/examples/demo/components/esp_wireguard/src/esp_wireguard.c:185</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400d7294: esp_wireguard_connect at /home/chyi/workspace/ESP32/esp_wireguard/examples/demo/components/esp_wireguard/src/esp_wireguard.c:240</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400d6b8a: wireguard_setup at /home/chyi/workspace/ESP32/esp_wireguard/examples/demo/main/main.c:79 (discriminator 13)</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x400d6d9c: app_main at /home/chyi/workspace/ESP32/esp_wireguard/examples/demo/main/main.c:381</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x40156ebb: main_task at /home/chyi/workspace/ESP32/esp-idf/components/freertos/app_startup.c:208 (discriminator 13)</div><div style="text-align: left;"><br /></div><div style="text-align: left;">0x4008b9b5: vPortTaskWrapper at /home/chyi/workspace/ESP32/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:162</div></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="text-align: center;"><br /></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;">한참을 debugging 한 끝에, esp_netif code에 결함이 있음을 알게 되었고, 아래와 같이 코드 수정하여 임시로 해결하였다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4uHjWV1AZSneJMk-0KkP0bd7Jhb5PD_obXDxV5uWCbHEFcVQSGWXMis-1fVraqzUblouof-IEYjny8fMNnnQGZ8Hq2Y7dRil52GbIr7APqr3mi1mEayItNW2zoIeDDpAeor4MQWOvYsgimy7UyQEz-LUiaRaFDMLPlhI7VEAaKVjK17CoFddx5dYOSg/s943/esp32_lwip_bug_fixed.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="636" data-original-width="943" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4uHjWV1AZSneJMk-0KkP0bd7Jhb5PD_obXDxV5uWCbHEFcVQSGWXMis-1fVraqzUblouof-IEYjny8fMNnnQGZ8Hq2Y7dRil52GbIr7APqr3mi1mEayItNW2zoIeDDpAeor4MQWOvYsgimy7UyQEz-LUiaRaFDMLPlhI7VEAaKVjK17CoFddx5dYOSg/w400-h270/esp32_lwip_bug_fixed.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.8] lwip 버그 수정 내용</span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="text-align: center;"><br /></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="text-align: center;"><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="font-family: Nunito;"><span style="color: #666666;">(이부분은 나중에 작업한 것임) </span>또한, 중요한 부분은 아니나, while loop을 돌면서 반복적으로 wireguard 연결을 끊고 다시 연결하는 코드가 있어 아래와 같이 재연결하지 않도록 막아 보기로 한다.</span></div><div style="font-family: "Noto Sans CJK KR"; text-align: left;"><br /></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR";"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1_sJmM3QVpsLxi7nYOlRMulGXsSotAWd4E2ArJMtt_sqQMO0uMh5MHwzOjjjs9dOHaD0u-C6tUIEchNXFQn1wgmQdsdGf52PIpcdiJuCynNXFZShX1aCCMtiBHWcfzEfpDCJJp0w9MFj0-26yn0D3Xt4kCv0UN7sR9ZeOl8AR63jGTm6B9MS277frVw/s718/esp32_wireguard_main_loop_fixed.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="607" data-original-width="718" height="339" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1_sJmM3QVpsLxi7nYOlRMulGXsSotAWd4E2ArJMtt_sqQMO0uMh5MHwzOjjjs9dOHaD0u-C6tUIEchNXFQn1wgmQdsdGf52PIpcdiJuCynNXFZShX1aCCMtiBHWcfzEfpDCJJp0w9MFj0-26yn0D3Xt4kCv0UN7sR9ZeOl8AR63jGTm6B9MS277frVw/w400-h339/esp32_wireguard_main_loop_fixed.png" width="400" /></a></div><div class="separator" style="clear: both; font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">[그림 3.9] wireguard connect & disconnect 반복 routine 제거</span></div></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">다시 source code를 build 후, flash writing을 해 보도록 한다.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><span style="font-family: Nunito;">$ <b>idf.py build</b></span><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB0 flash</b></span></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">$ </span><b style="font-family: Nunito;">idf.py -p /dev/ttyUSB0 monitor</b></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">와우, 드디어 동작한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj72DoqTdfK0YkLddV73_LdY__yixXP9cwL-VTxGfPk3c91OYR5GOX8DZ3OE7fHslTYBn98pgy6BhPubnIrBMaAZbsIj_cg7hhJ1IkJ6xK13pwUXYXzGvR36U_1X7IgN9nmuRtycpux5A13ggKF6FjNtDCgsojF28MgrcdS3OHXQVl4ZtXXRlGwXTZkog/s908/esp32_wireguard_ping_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="632" data-original-width="908" height="446" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj72DoqTdfK0YkLddV73_LdY__yixXP9cwL-VTxGfPk3c91OYR5GOX8DZ3OE7fHslTYBn98pgy6BhPubnIrBMaAZbsIj_cg7hhJ1IkJ6xK13pwUXYXzGvR36U_1X7IgN9nmuRtycpux5A13ggKF6FjNtDCgsojF28MgrcdS3OHXQVl4ZtXXRlGwXTZkog/w640-h446/esp32_wireguard_ping_ok.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.10] esp32 board 상에서 aws ec2 wireguard로 ping이 되는 모습</span></div><div style="text-align: left;"><br /></div><span style="font-family: Nunito;">당연한 거지만, aws ec2에도 wireguard가 동작하고 있어야 한다. Ubuntu 상에서의 wireguard 설정과 관련해서는 이미 여러 차례 설명한 바 있으므로, 자세한 설정은 생략하기로 한다.</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="goog_1139710267"><br /></a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html</a></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito;"><span style="font-size: medium;">b) ADXL345 driver code와 Wireguard 통합하기</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">이번 절에서는 2장에서 검증한 i2c driver code와 이번 장에서 설명한 Wireguard code를 하나로 통합한 후, adxl345 sensor를 통해 감지된 3축 가속도 센서 정보를 VPN server로 전달하는 예제를 작성해 보기로 하겠다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><TBD> </span><b style="font-family: Nunito;"><span style="background-color: #fcff01; color: #990000;">[ESP32 Course 과제 2]</span></b><span style="font-family: Nunito;"> 😛</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[1] ESP32 board 상에 task를 하나 만들고 udp로 sensor 정보를 서버로 전달하는 routine(client) 구현</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[2] AWS EC2 상에 udp server를 하나 만들고, client로 부터 온 내용을 출력</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[3] client & server 간에 전송되는 message format(규격)을 정의해야 함.</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><p style="text-align: left;"><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>4. ESP32를 NAT Gateway로 만들기</b></span></p><p><span style="font-family: Nunito;">ESP32는 IoT device용 초소형 chipset이다. 그런데, esp32 board를 NAT gateway로 만드는 아주 흥미로운 내용이 있어 여기에 소개해 보고자 한다. 😗 사실 embedded linux를 올리고, netfilter를 사용하면 아주 쉽게 NAT gateway를 만들 수 있지만, esp32(정확히는 LWIP)라면 사정이 완전히 달라진다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;">[1] <a href="https://github.com/jonask1337/esp-idf-nat-example">https://github.com/jonask1337/esp-idf-nat-example</a></span></p><p style="text-align: center;"><span style="font-family: Nunito;">[2] <a href="https://github.com/martin-ger/esp32_nat_router">https://github.com/martin-ger/esp32_nat_router</a></span></p><p style="text-align: center;"><br /></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkRrUpLXKfnpI0PHbVqvUSgGmNDuGE9nzP0SmAIUdEuVLlKPBRWKZOzITaVK2gslga0mJnZBsTUON1Z1qgq_iBtL0UK6-Cs9zS7Yk1d-WnkIx2HNYVX0k_t1g5iFdseRwAnYiTddk17AlCwAzHu1gRkaYidsKmBeUUp6-fbAPm2iBQDdtaFmkzQPrcAA/s1990/72107648-085e4a80-3332-11ea-95a7-e2269adb37dd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="644" data-original-width="1990" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkRrUpLXKfnpI0PHbVqvUSgGmNDuGE9nzP0SmAIUdEuVLlKPBRWKZOzITaVK2gslga0mJnZBsTUON1Z1qgq_iBtL0UK6-Cs9zS7Yk1d-WnkIx2HNYVX0k_t1g5iFdseRwAnYiTddk17AlCwAzHu1gRkaYidsKmBeUUp6-fbAPm2iBQDdtaFmkzQPrcAA/w640-h208/72107648-085e4a80-3332-11ea-95a7-e2269adb37dd.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 4.1] ESP32 NAT Gateway [출처: 위의 site [1]]</span></div><p></p><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>a) LWIP NAT feature enable하기</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">최신 esp32 sdk에는 이미 위의 site에서 말하는 NAT 관련 code가 포함되어 있는 것으로 보인다. 따라서, </span><span style="font-family: Nunito;">idf.py menuconfig 한 후, Component -> LWIP 아래에서 아래와 같이 3가지 설정을 enable해 주도록 하자.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;"> [*] Enable copy between Layer2 and Layer3 packets<br /></span><span style="font-family: Nunito;"> [*] Enable IP forwarding<br /></span><span style="font-family: Nunito;"> [*] Enable NAT (new/experimental)</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggDqt0xG4Q-m9IrNWtckl_pPhwKlFnBgIyhNpuqI8G4AEzjNHPgTr8Bw9eZtU5iWoP423m74wUl7gJDfFvH9ThY58mfvwyiqB6Mt4Sky24W05tJojeZumMriTp1HZ-Ob0Q0zLxaGqDGeChaaPZlbITDjUGYLX_pqFhpGm-1FJszzsZrJiErjmP1HhoCw/s922/esp32_nat_enable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="811" data-original-width="922" height="351" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggDqt0xG4Q-m9IrNWtckl_pPhwKlFnBgIyhNpuqI8G4AEzjNHPgTr8Bw9eZtU5iWoP423m74wUl7gJDfFvH9ThY58mfvwyiqB6Mt4Sky24W05tJojeZumMriTp1HZ-Ob0Q0zLxaGqDGeChaaPZlbITDjUGYLX_pqFhpGm-1FJszzsZrJiErjmP1HhoCw/w400-h351/esp32_nat_enable.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 4.2] idf.py menuconfig - lwip NAT enable 모습(1)</span></div><p><span style="font-family: Nunito;">그런데, esp-idf 최신 version 환경에서 build해 보니, (일일이 해결하기에 너무 많은) 에러가 발생한다. 아무래도 esp-idf의 적당한 버젼을 찾아서 build를 해 보아야 겠다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><b style="color: #38761d; font-family: Nunito; font-size: large;">b) NAT Gateway 동작 확인하기</b></p><div style="text-align: left;"><span style="font-family: Nunito;">몇가지 시도 끝에 esp-idf v4.4에서 제대로 build가 되는 것을 알았다. 여기에 그 내용을 정리해 보기로 한다.</span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 </span><span style="background-color: white; color: #e69138; font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;">반드시 v4.4에서만 build가 되는 것은 아니므로, 다른 version으로도 시도해 보기 바란다.</span></div><div style="text-align: left;"><span style="background-color: white; color: #e69138; font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;"><span style="color: #b45f06; font-family: Nunito; font-size: 14.85px; white-space: normal;">📌 </span><span style="color: #e69138; font-family: Nunito; font-size: 14.85px;">3장에서 소개한 wireguard code도 v4.4 환경에서 build가 된다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">$ mkdir stable; cd stable</span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>git clone --recursive https://github.com/espressif/esp-idf.git</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div>$ <b>git branch</b></div><div>* master</div><div>$ <b>git checkout "release/v4.4"</b></div><div><div>$ <b>git branch</b></div><div> master</div><div>* release/v4.4</div></div><div>$ <b>git submodule update --init --recursive</b></div><div>$ <b>./install.sh esp32</b></div></span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 </span><span style="background-color: white; color: #e69138; font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;">현재 터미널 상태가 ". ./export.sh"을 시도한 상태라면, 이 명령 실행시 에러가 발생하게 되므로, 다른 terminal을 띄우고 이 명령을 다시 실행해 주기 바란다.</span></div><div style="text-align: left;"><span style="background-color: white; color: #e69138; font-family: Nunito; font-size: 14.85px; white-space: pre-wrap;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ cd ..</span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>git clone https://github.com/martin-ger/esp32_nat_router</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ cd </span><span style="font-family: Nunito;">esp32_nat_router</span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW_iZLdotmn2-mnu6C5299GSSyrOVcZdssqpwTnHnoNwaum4tfSxXrZVEzELhFfSnKEpZ9MVuh2kYODD8Lnnk7Zo7XOkTc3rJbXkG7dgbHeL9ULUyvmTU1LiS-b7NksptPQj689fUbwIbK3CW3L0HJmk9btZOVIU8Qm-1UpfD9OgOVy4ibqPo5mX19Mg/s1037/esp32_nat_router_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="742" data-original-width="1037" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW_iZLdotmn2-mnu6C5299GSSyrOVcZdssqpwTnHnoNwaum4tfSxXrZVEzELhFfSnKEpZ9MVuh2kYODD8Lnnk7Zo7XOkTc3rJbXkG7dgbHeL9ULUyvmTU1LiS-b7NksptPQj689fUbwIbK3CW3L0HJmk9btZOVIU8Qm-1UpfD9OgOVy4ibqPo5mX19Mg/w400-h286/esp32_nat_router_menuconfig.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 4.3] idf.py menuconfig - lwip NAT enable 모습(2)</span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>idf.py build</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div><i><span style="font-size: x-small;">...</span></i></div><div><i><span style="font-size: x-small;">r/bootloader.bin</span></i></div><div><i><span style="font-size: x-small;">Bootloader binary size 0x5b40 bytes. 0x14c0 bytes (19%) free.</span></i></div><div><i><span style="font-size: x-small;">[1046/1058] Building C object esp-idf/main/CMakeFiles/__idf_main.dir/http_server.c.obj</span></i></div><div><i><span style="font-size: x-small;">In file included from /home/chyi/workspace/ESP32/stable/esp32_nat_router/main/http_server.c:23:</span></i></div><div><i><span style="font-size: x-small;">/home/chyi/workspace/ESP32/stable/esp32_nat_router/main/pages.h:167:70: warning: backslash-newline at end of file</span></i></div><div><i><span style="font-size: x-small;"> #define LOCK_PAGE "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n\</span></i></div><div><i><span style="font-size: x-small;"> </span></i></div><div><i><span style="font-size: x-small;">/home/chyi/workspace/ESP32/stable/esp32_nat_router/main/http_server.c:258:13: warning: 'stop_webserver' defined but not used [-Wunused-function]</span></i></div><div><i><span style="font-size: x-small;"> static void stop_webserver(httpd_handle_t server)</span></i></div><div><i><span style="font-size: x-small;"> ^~~~~~~~~~~~~~</span></i></div><div><i><span style="font-size: x-small;">[1057/1058] Generating binary image from built executable</span></i></div><div><i><span style="font-size: x-small;">esptool.py v3.3.2</span></i></div><div><i><span style="font-size: x-small;">Creating esp32 image...</span></i></div><div><i><span style="font-size: x-small;">Merged 25 ELF sections</span></i></div><div><i><span style="font-size: x-small;">Successfully created esp32 image.</span></i></div><div><i><span style="font-size: x-small;">Generated /home/chyi/workspace/ESP32/stable/esp32_nat_router/build/esp32_nat_router.bin</span></i></div><div><i><span style="font-size: x-small;">[1058/1058] cd /home/chyi/workspace/ESP32/stable/esp32_n...ESP32/stable/esp32_nat_router/build/esp32_nat_router.bin</span></i></div><div><i><span style="font-size: x-small;">esp32_nat_router.bin binary size 0xe3e80 bytes. Smallest app partition is 0x100000 bytes. 0x1c180 bytes (11%) free.</span></i></div><div><i><span style="font-size: x-small;"><br /></span></i></div><div><i><span style="font-size: x-small;">Project build complete. To flash, run this command:</span></i></div><div><i><span style="font-size: x-small;">/home/chyi/.espressif/python_env/idf4.4_py3.8_env/bin/python ../esp-idf/components/esptool_py/esptool/esptool.py -p (PORT) -b 460800 --before default_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/esp32_nat_router.bin</span></i></div><div><i><span style="font-size: x-small;">or run 'idf.py -p (PORT) flash'</span></i></div><div>와우, build가 정상적으로 진행된다.</div><div><br /></div><div>$ <b>idf.py -p /dev/ttyUSB1 flash</b></div><div>$ <b>idf.py -p /dev/ttyUSB1 monitor</b></div><div><br /></div><div>Serial console로 동작 모습을 확인해 본다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK18XUboqD_70DhDOhoGUQKxdClK1uw2qvJAlW6VhSVPTA7ikpjVWI8kWpBr8kCNpHsZP7j6aXstDNGg2QlrFYNKtj-9cOSItAxo6wTNkANC3r66ItDGl0-lD0_O5h36zzQSI0wE2YiNX0_xsZO2H4poTA-eqIrZhzw_3v4xTfNfxiPG7BrfsXhNBrTA/s955/esp32_nat_router_run1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="746" data-original-width="955" height="313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhK18XUboqD_70DhDOhoGUQKxdClK1uw2qvJAlW6VhSVPTA7ikpjVWI8kWpBr8kCNpHsZP7j6aXstDNGg2QlrFYNKtj-9cOSItAxo6wTNkANC3r66ItDGl0-lD0_O5h36zzQSI0wE2YiNX0_xsZO2H4poTA-eqIrZhzw_3v4xTfNfxiPG7BrfsXhNBrTA/w400-h313/esp32_nat_router_run1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.4] </span><span style="text-align: left;">idf.py -p /dev/ttyUSB1 monitor 모습</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b>esp32> </b>로 시작하는 cli 명령어도 보인다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuJZApyKLaIJwcmRBGqEZQVy7Rrgzrz7IOm4y1VsHeSlAOf1GYn4abUJjEcsJr5ti9WkaHe5TRp62oP8ND7zhk-vodJNf9WuYAhd3mjG8Qjg9oRmyKHtg-g0DdX_VS6JRHY_Lw3xlOrEBGtDGjfL8EUUK7dxojfN__TqjKpaC2SagX59Y-6DOXFKhvXw/s753/esp32_nat_router_cli.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="691" data-original-width="753" height="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuJZApyKLaIJwcmRBGqEZQVy7Rrgzrz7IOm4y1VsHeSlAOf1GYn4abUJjEcsJr5ti9WkaHe5TRp62oP8ND7zhk-vodJNf9WuYAhd3mjG8Qjg9oRmyKHtg-g0DdX_VS6JRHY_Lw3xlOrEBGtDGjfL8EUUK7dxojfN__TqjKpaC2SagX59Y-6DOXFKhvXw/w400-h368/esp32_nat_router_cli.png" width="400" /></a></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.5] </span><span style="text-align: left;">idf.py -p /dev/ttyUSB1 monitor 모습(2) - CLI</span></div><div><br /></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;">그리고, 보다 재밌는 것은 web 설정 화면이 있다는 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj48aAXuJKcjyp89cPG3W7XNg6qpNkktXp0-6yv6T3wgn76VBZn2UDivYp4G52yTiEtMjhNd007Rx3UlnkOZi2tqGPtjrAFni56vCraxXFPqMYB_PneBGj_CdPjTAUK-Eq3i3W4UnAEScluM4y9R0pdG5SmCeaKHF5QsgKLU52LjZdSmQpIE0QvqxpHlA/s1050/esp32_nat_router.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="829" data-original-width="1050" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj48aAXuJKcjyp89cPG3W7XNg6qpNkktXp0-6yv6T3wgn76VBZn2UDivYp4G52yTiEtMjhNd007Rx3UlnkOZi2tqGPtjrAFni56vCraxXFPqMYB_PneBGj_CdPjTAUK-Eq3i3W4UnAEScluM4y9R0pdG5SmCeaKHF5QsgKLU52LjZdSmQpIE0QvqxpHlA/w400-h316/esp32_nat_router.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.6] http://192.168.4.1 접속 모습</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div></span></div><p style="text-align: left;">아래 네트워크 구성 정보를 토대로 적절히 설정 후, Connect 버튼을 눌러 보자.</p><p style="text-align: left;"><b><span style="color: #b45f06;"><네트워크 구성></span></b></p><p style="text-align: center;"><span style="font-family: Nunito;"><b style="background-color: #d9ead3;">Ubuntu PC(Wi-Fi) => ESP32 Router(AP | Station) => Access Point(192.168.7.1)</b></span></p><p style="text-align: center;"><span style="font-family: Nunito;"><b><br /></b></span></p><p style="text-align: left;"><span style="color: #b45f06; font-family: Nunito;"><b><Ubuntu PC></b></span></p><p style="text-align: left;"><span style="font-family: Nunito;">$ <b>ping 8.8.8.8</b></span></p><p style="text-align: left;"><span style="font-family: Nunito;">와우, ping이 된다. 인터넷에 접속해 보니, 조금 느리긴 해도 그럭저럭 동작한다.</span></p><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p><b style="color: #38761d; font-family: Nunito; font-size: large;">c) NAT 기능과 Wireguard 기능 통합하기</b></p><div><span style="font-family: Nunito;">NAT router 기능과 Wireguard code를 하나로 통합하면, Linux 처럼 동작할까 ? 당연히 그렇게 될 것 같진 않지만 한번 시도는 해 볼 만한 일이다.</span></div><div><span style="font-family: Nunito;"><TBD> </span><b style="font-family: Nunito;"><span style="background-color: #fcff01; color: #990000;">[ESP32 Course 과제 3]</span></b><span style="font-family: Nunito;"> 😛</span></div><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p><span style="font-size: x-large;"><span style="color: #3d85c6; font-family: Nunito;"><b>5. P</b></span><b style="color: #3d85c6; font-family: Nunito;">QC 알고리즘 Porting하기 - </b><b style="color: #3d85c6; font-family: Nunito;">CRYSTALS Kyber & Dilithium</b></span></p><div style="text-align: justify;"><span style="font-family: Nunito;"><span>이번 장에서는 ESP32에 맞게 PQC(Post Quantum Cryptography) 알고리즘을 porting하는 과정을 소개해 보고자 한다. PQC와 관련해서는 <a href="https://slowbootkernelhacks.blogspot.com/2023/01/orangepi-r1-plus-lts-pqc-wireguard-vpn.html">이전 blog post의 글(4장)</a>을 먼저 참조하기 바란다.</span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><span><div style="text-align: left;"><br /></div></span></span></div><div style="text-align: center;"><div style="text-align: left;"><span style="font-family: Nunito;">아직까지 ESP32에 PQC 알고리즘(특히 NIST 표준으로 정해진 CRYSTALS Kyber, Dilithium 등)을 porting한 내용이 인터넷 어디를 뒤져봐도 보이질 않는다. 다만, 한가지 ESP32에 Saber(NIST 3 round 탈락)알고리즘을 올려 놓은게 전부인 듯 하다. 이 내용과 관련해서는 아래 site를 참조하도록 하자.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;"><a href="https://eprint.iacr.org/2019/1453.pdf">https://eprint.iacr.org/2019/1453.pdf<br /></a><a href="https://github.com/SABERONESP32/SABERONESP32">https://github.com/SABERONESP32/SABERONESP32</a></span></div><div style="text-align: center;"><br /></div><p><span style="font-family: Nunito; font-size: medium;"><b style="color: #38761d;">a) Kyber768 코드를 </b></span><b style="color: #38761d; font-family: Nunito; font-size: large;">ESP32용으로 porting하기</b></p><div style="text-align: left;"><span style="font-family: Nunito;">우선은 PQClean code를 esp32에서 돌려 볼 수 있도록 해 보자.</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/PQClean/PQClean">https://github.com/PQClean/PQClean</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;"><b><Porting 절차></b><br /></span><span style="font-family: Nunito;">$ <b>mkdir kybkyber768-example</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>cd kyber768-example</b><br /></span><span style="font-family: Nunito;">$ <b>vi CMakeLists.txt</b></span></div><div style="text-align: left;"><span><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;"># The following lines of boilerplate have to be in your project's CMakeLists</span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;"># in this exact order for cmake to work correctly</span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;">cmake_minimum_required(VERSION 3.16)</span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;"><br /></span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;">include($ENV{IDF_PATH}/tools/cmake/project.cmake)</span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;">project(kyber768-example)</span></i></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;">~</span></i></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>mkdir main; cd main</b></div><div style="font-family: Nunito;">$ <b>ls -l</b></div><div style="font-family: Nunito;"><div><span style="font-size: x-small;">drwxrwxr-x 2 chyi chyi 4096 Feb 8 13:38 .</span></div><div><span style="font-size: x-small;">drwxrwxr-x 4 chyi chyi 4096 Feb 8 11:34 ..</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 280 Feb 8 13:37 <span style="color: #990000;">CMakeLists.txt //신규 생성</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 210 Feb 8 11:26 LICENSE</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 653 Feb 8 11:31 api.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 2699 Feb 8 11:31 cbd.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 336 Feb 8 11:31 cbd.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 29027 Feb 8 11:31 <span style="color: #990000;">fips202.c //PQClean common/ 에서 복사해 옴.</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 5567 Feb 8 11:31 <span style="color: #990000;">fips202.h </span><span style="color: #990000;">//PQClean common/ 에서 복사해 옴.</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 13065 Feb 8 11:31 indcpa.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 938 Feb 8 11:31 indcpa.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 4684 Feb 8 11:31 kem.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 733 Feb 8 11:31 kem.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 2537 Feb 8 11:31 kex.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1035 Feb 8 11:31 kex.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1487 Feb 8 13:38 <span style="color: #990000;">main.c //신규 생성, app_main() 함수 필요함</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 5515 Feb 8 11:31 ntt.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 388 Feb 8 11:31 ntt.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1060 Feb 8 11:31 params.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 11080 Feb 8 11:31 poly.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1542 Feb 8 11:31 poly.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 7061 Feb 8 11:31 polyvec.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 974 Feb 8 11:31 polyvec.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 2601 Feb 8 13:29 <span style="color: #990000;">randombytes.c </span><span style="color: #990000;">//esp32 random number 생성 코드를 넣어야 함.</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 362 Feb 8 11:44 <span style="color: #990000;">randombytes.h</span></span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1390 Feb 8 11:31 reduce.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 323 Feb 8 11:31 reduce.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1899 Feb 8 11:31 symmetric-shake.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1099 Feb 8 11:31 symmetric.h</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1563 Feb 8 11:31 verify.c</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 320 Feb 8 11:31 verify.h</span></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;">$ <b>vi CMakeLists.txt</b></div><div style="font-family: Nunito;"><div><i><span style="color: #b45f06; font-size: x-small;">idf_component_register(SRCS "main.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "cbd.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "fips202.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "indcpa.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "kem.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "ntt.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "poly.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "polyvec.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "reduce.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "symmetric-shake.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "verify.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "randombytes.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> "kex.c"</span></i></div><div><i><span style="color: #b45f06; font-size: x-small;"> INCLUDE_DIRS "./")</span></i></div></div><div style="font-family: Nunito;"><i><span style="color: #b45f06; font-size: x-small;">~</span></i></div><div style="font-family: Nunito;">$ cd ..</div><div style="font-family: Nunito;">$<b> idf.py menuconfig</b></div><div style="font-family: Nunito;">$ <b>idf.py build</b></div><div style="font-family: Nunito;">OK, 여기까지 정상적으로 build가 된다.</div><div style="font-family: Nunito;"><br /></div><div class="separator" style="clear: both; font-family: Nunito; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4rF9IPnanhUp0mWd43bzVUG_MRv6ZO1qIm1T_A-PoZrHce2gS4CwTUUIiWz9Id_PGw9lWuW-RXbnFACnI42N7hDngGryHsmKieQzgDHPWjoN_8OSv-zMRZ4cPzbRUeqPF9C4S9EbTkdH-73R34Pdth7kPWEJ-QNNnP6IDF13ldnLFaGU3zS_ufRmMA/s695/esp32_kyber768_build.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="673" data-original-width="695" height="388" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK4rF9IPnanhUp0mWd43bzVUG_MRv6ZO1qIm1T_A-PoZrHce2gS4CwTUUIiWz9Id_PGw9lWuW-RXbnFACnI42N7hDngGryHsmKieQzgDHPWjoN_8OSv-zMRZ4cPzbRUeqPF9C4S9EbTkdH-73R34Pdth7kPWEJ-QNNnP6IDF13ldnLFaGU3zS_ufRmMA/w400-h388/esp32_kyber768_build.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.1] kyber768-example.bin 파일 생성 모습</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">다음으로 할 일은 app_main() 함수 내에 kyber 키 생성 및 key 교환 관련 아래의 API 등을 호출하는 코드를 추가하는 일이다. </span></div><div><br /></div><div><div><span style="font-family: Nunito;">int <b>PQCLEAN_KYBER768_CLEAN_crypto_kem_keypair</b>(uint8_t *pk, uint8_t *sk);</span></div><div><span style="font-family: Nunito;">int <b>PQCLEAN_KYBER768_CLEAN_crypto_kem_enc</b>(uint8_t *ct, uint8_t *ss, const uint8_t *pk);</span></div><div><span style="font-family: Nunito;">int <b>PQCLEAN_KYBER768_CLEAN_crypto_kem_dec</b>(uint8_t *ss, const uint8_t *ct, const uint8_t *sk);</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">Hmm, 너무 많은 내용을 적으려다 보니 ... 좀 지친다. 😭 따라서 이 부분은 독자 여러분의 몫으로 남겨 두겠다.</span></div></div><div style="font-family: Nunito;"><br /></div><div style="font-family: Nunito;"><b style="color: #38761d; font-size: large;">b) Dilithium3 코드를 ESP32용으로 porting하기</b></div><div style="font-family: Nunito;">이번에는 Dilithium3 code를 porting해 보자. 방식은 kyber768과 별반 다르지 않다.</div><div style="font-family: Nunito;"><br /></div><div><div style="font-family: Nunito;">chyi@sun:~/workspace/ESP32/stable/<b>dilithium3-example</b>$ ls -la</div><div style="font-family: Nunito;">total 64</div><div style="font-family: Nunito;">drwxrwxr-x 4 chyi chyi 4096 Feb 8 14:52 .</div><div style="font-family: Nunito;">drwxrwxr-x 8 chyi chyi 4096 Feb 8 14:46 ..</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 243 Feb 8 14:47 <span style="color: #990000;">CMakeLists.txt //신규로 추가</span></div><div style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 Feb 8 14:56 main</div><div style="font-family: Nunito;">chyi@sun:~/workspace/ESP32/stable/dilithium3-example$ <b>cd main/</b></div><div style="font-family: Nunito;">chyi@sun:~/workspace/ESP32/stable/dilithium3-example/main$ ls -la</div><div style="font-family: Nunito;">total 168</div><div style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 Feb 8 14:56 .</div><div style="font-family: Nunito;">drwxrwxr-x 4 chyi chyi 4096 Feb 8 14:52 ..</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 235 Feb 8 14:56 <span style="color: #990000;">CMakeLists.txt //신규로 추가</span></div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 210 Feb 8 14:52 LICENSE</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 989 Feb 8 14:47 api.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 5567 Feb 8 14:54 <span style="color: #990000;">fips202.h // PQClean common 디렉토리에서 복사</span></div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1460 Feb 8 14:52 main.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 4893 Feb 8 14:47 ntt.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 236 Feb 8 14:47 ntt.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 8682 Feb 8 14:47 packing.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1696 Feb 8 14:47 packing.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 978 Feb 8 14:47 params.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 28621 Feb 8 14:47 poly.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 2197 Feb 8 14:47 poly.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 15024 Feb 8 14:47 polyvec.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 2710 Feb 8 14:47 polyvec.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1601 Feb 8 14:55 <span style="color: #990000;">randombytes.c //esp32용으로 구현</span></div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 362 Feb 8 14:55 <span style="color: #990000;">randombytes.h</span></div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1971 Feb 8 14:47 reduce.c</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 434 Feb 8 14:47 reduce.h</div><div style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 2785 Feb 8 14:47 rounding.c</div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 424 Feb 8 14:47 rounding.h</span></div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 12304 Feb 8 14:47 sign.c</span></div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 925 Feb 8 14:47 sign.h</span></div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 820 Feb 8 14:47 symmetric-shake.c</span></div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1254 Feb 8 14:47 symmetric.h</span></div><div><span style="font-family: Nunito;"><br /></span></div></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>cd dilithium3-example</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>idf.py build</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ cd build</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjixchF5Drakc-m9gJpBhoMG9uF7RcVHCC1Skxc6edYKZfWLyCWz_r3NYlNfdCRXCn_I_uHg8ikwG6pwwmL4unHuiVeM7Pfka9rj4IPHBhf4fNA0XfhSN44dgkPDG2HjP0hXVOE5t8aGqhnl35c1B3UcxF2JpeF1cdtGygVYj3vI1QdOZx_Bz4CfMQ5Lw/s668/esp32_dilithium3_build.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="668" data-original-width="656" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjixchF5Drakc-m9gJpBhoMG9uF7RcVHCC1Skxc6edYKZfWLyCWz_r3NYlNfdCRXCn_I_uHg8ikwG6pwwmL4unHuiVeM7Pfka9rj4IPHBhf4fNA0XfhSN44dgkPDG2HjP0hXVOE5t8aGqhnl35c1B3UcxF2JpeF1cdtGygVYj3vI1QdOZx_Bz4CfMQ5Lw/w393-h400/esp32_dilithium3_build.png" width="393" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.2] dilithium3-example.bin 파일 생성 모습</span></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><span style="font-family: Nunito;">다음으로 할 일은 app_main() 함수 내에 digital 서명 키 생성 및 검증에 관한 아래의 API 등을 호출하는 코드를 추가하는 일이다. </span></div><div><br /></div><div><span style="font-family: Nunito;"><div>int <b>PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_keypair</b>(uint8_t *pk, uint8_t *sk); <span style="color: #990000;">//서명용 키 생성</span></div><div><br /></div><div><div>int <b>PQCLEAN_DILITHIUM3_CLEAN_crypto_sign</b>( <span style="color: #cc0000;"> </span><span style="color: #990000;">//서명 함수</span></div><div> uint8_t *sm, size_t *smlen,</div><div> const uint8_t *m, size_t mlen, const uint8_t *sk);</div></div><div><br /></div><div>int <b>PQCLEAN_DILITHIUM3_CLEAN_crypto_sign_open</b>( <span style="color: #990000;">//verify 함수</span></div><div> uint8_t *m, size_t *mlen,</div><div> const uint8_t *sm, size_t smlen, const uint8_t *pk);</div></span></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;"><b style="color: #38761d; font-size: large;">c) ESP32 dual core를 활용하도록 Kyber & Dilithium 알고리즘 최적화 하기</b></span></div><p><span style="font-family: Nunito;">지금까지 설명한 porting 방식은 esp32의 특징(dual core 등)을 전혀 살린 것이 아니다. 그저 단순히 PQClean code를 cross-compile한 것에 불가하다. 그렇다면 (앞선 Saber의 예에서 처럼) esp32의 h/w적인 특징을 살려 보다 향상된 code를 만들기 위해서는 어떻게 해야 할까 ?</span></p><p><span style="font-family: Nunito;"><TBD - 난이도 최상> </span><b style="font-family: Nunito;"><span style="background-color: #fcff01; color: #990000;">[ESP32 Course 과제 4]</span></b><span style="font-family: Nunito;"> 😛</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">__________________________________________________________________</span></p><p><span style="font-family: Nunito;">이상으로 ESP32 board에 i2c & spi device(ADXL345)를 하나 붙이고, wireguard vpn tunnel을 통해 sensor data를 서버로 올리는 과정을 정리해 보았다. 언제나 그렇듯 부족한 부분은 (기약은 없지만) 다음 글을 통해서 보충해 나가도록 하겠다.<b> "May the Source be with You" </b>😋</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><b style="color: #3d85c6; font-family: Nunito; font-size: xx-large;">6. References</b></p><div style="text-align: left;"><span style="font-family: Nunito;"><span>[1] https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span>[2] https://www.es.co.th/Schemetic/PDF/ESP32.PDF</span><span style="background-color: white; color: #24292f; font-size: 16px;"> </span></span></div><div style="text-align: left;"><span style="font-family: Nunito;">[3] <a href="http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf" rel="nofollow" style="background-color: white; box-sizing: border-box; font-size: 16px; text-decoration-line: none;">http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;">[4] https://github.com/hepingood/adxl345/blob/master/README_ko.md</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[5] https://learn.sparkfun.com/tutorials/adxl345-hookup-guide/all</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[6] https://www.mischianti.org/2022/08/13/gy-291-adxl345-i2c-spi-accelerometer-with-interrupt-for-esp32-esp8266-stm32-and-arduino/<a href="http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf" rel="nofollow" style="background-color: white; box-sizing: border-box; text-decoration-line: none;"><span style="color: black;"><br /></span></a>[7] And Google~</span><span style="font-family: Nunito;"><br /></span></div><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p style="text-align: right;"><span style="color: #3d85c6; font-family: Nunito; font-size: large;"><b>Slowboot</b></span></p><p><br /></p>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-75387307687488239932023-01-28T16:46:00.001+09:002023-01-30T09:37:45.975+09:00OrangePi R1 Plus LTS 보드로 PQC WireGuard VPN Router 만들기<p><span style="font-family: Nunito;"><b><span style="font-size: x-large;">오</span></b><span>랜만(거의 2년만)에 blog에 글을 다시 올리는 것 같다.😎 이번 시간에는 </span><a href="http://www.orangepi.org/">OrangePi R1 Plus LTS board</a><span>를 이용하여 </span><a href="https://csrc.nist.gov/News/2022/pqc-candidates-to-be-standardized-and-round-4">PQC(Post-Quantum Cryptography)</a><span> 기반 초소형 VPN(</span><a href="https://www.wireguard.com/">WireGuard</a><span>) router를 만드는 과정을 소개해 보고자 한다.</span></span></p><p><span style="font-family: Nunito;"><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtpzUumNIFqkOB30tRtEJY6lS89ho5yyOYJsqKfvMK6yjbXotLRJodCJSowJUT5GgKaOcVDEAB6a8k1_q74eNy_VO_yRgZPtTNjEsfbx72EtLnZNFuAC_u7cGP_96P30GZJUaPBFWbO5f1a7EEieKUzN7_3rtww-PJ3Ma3l2ML-hEqOgJuIDNlWOPy5Q/s489/orange-pi_r1_plus_white.PNG" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="413" data-original-width="489" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtpzUumNIFqkOB30tRtEJY6lS89ho5yyOYJsqKfvMK6yjbXotLRJodCJSowJUT5GgKaOcVDEAB6a8k1_q74eNy_VO_yRgZPtTNjEsfbx72EtLnZNFuAC_u7cGP_96P30GZJUaPBFWbO5f1a7EEieKUzN7_3rtww-PJ3Ma3l2ML-hEqOgJuIDNlWOPy5Q/s320/orange-pi_r1_plus_white.PNG" width="320" /></span></a></div><span style="font-family: Nunito;"><div><span style="font-family: Nunito;"><br /></span></div><div><p style="font-family: "Noto Sans CJK KR"; text-align: center;"><span style="color: #660000; font-family: Nunito;"><b>PQC(양자내성 암호 알고리즘)이 탑재된 초소형 VPN Router(Tiny VPN Router)를 만들어 보면 어떨까 ?</b></span></p></div><div><span style="font-family: Nunito;"><br /></span></div><br /></span><div style="text-align: left;"><span style="font-family: Nunito;"><span><i><b><span>목차</span></b><br /></i></span><span><span><i>1. OrangePi R1 Plus LTS board 소개<br /></i></span><i>2. OpenWrt build 하기<br /></i><span><i>3. i2c device tree 및 device driver 추가하기</i></span></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><i>4. PQC(Post Quantum Cryptography) 개요</i></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><i>5. PQC 기반 WireGuard VPN Router 만들기</i></span><span><i><br /></i></span><span><i>6. References</i></span></span></div><p><span style="font-family: Nunito;"><span style="color: #b45f06;">Keyword: Orange Pi R1 Plus LTS, i2c, PQC(Kyber, Dilithium), WireGuard</span></span></p><p><span><br /></span></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>1. OrangePi R1 Plus LTS board 소개</b></span></p><p><span style="font-family: Nunito;">일전에 camera가 장착된 Orange Pi(모델명은 정확히 기억이 안남)를 하나 테스트했던 적이 있는데, 열도 많이 나고 camera 동작도 형편없었던 안좋은 기억이 난다. 2개의 LAN port를 장착한 보드를 찾던 중, <a href="https://www.friendlyelec.com/index.php?route=product/product&product_id=284">NanoPi R4S</a>와 더불어 <a href="http://www.orangepi.org/">Orange Pi</a>를 다시 살펴 보게 되었는데, 과연 이번에는 만족할만한 결과를 얻을 수 있을지 기대해 보도록 하자. 💢</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">본 blog에서 소개하는 Orange Pi 관련 내용은 아래 wiki page와 user manual을 기초로 하였다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="http://www.orangepi.org/orangepiwiki/index.php/Orange_Pi_R1_Plus_LTS">http://www.orangepi.org/orangepiwiki/index.php/Orange_Pi_R1_Plus_LTS</a></span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://drive.google.com/drive/folders/1VLsrHLXRNGINbXcuxSsCtvX1430Pjmmt/OrangePi_R1_Plus_LTS_RK3328_User_Manual_v2.0.pdf">https://drive.google.com/drive/folders/1VLsrHLXRNGINbXcuxSsCtvX1430Pjmmt/OrangePi_R1_Plus_LTS_RK3328_User_Manual_v2.0.pdf</a></span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbBTNitNhBczEcmO482Lrir32xLbTYU3WIWBVWRs51YjfqMK9rPJ_EX6fMwo--lowu8okTPMRlmzlFbHNCthFdzuv9mjAmeoW0rO81iD2_euKXHWnqX6KpIBTg89LupF--Amu6-IMyKBb8tzuYEXUazA9lXw1ascgCsPHC5eUk04SZBTZRUBYyjPesew/s1813/Orange-pi-r1-plus-lts-img3.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="1813" data-original-width="1190" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbBTNitNhBczEcmO482Lrir32xLbTYU3WIWBVWRs51YjfqMK9rPJ_EX6fMwo--lowu8okTPMRlmzlFbHNCthFdzuv9mjAmeoW0rO81iD2_euKXHWnqX6KpIBTg89LupF--Amu6-IMyKBb8tzuYEXUazA9lXw1ascgCsPHC5eUk04SZBTZRUBYyjPesew/w420-h640/Orange-pi-r1-plus-lts-img3.png" width="420" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.1] OrangePi R1 Plus LTS 보드</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwhq2srb8WiYS5s0fxUqlYxcUiKJQkWLX0JnJuJmUb2wBqgkgiKwpeedvX6bGiOIbI91DgNvznPH0YAzgHQ2G_r2jgShvgtTl0X0NxP9E7NsaEyyZROh4jWGFDkpRZfnjQoPrEhxLIzsxFljqgzj-S2TOqVE4Unk2UxhFwBKYL7LgmnMhtgXK39JOw4w/s1643/Rectangle%20742.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="1643" data-original-width="1200" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwhq2srb8WiYS5s0fxUqlYxcUiKJQkWLX0JnJuJmUb2wBqgkgiKwpeedvX6bGiOIbI91DgNvznPH0YAzgHQ2G_r2jgShvgtTl0X0NxP9E7NsaEyyZROh4jWGFDkpRZfnjQoPrEhxLIzsxFljqgzj-S2TOqVE4Unk2UxhFwBKYL7LgmnMhtgXK39JOw4w/w293-h400/Rectangle%20742.png" width="293" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.2] OrangePi R1 Plus LTS 보드 Case</span></div><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9e9oveM8sOuDqNTCQwPODNHjNOwfVtN0PnnLvuy1c7wbYH3chuHTqZ6SFtLYWNZVAC1OJ1yVT-oWprHnZIWg9jmjvYZ0cHLB7vzBZMlYEhmkk3BEoSaClVz9SE4Qk3P6g9qxggOfqcXcckDnT9f-j70k8FqWtRtOrp9-232SC-c_Jx1B8NXScC9mHTQ/s960/Orange-pi-r1-plus-lts-img4.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="610" data-original-width="960" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9e9oveM8sOuDqNTCQwPODNHjNOwfVtN0PnnLvuy1c7wbYH3chuHTqZ6SFtLYWNZVAC1OJ1yVT-oWprHnZIWg9jmjvYZ0cHLB7vzBZMlYEhmkk3BEoSaClVz9SE4Qk3P6g9qxggOfqcXcckDnT9f-j70k8FqWtRtOrp9-232SC-c_Jx1B8NXScC9mHTQ/w640-h406/Orange-pi-r1-plus-lts-img4.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.3] OrangePi R1 Plus LTS 보드 확장 pinmap</span></div><span style="font-family: Nunito;"><br /></span><p></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>2. OpenWrt build 하기</b></span></p><p><span style="font-family: Nunito;">개발 board가 준비되면, 제일 먼저 해보게 되는 일은 역시 kernel을 build한 후 이를 target board에 올려 보는 일일 것이다. 정확히는 bootloader/kernel/rootfs 등을 build해서 올리는 일이 될 것인데, linux 배포판 중, router 용 board(or wifi access point)에 최적화되어 있는 것은 단연 openwrt가 최고라고 말할 수 있다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><b><span style="color: #38761d; font-family: Nunito; font-size: large;">a) openwrt build하기</span></b></p><p><span>각설하고 Orange Pi L1 Plus LTS용 openwrt source code를 내려 받아 build하는 절차를 적어보면 다음과 같다.</span></p><p><span style="font-family: Nunito;"><span>$ </span><b>git clone https://github.com/orangepi-xunlong/openwrt.git -b openwrt-21.02</b></span></p><p><span style="font-family: Nunito;">$ <b>cd openwrt</b></span></p><p><span style="font-family: Nunito;">$ <b>./scripts/feeds update -a</b></span></p><p><span style="font-family: Nunito;">$ <b>./scripts/feeds install -a</b></span></p><p><span style="font-family: Nunito;"><span>$ </span><b>cp configs/OrangePi_R1_Plus_LTS_defconfig .config</b></span></p><p><span style="font-family: Nunito;">$ <b>make defconfig</b></span></p><p><span style="font-family: Nunito;">$ <b>make V=s</b></span></p><p><span style="font-family: Nunito;">$ <b>cd <span face=""맑은 고딕"">openwrt/bin/targets/rockchip/armv8</span></b></span></p><p><span style="font-family: Nunito;"><b><span face=""맑은 고딕""><br /></span></b></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb-bAD-uN9JNC1DfwJARvwhKdPXKlOexNYsqCmKNQ1eyclb02gb7dtTt-iJc4KPfxEFfY460ItQz9B_x9u-0aFAgQiEerc0r96rdOMhg581i4lDmI8e3170k6kLuhiLQihw62s9ybw9HfU9uvR7PLs2UCJxPwITxBKuk9fm7sOLlgSUX9eu7TwD4DkNQ/s974/orangepi_openwrt_build_bin.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="254" data-original-width="974" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb-bAD-uN9JNC1DfwJARvwhKdPXKlOexNYsqCmKNQ1eyclb02gb7dtTt-iJc4KPfxEFfY460ItQz9B_x9u-0aFAgQiEerc0r96rdOMhg581i4lDmI8e3170k6kLuhiLQihw62s9ybw9HfU9uvR7PLs2UCJxPwITxBKuk9fm7sOLlgSUX9eu7TwD4DkNQ/w640-h166/orangepi_openwrt_build_bin.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.1] build 결과 - openwrt 설치용 image 파일 생성 모습</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">참고: 위의 내용은 Ubuntu 18.04 or 20.04를 기준으로 정리한 것이다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></div><span style="font-family: Nunito;"><b><span style="color: #38761d; font-size: large;">b) target board 부팅하기</span></b><br /></span><p></p><p style="line-height: 150%; margin: 0cm;"><span lang="EN-US" style="font-family: Nunito; line-height: 150%;">적당한 크기의 microSD card를 준비하고, 아래 명령을 이용하여 앞서 build한 image 파일에 대한 writing을 시도하도록 한다.</span></p><p style="line-height: 150%; margin: 0cm;"><span lang="EN-US" style="font-family: Nunito; line-height: 150%;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span lang="EN-US" style="font-family: Nunito; line-height: 150%;">$ <b>sudo dd if=./openwrt-rockchip-armv8-xunlong_orangepi-r1-plus-lts-ext4-sysupgrade.img of=/dev/sdb bs=1M</b><br />
664+0 records in<br />
664+0 records out<br />
696254464 bytes (696 MB, 664 MiB) copied, 159.026 s, 4.4 MB/s<span><o:p></o:p></span></span></p><p><span style="color: #b45f06; font-family: Nunito;">주의: of=/dev/sdb는 독자의 실제 환경에 맞게 지정해 주어야 한다.</span></p><p><span style="color: #b45f06; font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">이후 microSD를 target board에 장착하고 부팅을 시도해본다.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNUlYpDd00rNpovEW36XyHP9Me4z9bkjtRNaXR0NVBEyu2PTxljVZmwK8tC2wl-4CPeGOgz7gbHGXsBbKIS-1KkftVUIMj9Ziat0NzblTWYWndDdpfdEsSBajdhtRx4BDWDHcNO8_leKf0h7TXifbCBK53A7_vf9WWZOMdIncoFwJwOnFvQ-amXEl5Uw/s4000/20230113_161853.jpg" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="3000" data-original-width="4000" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNUlYpDd00rNpovEW36XyHP9Me4z9bkjtRNaXR0NVBEyu2PTxljVZmwK8tC2wl-4CPeGOgz7gbHGXsBbKIS-1KkftVUIMj9Ziat0NzblTWYWndDdpfdEsSBajdhtRx4BDWDHcNO8_leKf0h7TXifbCBK53A7_vf9WWZOMdIncoFwJwOnFvQ-amXEl5Uw/s320/20230113_161853.jpg" width="320" /></span></a></div><p></p><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 2.2] Orange Pi R1 LTS board 부팅 모습(1)</span></span></div><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">$ <b>sudo minicom -b 1500000 -D /dev/ttyUSB0</b></span></p><p><span style="color: #b45f06; font-family: Nunito;">참고) 요즘 나오는 board의 serial port baudrate은 1.5Mbps(= 1500000)을 기본으로 한다. 캬~ 빠르다 빨러~ 🏂</span></p><p><span style="font-family: Nunito;"><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9TobnGcQnQGxZ5Xa2pOi7E_0gl5uGoQCN3Ji_-BtSDu5uQr_PBkra9XQMxQqkHk0u2xCRxs9o_669_tt5rU11-_zDlx9fEMCsavNwvLaiYOjNcVNXDgd0ebaenSas24tGz_fnx4MQiZv-yI3Lxhj1hUGhaQFBCt5h3qQ9UQaYLeh0jB4yl7hocVF8w/s1269/orange_pi_kernel_booting.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="727" data-original-width="1269" height="366" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ9TobnGcQnQGxZ5Xa2pOi7E_0gl5uGoQCN3Ji_-BtSDu5uQr_PBkra9XQMxQqkHk0u2xCRxs9o_669_tt5rU11-_zDlx9fEMCsavNwvLaiYOjNcVNXDgd0ebaenSas24tGz_fnx4MQiZv-yI3Lxhj1hUGhaQFBCt5h3qQ9UQaYLeh0jB4yl7hocVF8w/w640-h366/orange_pi_kernel_booting.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.3] Orange Pi R1 LTS board 부팅 모습(2)</span></div><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">Target board용 image를 생성하고, image를 target board에 올리는 방법과 관련해서는 이미 다른 blog posting을 통해 아주 여러차례 소개한 바 있으므로, 여기서는 이 정도 선에서 마무리하고 다음으로 넘어가기로 한다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2017/01/sbcsmall-board-computer-embedded-linux.html">https://slowbootkernelhacks.blogspot.com/2017/01/sbcsmall-board-computer-embedded-linux.html</a></span></p><div class="separator" style="clear: both; text-align: center;"><span><br /></span></div><p></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>3. i2c device tree 및 device driver 추가하기</b></span></p><div style="text-align: left;"><span style="font-family: Nunito;"><span>이 장에서는 </span><span>OrangePi board에</span><span> i2c 주변장치를 하나 연결하고, 이를 인식시키는 과정(device tree & device driver)을 소개해 보고자 한다.<br /></span></span><span style="font-family: Nunito;">i2c 장치로는 이전 posting에서 한 차례 사용했던, 온습도 센서인 HTU21D를 다시 활용해 보기로 하겠다.</span></div><p style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html"><span style="font-family: Nunito;">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html</span></a></p><div><span><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibjuuW6uCElyGVLbuhyGqDoXEzjabeE56CUzmpQ3Z_XhULkKatId3Thcijxw-SVv2FHFzkTE4nln-YjWe02b7jA05aIdbtl20JAOMxqrCrsp2qTvFOckvxVOJWkspgSgq2m6Z21sVfs5D9-YZn2V9FgZVdLe8nl0TYyGnzORRtHHmoWhrgQjepPP162A/s184/htu21d_2.jpeg" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="173" data-original-width="184" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibjuuW6uCElyGVLbuhyGqDoXEzjabeE56CUzmpQ3Z_XhULkKatId3Thcijxw-SVv2FHFzkTE4nln-YjWe02b7jA05aIdbtl20JAOMxqrCrsp2qTvFOckvxVOJWkspgSgq2m6Z21sVfs5D9-YZn2V9FgZVdLe8nl0TYyGnzORRtHHmoWhrgQjepPP162A/s1600/htu21d_2.jpeg" width="184" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 3.1] HTU21D 온습도 센서</span></span></div><div><span><br /></span></div><div><span style="color: #b45f06;">참고: 일단 가지고 있는 sensor를 활용하다 보니, HTU21D 센서를 다시 사용하게 되었는데, 조만간 다른 센서로 교체해 보도록 하자.</span></div><div><span><br /></span></div><p><b><span style="color: #38761d; font-family: Nunito; font-size: large;">a) rk3328 orangepi r1 plus lts device tee 분석</span></b></p><p><span style="font-family: Nunito;"><span>먼저, 언제나 그렇듯 target board의 device tree 관계를 파악해 보는 것이 첫번째로 해야 할 일이다.</span></span></p><p><span style="font-family: Nunito;"><span><br /></span></span></p><div style="text-align: center;"><span><span style="font-family: Nunito;"><b>rk3328.dtsi <br /></b></span><span style="font-family: Nunito;"><b>^<br /></b></span><span style="font-family: Nunito;"><b>|<br /></b></span><span style="font-family: Nunito;"><b>rk3328-nanopi-r2s.dts</b></span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><b>^</b></span></div><div style="text-align: center;"><span><span style="font-family: Nunito;"><b>|<br /></b></span><span style="font-family: Nunito;"><b>rk3328-orangepi-r1-plus.dts</b></span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><b>^</b></span></div><div style="text-align: center;"><span><span style="font-family: Nunito;"><b>|<br /></b></span><span face=""맑은 고딕""><b><span style="color: #ffa400; font-family: Nunito;">rk3328-orangepi-r1-plus-lts.dts </span></b></span></span></div><div style="text-align: center;"><span face=""맑은 고딕""><b><span style="color: #ffa400; font-family: Nunito;"><br /></span></b></span></div><div style="text-align: center;"><span face=""맑은 고딕""><span style="font-family: Nunito;">[그림 3.2] Orange Pi R1 Plus LTS board device tree 관계도</span></span></div><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_IQcBbtjAqn_RXXwWoo1S6ZpzSQvBQeZ2Njh2hKhUj6UxIcvc9R-aM5BUkacIjKanD1JWWH15d7MySrxGJJ780rd3fAM2gpf-YRxcoPAaA0d6rAzFu5kNyW78-JWlaLTzsFOS2zcebUosKJL2ZIPXyBraX8gai2s2DrF-OrLIJmMcpzp8K09IoPckEQ/s781/rk3328_dtsi.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="781" data-original-width="629" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_IQcBbtjAqn_RXXwWoo1S6ZpzSQvBQeZ2Njh2hKhUj6UxIcvc9R-aM5BUkacIjKanD1JWWH15d7MySrxGJJ780rd3fAM2gpf-YRxcoPAaA0d6rAzFu5kNyW78-JWlaLTzsFOS2zcebUosKJL2ZIPXyBraX8gai2s2DrF-OrLIJmMcpzp8K09IoPckEQ/w323-h400/rk3328_dtsi.png" width="323" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.3] rk3328.dtsi</span></div><span style="font-family: Nunito;"><br /></span><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwOm4JjyfrjgpQs0fm2DbORjFxSA_-MxtELGn95QrM92e7VIG9tDbJ7RVmh_DJMnMuIoZSZNQputDKk312xLd6bcMG0N3KYY5TK0s97Ovk7fC_-gnNT6DhaoP1GzpRf3l5lgH9BZignKKqDu1laRsokIeMLfIyzLA-iekX_v8F1PAPNeYR8rB6q8h0bQ/s629/rk3328_dtsi_i2c.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="432" data-original-width="629" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwOm4JjyfrjgpQs0fm2DbORjFxSA_-MxtELGn95QrM92e7VIG9tDbJ7RVmh_DJMnMuIoZSZNQputDKk312xLd6bcMG0N3KYY5TK0s97Ovk7fC_-gnNT6DhaoP1GzpRf3l5lgH9BZignKKqDu1laRsokIeMLfIyzLA-iekX_v8F1PAPNeYR8rB6q8h0bQ/s320/rk3328_dtsi_i2c.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] rk3328.dtsi - i2c controller 중심</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCjYORYJ32AiS8oECnSznf2M2QV4AINdqnPAUbTM6HYYqiKqW9RC5oMg7RizYnJwbztQTkY_cvTrGO9Hh_IfVxMFmWpuVdwBysGZ0TZ92NEkCwQaxtgGmxoLe5b6e-Cev4NdDmr6vBlbredoJ45DITsbmXw-U7MCz9lNknqJUWZXMbzSwoSACeW6EYyQ/s778/rk3328_orange_pi_r1_plus_lts_device_tree.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="759" data-original-width="778" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCjYORYJ32AiS8oECnSznf2M2QV4AINdqnPAUbTM6HYYqiKqW9RC5oMg7RizYnJwbztQTkY_cvTrGO9Hh_IfVxMFmWpuVdwBysGZ0TZ92NEkCwQaxtgGmxoLe5b6e-Cev4NdDmr6vBlbredoJ45DITsbmXw-U7MCz9lNknqJUWZXMbzSwoSACeW6EYyQ/s320/rk3328_orange_pi_r1_plus_lts_device_tree.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] OrangePi R1 Plus LTS device tree</span></div><p></p><p><span style="color: #b45f06;"><span style="font-family: Nunito; text-align: center;">참고: device tree를 이해하기 위해서는 많은 부분이 참고가 되어야 한다. 특히 </span><span style="font-family: Nunito; text-align: center;"> </span><span style="font-family: Nunito; text-align: center;">rk3328.dtsi 파일의 include 문에 명기된 파일을 면밀히 살펴 볼 필요가 있다.</span></span></p><p><span style="font-family: Nunito; text-align: center;"><span><br /></span></span></p><p style="text-align: left;"><b><span style="color: #38761d; font-family: Nunito; font-size: large;">b) i2c device를 위한 device tree 내용 수정하기</span></b></p><p style="text-align: left;"><span style="font-family: Nunito;"><span>다음으로 해야 할 일은 Orange Pi 확장 핀 중에서 i2c pin이 어느 것인지를 확인하는 것이다. 눈치챘겠지만, 아래 그림의 3, 4번 pin 즉 TWI0-SDA, TWI-SCK가 i2c용 pin임을 쉽게 알 수 있다. 물론, VCC_SYS(3.3V)와 GND도 함께 사용되어야 한다.</span></span></p><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkswil1cYDX84-fCBBUnOgpPS6ugagFI7xh_yexleFuq7sgPl4TwIYNj_a9MSBNNRLpW87jTh0qVasdQvbEG9QcHIqvWqEZBvhxcG3-OyDZI3uXHxPandsTvAZz5s09NEjq9dqz_T91vEUXWjX9w76nf-nIpCOerIkZwW0gxwN9Kppdx0dkQN-bRjcVQ/s450/Orange-pi-r1-plus-lts-img8.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="376" data-original-width="450" height="334" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkswil1cYDX84-fCBBUnOgpPS6ugagFI7xh_yexleFuq7sgPl4TwIYNj_a9MSBNNRLpW87jTh0qVasdQvbEG9QcHIqvWqEZBvhxcG3-OyDZI3uXHxPandsTvAZz5s09NEjq9dqz_T91vEUXWjX9w76nf-nIpCOerIkZwW0gxwN9Kppdx0dkQN-bRjcVQ/w400-h334/Orange-pi-r1-plus-lts-img8.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] OrangePi R1 Plus LTS 확장 pin</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">Orange Pi도 i2c pin을 그냥 단독으로 사용하게 내버려 두지는 않는다. 즉, GPIO 등 다른 용도로 사용 가능하도록 pinmux되어 있는데, 이와 관련한 정확한 내용을 파악하게 위해서는 <a href="https://rockchip.fr/RK3328%20datasheet%20V1.2.pdf">rk3328 datasheet</a>를 반드시 읽어 보아야만 한다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimo4AqY1kW1JMuOdjBWlsEVQGLhrpfbF8LWkYAhKWBNL2gRBLZp97U6nCGfz26j0XZWGiiGjwl_OXgteSzrp5588P5hwR8oVbGnztZ0KAMfdX5Y0prHkfo6YRrPhUh5Nj9t3f_CU5vThG2m1jQTZDIx4tjl0lZK_Ye8AFBS38RQ9JWz_o3ROezvjDFdw/s1499/rk3328_datasheet_pinmux_table.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="880" data-original-width="1499" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimo4AqY1kW1JMuOdjBWlsEVQGLhrpfbF8LWkYAhKWBNL2gRBLZp97U6nCGfz26j0XZWGiiGjwl_OXgteSzrp5588P5hwR8oVbGnztZ0KAMfdX5Y0prHkfo6YRrPhUh5Nj9t3f_CU5vThG2m1jQTZDIx4tjl0lZK_Ye8AFBS38RQ9JWz_o3ROezvjDFdw/w400-h235/rk3328_datasheet_pinmux_table.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.7] rk3328 pinmux table</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6ybz0sJ6RkvZMb7kEu3wjzIXPu_PH6p4lxVvqWd9CT3MmIMneEkPo09PXNbZS90tI-PVjx67PdPo4YSEj1DsVw0yk0SJq2OBmWpb3ILzBUSE6R1Lyrv4xrPIBScwtsiqCaaKDAEm1Q0bmzQXIMtQ2NGgz7SrWECyn9z5CDph2eWHMkPRVLR7wr3BhuQ/s1501/rk3328_i2c_pinmux.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="61" data-original-width="1501" height="26" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6ybz0sJ6RkvZMb7kEu3wjzIXPu_PH6p4lxVvqWd9CT3MmIMneEkPo09PXNbZS90tI-PVjx67PdPo4YSEj1DsVw0yk0SJq2OBmWpb3ILzBUSE6R1Lyrv4xrPIBScwtsiqCaaKDAEm1Q0bmzQXIMtQ2NGgz7SrWECyn9z5CDph2eWHMkPRVLR7wr3BhuQ/w640-h26/rk3328_i2c_pinmux.png" width="640" /></span></a></div><span style="font-family: Nunito;"><br /></span><div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.8] rk3328 pinmux table 중 i2c0 관련 내용</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5AntrpNbg0hOFvvmV530G4dDUhMRFwtkE9Vo7xIagnZmm49yAp0qDAe5MUXEYtmCdgAhuZ0A2w8cN8wZvDC7JrOuB8Hrgx_mT1mVtkm3BwIECximm7Qj75PW3jAZ2dFDfPqIegnQPJBxknWF6LuVygju8o7J1_s73zA1N2sVC0NKjYvhchD_PcT60Zg/s4000/20230121_151341.jpg" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="3000" data-original-width="4000" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5AntrpNbg0hOFvvmV530G4dDUhMRFwtkE9Vo7xIagnZmm49yAp0qDAe5MUXEYtmCdgAhuZ0A2w8cN8wZvDC7JrOuB8Hrgx_mT1mVtkm3BwIECximm7Qj75PW3jAZ2dFDfPqIegnQPJBxknWF6LuVygju8o7J1_s73zA1N2sVC0NKjYvhchD_PcT60Zg/s320/20230121_151341.jpg" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 3.9] Orange Pi 확장 핀에 htu21d 센서 연결 모습</span></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;">자, 이제 device tree 및 pinmux에 관한 어느 정도의 내용 파악이 끝났으니, device tree에 i2c0 device를 하나 추가해 보도록 하자.</span><div><span style="font-family: Nunito;"><br /></span><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWqp4E-2hxqIyiTACfj_ELnmNpVi2BAprDzdxRMmyrtIYsSBRnKLkrfarbQNar_ps5gA78n9Qu0N8YQQs5Y8iPE7vDVX7ADwGvea1C0_O-6o6luDy1-Eexi6BpZsik2FuNg1COk230CEgGiU9q3DhVTl52QHuHOjiSK37CFcPmmWU0VlcxAV4AG-O5jg/s573/orange_pi_r1_plus_lts_i2c0_device.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="350" data-original-width="573" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWqp4E-2hxqIyiTACfj_ELnmNpVi2BAprDzdxRMmyrtIYsSBRnKLkrfarbQNar_ps5gA78n9Qu0N8YQQs5Y8iPE7vDVX7ADwGvea1C0_O-6o6luDy1-Eexi6BpZsik2FuNg1COk230CEgGiU9q3DhVTl52QHuHOjiSK37CFcPmmWU0VlcxAV4AG-O5jg/w400-h244/orange_pi_r1_plus_lts_i2c0_device.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.10] OrangePi R1 Plus LTS용 i2c device 추가</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;"><b><span style="color: #38761d; font-size: large;">c) 새로운 device tree blob 만들기</span></b><br /></span><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">Device tree 내용을 수정하였으니, 이를 build하여 target board에 반영해 보도록 하자.</span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">$ <b>cd <span face=""맑은 고딕"">openwrt/build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/l</span><span face=""맑은 고딕"">inux-5.4.179</span></b></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span lang="EN-US" style="font-family: Nunito; line-height: 150%;">$ <b>export STAGING_DIR=YOUR_PATH/openwrt/staging_dir</b><br />$ <b>export TOOLCHAIN_DIR=$STAGING_DIR/toolchain-aarch64_generic_gcc-8.4.0_musl</b><br />$ <b>export LDCFLAGS=$TOOLCHAIN_DIR/usr/lib</b><br />$ <b>export LD_LIBRARY_PATH=$TOOLCHAIN_DIR/usr/lib</b><br />$ <b>export PATH=$TOOLCHAIN_DIR/bin:$PATH</b><br />$ <b>export ARCH=arm64</b><br />$ <b>export CROSS_COMPILE=aarch64-openwrt-linux-musl-</b><br />
<br />$ <b>make dtbs</b><span><o:p></o:p></span></span></p><p style="line-height: 150%; margin: 0cm;"><span><span style="font-family: Nunito;">build가 제대로 진행되고 나면 아래 위치(arch/arm64/boot/dts/rockchip)</span><span style="font-family: Nunito;">에 dtb 파일이 만들어지게 된다.</span></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgEIWwbBc__xTSLV8GSpQQQeDUSYmYfVOgiq0qmjkp8t1OJXJwAwS1WIqdyx3U7JRl6Os7ACNhzFjhk2T8ccx7GL2MbpPt3VBo6TLCZ-mMTvFsGGuB8SP03aAc3NIKPDff1KQ2zaHTpfozcRkcOERm8MYyrrz4xXGK3pu7WPOT7KSFR3mgjZoJvQ3wJA/s975/rockchip_dtb.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="698" data-original-width="975" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgEIWwbBc__xTSLV8GSpQQQeDUSYmYfVOgiq0qmjkp8t1OJXJwAwS1WIqdyx3U7JRl6Os7ACNhzFjhk2T8ccx7GL2MbpPt3VBo6TLCZ-mMTvFsGGuB8SP03aAc3NIKPDff1KQ2zaHTpfozcRkcOERm8MYyrrz4xXGK3pu7WPOT7KSFR3mgjZoJvQ3wJA/w400-h286/rockchip_dtb.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.11] rockchip용 device tree blob</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span><span style="font-family: Nunito;">이 중 우리에게 필요한 파일은 아래 파일이다. </span><span style="font-family: Nunito;">이 파일을 microSD에 복사하도록 하자.</span></span></div><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #a64d79; font-family: Nunito;">rk3328-orangepi-r1-plus-lts.dtb</span></b></div><p style="line-height: 150%; margin: 0cm;"><span><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="color: #b45f06;">참고: MicroSD card를 Ubuntu PC에 꽂고, mount된 디렉토리를 확인한 후, 위의 파일을 기존 dtb 파일명(rockchip.dtb)으로 복사한다.</span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">Target board를 재 부팅 후, console login하여 아래 디렉토리로 이동하도록 한다.</span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">$ <b>cd /sys/bus/i2c/devices</b></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">이 디렉토리 아래에 보면 (기존에는 없었던) i2c-0가 생성된 것을 확인할 수 있다.</span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgriqacZSB5fslx6THIopndfKXBMFmnetvt3hR2bGabRdD-Be8GyNG8oJug8pUk7HohhInHKAO9urTF7HfFVSdIOeKz3mrc5lNLcvF0ELnIUn_cdjxZuMcZqCNUc2JBmbD9v0RUAI8jJUqnUA-MVtWM5Lt6dV2FNAw17ku35YUKqkO_JpzdmP3Fh22yww/s1096/orangepi_minicom_sys_device.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="176" data-original-width="1096" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgriqacZSB5fslx6THIopndfKXBMFmnetvt3hR2bGabRdD-Be8GyNG8oJug8pUk7HohhInHKAO9urTF7HfFVSdIOeKz3mrc5lNLcvF0ELnIUn_cdjxZuMcZqCNUc2JBmbD9v0RUAI8jJUqnUA-MVtWM5Lt6dV2FNAw17ku35YUKqkO_JpzdmP3Fh22yww/w640-h102/orangepi_minicom_sys_device.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[그림 3.12] sysfs i2c device 디렉토리 모습</span></div></div><span style="font-family: Nunito;"><div><span style="font-family: Nunito;"><br /></span></div><div>i2cdetect -l 명령을 실행해 보아도 비슷한 결과(2개의 i2c controller 출력)를 얻을 수 있다.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcpANbHQbLK7dDxuBGp2KC_KkmpUcjrrbhbz_qKtjUDtDbk1MOJU4WV5sucZ_mAovjvMcabT5dNM2o_I2sdmKhjs_2Ux4YNrZBv9hw5kMdDsSJW81SJX_WUKyoIXJjl9J-CWZT5IEeqMouXdHgdzpLZ9zlb4fDa8A8uRfdMwvFRiQTiGl_b_I7EPg4FA/s709/i2cdetect_list.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="72" data-original-width="709" height="64" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcpANbHQbLK7dDxuBGp2KC_KkmpUcjrrbhbz_qKtjUDtDbk1MOJU4WV5sucZ_mAovjvMcabT5dNM2o_I2sdmKhjs_2Ux4YNrZBv9hw5kMdDsSJW81SJX_WUKyoIXJjl9J-CWZT5IEeqMouXdHgdzpLZ9zlb4fDa8A8uRfdMwvFRiQTiGl_b_I7EPg4FA/w640-h64/i2cdetect_list.png" width="640" /></a></div><br /></div></span><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">i2c device 즉, htu21d가 제대로 인식되는지를 보기 위해 <b>i2cdetect -y 0 </b>명령을 사용해 보니, 아래와 같이 device address 40(hex)이 보인다. 참고로 htu21d의 7-bit i2c address는 0x40이다.</span></p><p style="line-height: 150%; margin: 0cm;"><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcqQqv0c8qCEgy-sx2Dj-CU_fdzG-A0gBZJt_NChdP1EhJHjrNuQWjDJBXbt5Sp4boeUqtxWEfD1IwNYLk5h5RehmR1rUwcWzF8rLZ7tvOhhpMXvrqGAlGswzCcDr-p7_SwaEUW72GYmI7eWg5IiYceS9BxN7Ymmnwgom-g5TwtH1NCWvhmmTi70GLyA/s504/orangepi_i2cdetect.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="222" data-original-width="504" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcqQqv0c8qCEgy-sx2Dj-CU_fdzG-A0gBZJt_NChdP1EhJHjrNuQWjDJBXbt5Sp4boeUqtxWEfD1IwNYLk5h5RehmR1rUwcWzF8rLZ7tvOhhpMXvrqGAlGswzCcDr-p7_SwaEUW72GYmI7eWg5IiYceS9BxN7Ymmnwgom-g5TwtH1NCWvhmmTi70GLyA/w400-h176/orangepi_i2cdetect.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 3.13] i2c detect -y 0 명령 실행 모습</span></span></div><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="color: #b45f06; font-family: Nunito;">참고: i2cdetect는 device tree 설정만 제대로 되어 있어도 위와 같이 address를 감지해 낼 수 있다.</span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="color: #ff00fe; font-family: Nunito;"><b><여기서 잠깐></b></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">OpenWrt에서는 i2cdetect 명령어를 아래의 방법을 통해 설치해 주어야 한다.</span></p><p style="line-height: 150%; margin: 0cm;"><span><br /></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"># <b>opkg update</b></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;"># <b>opkg install i2c-tools</b></span></p><p style="line-height: 150%; margin: 0cm;"><span style="font-family: Nunito;">_____________________________________</span></p><p><span><span style="font-family: Nunito;"><br /></span></span></p><p><span><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">d) i2c device driver 구동하기</b></span></span></p><p><span><span style="font-family: Nunito;">온습도 센서인 HTU21의 device driver code는 아래 위치에 존재한다.</span></span></p><p style="text-align: center;"><span style="font-family: Nunito;">openwrt/build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/linux-5.4.179/<b>drivers/iio/humidity/htu21.c</b></span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">당연히 기본 disable 상태이므로, menuconfig를 통해 htu21 module을 enable 시켜 보도록 하자.</span></p><p style="text-align: center;"><span style="color: #a64d79; font-family: Nunito;"><b>Kernel modules -> Industrial I/O Modules -> kmod-iio-htu21</b></span></p><p><span style="font-family: Nunito;">$ <b>make menuconfig</b></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxcd4pIAtS9vRgX3BTfDv9w02Q6-eaIhGyNgXaxSrZ3kTD_kTPANqenkfclhrOUIIGB63i5Qa1GOfbqLQ2iEv57wTiGYD9W2dvX9JiAzVOprrvdaVPFGAlKpLlI_InLw-JLZXMkqaDHP-v25VHv1o6pWr_qnlGa4YURdiDK68DT8qv6cgLBMv5oj98Mw/s936/orangepi_openwrt_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="703" data-original-width="936" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxcd4pIAtS9vRgX3BTfDv9w02Q6-eaIhGyNgXaxSrZ3kTD_kTPANqenkfclhrOUIIGB63i5Qa1GOfbqLQ2iEv57wTiGYD9W2dvX9JiAzVOprrvdaVPFGAlKpLlI_InLw-JLZXMkqaDHP-v25VHv1o6pWr_qnlGa4YURdiDK68DT8qv6cgLBMv5oj98Mw/w400-h300/orangepi_openwrt_menuconfig.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 3.14] openwrt make menuconfig 모습</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span><br /></span></span></div><p><span style="font-family: Nunito;">설정 변경한 내용을 저장한 후, kernel을 재 build하도록 한다. 이후, 아래 3개의 kernel module을 찾아 target board로 복사 후, 구동(modprobe or insmod)시켜 보도록 한다.</span></p><p><span style="font-family: Nunito;"><span style="color: #b45f06;">참고: modprobe htu21를 실행해 보면, 왜 3개의 kernel module이 필요한지를 알 수 있게 된다.</span></span></p><p><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></p><p><span style="color: #674ea7; font-family: Nunito;"><b><Ubuntu Desktop></b></span></p><p><span style="font-family: Nunito;">$ <b>make V=s</b></span></p><p><span style="font-family: Nunito;">$<b> cd build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/linux-5.4.179/drivers/iio/common/ms_sensors</b></span></p><p><span style="font-family: Nunito;"></span></p><p><span style="font-family: Nunito;">$ <b>scp ./</b><b><span style="color: #b45f06;">ms_sensors_i2c</span></b><b><span style="color: #b45f06;">.ko</span> root@192.168.2.1:~/workspace</b></span></p><p><span style="font-family: Nunito;">$<b> cd build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/linux-5.4.179/drivers/iio</b></span></p><p><span style="font-family: Nunito;"></span></p><p><span style="font-family: Nunito;"></span></p><p><span style="font-family: Nunito;">$ <b>scp ./</b><b><span style="color: #b45f06;">industrialio</span></b><b><span style="color: #b45f06;">.ko</span> root@192.168.2.1:~/workspace</b></span></p><p><span style="font-family: Nunito;"></span></p><p><span><span style="font-family: Nunito;">$</span><b style="font-family: Nunito;"> cd build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/linux-5.4.179/drivers/iio/humidity</b></span></p><p><span style="font-family: Nunito;">$ <b>scp ./<span style="color: #b45f06;">htu21.ko</span> root@192.168.2.1:~/workspace</b></span></p><p><span style="font-family: Nunito;"><span style="color: #b45f06;">참고: 192.168.2.1은 target board LAN의 ip 주소이다.</span></span></p><p><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></p><p><span style="color: #674ea7; font-family: Nunito;"><b><Target Board></b></span></p><div style="text-align: left;"><span style="font-family: Nunito;">$ ssh root@192.168.2.1</span></div><div style="text-align: left;"><span style="font-family: Nunito;"># cd ~/workspace<br /></span><span style="font-family: Nunito;">#<b> insmod ./ms_sensors_i2c.ko<br /></b></span><span style="font-family: Nunito;"># <b>insmod ./industrialio.ko<br /></b></span><span style="font-family: Nunito;">#<b> insmod ./htu21.ko</b></span></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiswAsja5pVM1w-JVdaeZ60ibfgP40V3KHOPo2PDdmdvEGCqYk8Q1LAJ6sJIdfjHRnDKhGyl8sPycpBJzPj3yyoaWvTqxslWjgBy4WtlPKB_UseayTAuTpEM_9mUiCpj4i9jID4Snzu1EMqRZyL3CxI88pxdmc1wqqkJ32bmGdZhhLP3BaKVQJcTe0SlQ/s482/orangepi_htu21.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="110" data-original-width="482" height="91" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiswAsja5pVM1w-JVdaeZ60ibfgP40V3KHOPo2PDdmdvEGCqYk8Q1LAJ6sJIdfjHRnDKhGyl8sPycpBJzPj3yyoaWvTqxslWjgBy4WtlPKB_UseayTAuTpEM_9mUiCpj4i9jID4Snzu1EMqRZyL3CxI88pxdmc1wqqkJ32bmGdZhhLP3BaKVQJcTe0SlQ/w400-h91/orangepi_htu21.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span>[그림 3.15] htu21d driver 구동 모습</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span><br /></span></span></div><p></p><p><span style="font-family: Nunito;">물론, 위의 방법 보다는 openwrt 전체 build를 통해 image file을 다시 생성한 후, microSD에 재 설치하는 방법이 더 쉬울 수도 있다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">나머지 센서 동작 확인 과정(온도, 습도 값, battery low 상태, heater enable 상태 값 확인 등)은 아래 blog post의 내용과 동일하므로 여기서는 자세한 사항은 생략하기로 한다. Pass~ 😋</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html</a></span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">e) i2c device driver 직접 만들기 - kernel용 드라이버</b></span></span></p><p><span style="font-family: Nunito;"></span></p><div style="text-align: left;"><span style="font-family: Nunito;">앞선 내용은 이미 구현되어 있는 드라이버 코드를 소개하는 것에 불과하다. 실제로 독자 여러분 중에는 이와 유사한 i2c device driver를 직접 구현하고 싶을 수도 있을 것이다. 따라서 이 절에서는 i2c driver 구현과 관련한 보다 구체적인 사항을 소개하고자 한다.<br /></span><span style="font-family: Nunito;">먼저, 아래 그림은 linux i2c subsystem을 하나의 그림으로 표현한 것인데, 이 중 지금 우리가 구현해야 할 부분은 우측의 i2c client driver 부분이 되겠다.</span></div><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglQVCpVNxaJArX99B3D9PX_xzkxDXlNqI3IB7r2nadWrWq2_0Tb6ILoIL-_ejc71N0wMi2DbCXNrNygk45gKel6JH-Kce-Uo1L2e8FbNn0avtCa13W-ekJTMcmVHEQ-UP0esbd09RStis34EQH-SIZFN2AduWyprijUUZtwOBEolOBjisaRoWTtBFSsw/s721/linux_i2c_subsystem.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="402" data-original-width="721" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglQVCpVNxaJArX99B3D9PX_xzkxDXlNqI3IB7r2nadWrWq2_0Tb6ILoIL-_ejc71N0wMi2DbCXNrNygk45gKel6JH-Kce-Uo1L2e8FbNn0avtCa13W-ekJTMcmVHEQ-UP0esbd09RStis34EQH-SIZFN2AduWyprijUUZtwOBEolOBjisaRoWTtBFSsw/w640-h356/linux_i2c_subsystem.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 3.16] Linux i2c subsystem [출처: 참고문헌 3]</span></div><div class="separator" style="clear: both; text-align: center;"><span><br /></span></div><div><span><br /></span></div><div><span>이 그림에는 표현되지 않았지만, i2c client driver로 부터 i2c controller로 이어지는 read or write 함수 흐름은 다음과 같다.</span></div><div><span><br /></span></div><div><div style="text-align: center;"><b><span>I2C client driver-> I2C bus core driver -> I2C controller driver:</span></b></div><div style="text-align: center;"><b><span style="color: #3d85c6;">i2c_smbus_write_byte_data() -> i2c_smbus_xfer() -> i2c_imx_xfer()</span></b></div></div><div style="text-align: center;"><span><br /></span></div><div><span><br /></span></div><span>본론으로 들어가서, i2c client driver를 구현하기 위해서는 제일 먼저 <b>struct i2c_driver</b>를 정의(예: htu21_driver)해 주어야 한다.<br /><span style="font-family: Nunito;"><br /><div><span style="color: #3d85c6;">static struct i2c_driver <b>htu21_driver</b> = {</span></div><div><span style="color: #3d85c6;"> .probe = <b>htu21_probe</b>,</span></div><div><span style="color: #3d85c6;"> .remove = <b>htu21_remove</b>,</span></div><div><span style="color: #3d85c6;"> .id_table = htu21_id,</span></div><div><span style="color: #3d85c6;"> .driver = {</span></div><div><span style="color: #3d85c6;"> .name = "htu21_simple",</span></div><div><span style="color: #3d85c6;"> <b> .of_match_table</b> = of_match_ptr(htu21_of_match),</span></div><div><span style="color: #3d85c6;"> },</span></div><div><span style="color: #3d85c6;">};</span></div><div><br /></div><div>앞서 정의한 struct i2c_driver를 실제로 i2c bus core에 등록 or 해지하기 위해서는 아래와 같이 <b>i2c_add_driver()</b> or <b> i2c_del_driver() </b>함수가 각각 사용된다.</div><div><br /></div><div><div><span style="color: #3d85c6;">static int __init i2c_init(void)</span></div><div><span style="color: #3d85c6;">{</span></div><div><span style="color: #3d85c6;"> return <b>i2c_add_driver</b>(&htu21_driver);</span></div><div><span style="color: #3d85c6;">}</span></div><div><span style="color: #3d85c6;">module_init(i2c_init);</span></div><div><span style="color: #3d85c6;">static void __exit i2c_cleanup(void)</span></div><div><span style="color: #3d85c6;">{</span></div><div><span style="color: #3d85c6;"> <b>i2c_del_driver</b>(&htu21_driver);</span></div><div><span style="color: #3d85c6;">}</span></div><div><span style="color: #3d85c6;">module_exit(i2c_cleanup);</span></div></div><div><br /></div><div><span>참고로, <b>module_i2c_driver</b>(htu21_driver) 함수는 위의 코드를 한줄로 대신해 준다.</span></div><div><br /></div><div><br /></div><div>of_device_id 구조체는 device tree와의 연결 고리인 <b>.compatible </b>필드를 갖고 있다. 또한 struct i2c_driver의 of_match_table 필드는 struct of_device_id 구조체 배열의 pointer이다. <b>만일 of_device_id의 항목 중 하나가 device tree node의 compatible 속성과 일치하는 것이 있을 경우, 해당 probe() 함수가 자동으로 호출되게 된다.</b></div><div><br /></div><div><div><span style="color: #38761d;">struct of_device_id {</span></div><div><span style="color: #38761d;"> char name[32];</span></div><div><span style="color: #38761d;"> char type[32];</span></div><div><span style="color: #38761d;"> char compatible[128];</span></div><div><span style="color: #38761d;">};</span></div></div><div><br /></div><div><div><span style="color: #3d85c6;">static struct of_device_id htu21_of_match[] = {</span></div><div><span style="color: #3d85c6;"> { <b>.compatible </b>= "meas,htu21", },</span></div><div><span style="color: #3d85c6;"> { },</span></div><div><span style="color: #3d85c6;">};</span></div><div><span style="color: #3d85c6;">MODULE_DEVICE_TABLE(of, htu21_of_match);</span></div></div><div><br /></div><br /></span></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihucmnVkxXO9N9wvcrUC6_Rm54Qp2NJkhxgscpraDFjXsglpmwX5BdjDvlVgeFG1Zzkjev3B8WCUcv4u2H5a-OPcS9zH4XtQcpXbUcIiowM9AiiWbtNgac2DxOJ7zp6QPpi6po3lIEhH4vOnngoGk1K6tZq1g7loPbKA22IHF8fDT0uAX5nqag-mapRg/s777/htu21_simple_driver.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="520" data-original-width="777" height="428" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihucmnVkxXO9N9wvcrUC6_Rm54Qp2NJkhxgscpraDFjXsglpmwX5BdjDvlVgeFG1Zzkjev3B8WCUcv4u2H5a-OPcS9zH4XtQcpXbUcIiowM9AiiWbtNgac2DxOJ7zp6QPpi6po3lIEhH4vOnngoGk1K6tZq1g7loPbKA22IHF8fDT0uAX5nqag-mapRg/w640-h428/htu21_simple_driver.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 3.17] htu21_simple i2c driver 구현(1)</span></div><div><span><br /></span></div><span>probe() 함수는 device tree node로 부터 얻은 속성 값을 이용하여 device를 초기화하는 역할을 수행하는 것은 물론이고, 적절한 kernel framework(예: input, iio frameworks 등)에 device를 등록시켜 주는 역할을 하게 된다.</span></div><div><span><br /></span><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiISDT_GHvdfuLQ7Ek03in6MmcJsVPZaTuOxwjhmcA3Alhwo5qYHXEyttViwI77AVbUcotfMom0xG5jBdi34N33cuVzBycwQBSY5o9UGMNsaOgrfuxGjOPPHyQrmTAzhlQw6raFtVU9UDc5a27CrAyxMMBFlMegH0YfvgfNmFTZuUs0G8BmmM18ErhIlA/s909/htu21_simple_driver2.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="909" data-original-width="773" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiISDT_GHvdfuLQ7Ek03in6MmcJsVPZaTuOxwjhmcA3Alhwo5qYHXEyttViwI77AVbUcotfMom0xG5jBdi34N33cuVzBycwQBSY5o9UGMNsaOgrfuxGjOPPHyQrmTAzhlQw6raFtVU9UDc5a27CrAyxMMBFlMegH0YfvgfNmFTZuUs0G8BmmM18ErhIlA/w544-h640/htu21_simple_driver2.png" width="544" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 3.18] htu21_simple i2c driver 구현(2)</span></div><span><br /><span style="font-family: Nunito;">probe() 함수를 통해 device가 초기화 되었으니, 그 다음으로 해야할 일은 i2c device를 통해 data를 읽거나 쓰는 코드를 작성하는 일이 될 것이다. 앞서 기술했던 내용을 여기에 다시한번 정리해 본다.</span></span></div><div><div style="text-align: center;"><span><br /></span></div><div style="text-align: center;"><b><span style="color: #a64d79;">i2c_smbus_write_byte_data() -> i2c_smbus_xfer() -> i2c_imx_xfer()</span></b></div><div style="text-align: center;"><b><span style="color: #a64d79;">i2c_smbus_read_byte_data() -> i2c_smbus_xfer() -> i2c_imx_xfer()</span></b></div><p></p><p><span style="font-family: Nunito;"><span style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></span></span></p><p><span style="font-family: Nunito;"><span style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">read, write 함수 호출 부분은 각각의 device 마다 일정한 시나리오를 가지고 운용되는 부분인 만큼 관련 해당 datasheet를 면밀히 살펴 본 후 작업에 들어가야만 한다. 끝으로 i2c client driver에서 사용 가능한</span></span><span style="font-family: Nunito;"><span> read/write 함수를 정리하는 것으로 이번 절을 마무리하도록 하겠다.</span></span></span></p><p><span style="font-family: Nunito;">_______________________________________________________________________</span></p><p><b style="font-family: Nunito;"><span><i2c/smbus read/write 함수 정리></span></b></p><p><span style="color: #c27ba0; font-family: Nunito;">int <b>i2c_master_send</b>(struct i2c_client *client, const char *buf, int count);</span></p><p><span style="color: #c27ba0; font-family: Nunito;"></span></p><p><span style="color: #c27ba0; font-family: Nunito;">int<b> i2c_master_recv</b>(struct i2c_client *client, char *buf, int count);</span></p><p><span style="color: #c27ba0; font-family: Nunito;">int <b>i2c_transfer</b>(struct i2c_adapter *adap, struct i2c_msg *msg, int num);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_read_byte</b>(struct i2c_client *client);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_write_byte</b>(struct i2c_client *client, u8 value);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_read_byte_data</b>(struct i2c_client *client, u8 command);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_write_byte_data</b>(struct i2c_client *client, u8 command, u8 value);</span></p><p><span style="font-family: Nunito;">s32<b> i2c_smbus_read_word_data</b>(struct i2c_client *client, u8 command);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_write_word_data</b>(struct i2c_client *client, u8 command, u16 value);</span></p><p><span style="font-family: Nunito;">s32<b> i2c_smbus_read_block_data</b>(struct i2c_client *client, u8 command, u8 *values);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_write_block_data</b>(struct i2c_client *client, u8 command, </span></p><p><span style="font-family: Nunito;"> u8 length, const u8 *values);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_read_i2c_block_data</b>(struct i2c_client *client, u8 command, </span></p><p><span style="font-family: Nunito;"> u8 length, u8 *values);</span></p><p><span style="font-family: Nunito;">s32 <b>i2c_smbus_write_i2c_block_data</b>(struct i2c_client *client, u8 command, </span></p><p><span style="font-family: Nunito;"></span></p><p><span style="font-family: Nunito;"> u8 length, const u8 *values);</span></p><p><span style="font-family: Nunito;">_______________________________________________________________________</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito; font-size: large;"><b style="color: #38761d;">f) i2c device driver 직접 만들기 - userspace 용 드라이버</b></span></p><div style="text-align: left;"><span style="font-family: Nunito;">i2c나 spi driver는 usrespace 용으로도 구현이 가능하다. 이 절에서는 이와 관련된 내용을 소개하고자 한다.</span></div><div style="text-align: left;"><span><span style="font-family: Nunito;"><br /></span><span style="color: #b45f06; font-family: Nunito;"><b><Userspace용 i2c driver 구현 절차 요약></b></span><br /><span style="font-family: Nunito;">a) /dev/i2c-0 or i2c-1 등의 device file을 open한다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"> <i>=> 이를 위해서는 i2c device가 i2c 몇번 controller에 연결되었는지를 확인하는 작업이 선행되어야 한다.</i></span></div><div style="text-align: left;"><span><span style="font-family: Nunito;">b) ioctl(fd, I2C_SLAVE, 0x40) 형태로 ioctl 함수를 이용하여 i2c slave 모드 지정 및 i2c address를 설정해 준다.</span><br /><span style="font-family: Nunito;">c) read(), write() 함수를 사용하여 i2c device와 통신을 한다. 앞서도 언급했다시피 이 부분은 각각의 i2c device 마다 사용하는 register 정보 및 동작 시나리오 등이 차이가 있으므로 사전에 datasheet를 면밀히 분석한 후 read, write 함수 부분을 적절히 구현해 주어야 한다.</span><br /><span style="font-family: Nunito;">d) 통신이 모두 끝난 경우에는 앞서 open한 부분을 반드시 닫아(close) 주도록 한다. </span></span></div><p><span style="font-family: Nunito;">________________________________________________________________________</span></p><p><span><span style="font-family: Nunito;">userspace용 i2c driver 구현은 크게 어렵지 않다. </span><span style="font-family: Nunito;">아래 site에 좋은 예제 코드가 있으니, 함께 참조하기 바란다.</span></span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/Digilent/linux-userspace-examples">https://github.com/Digilent/linux-userspace-examples</a></span></p><p style="text-align: center;"><a href="https://docs.kernel.org/i2c/dev-interface.html"><span>https://docs.kernel.org/i2c/dev-interface.html</span></a></p><p style="text-align: center;"><span><br /></span></p><p><span>___________________________________________________________________</span></p><div style="text-align: left;"><span style="color: #ff00fe; font-family: Nunito;"><b><여기서 잠깐 - </b></span><span style="font-family: Nunito;"><b><span style="color: #ff00fe;">i2c 말고 SPI 용 센서를 붙여 보고 싶다면, 어떻게 해야 할까 ?></span></b><br /></span><span style="font-family: Nunito;"><i>a) 아쉽게도 Orange Pi L1 Plus LTS board에는 SPI 확장 pin이 보이질 않는다.<br /></i></span><span style="font-family: Nunito;"><i>b) 따라서 Raspberry Pi 등을 이용해서 SPI 테스트를 해 볼 수 있겠다.<br /></i></span><span style="font-family: Nunito;"><i>c) 예를 들어, 아래 SPI용 3축 가속도 센서(ADXL345)를 하나 붙여 보도록 하자.</i></span></div><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHISvUnfj2dPqyBXHmZYp_AOKCRazufgXz1Mshm3gUwigNU3b9CoNw6XLBbc7cgztNa0aMNwNSM6ZVWT5dZBXh_7YJMMUyOdmy3M4RTcjyy6C-Mh4e5qoPafh1EAqz5bmM1muwvy3orow5CQzwFC-2qmaPdyiW52tFWDaj3RHnNxbsZhSLKXTG9cVx3Q/s584/spi_interface.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="194" data-original-width="584" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHISvUnfj2dPqyBXHmZYp_AOKCRazufgXz1Mshm3gUwigNU3b9CoNw6XLBbc7cgztNa0aMNwNSM6ZVWT5dZBXh_7YJMMUyOdmy3M4RTcjyy6C-Mh4e5qoPafh1EAqz5bmM1muwvy3orow5CQzwFC-2qmaPdyiW52tFWDaj3RHnNxbsZhSLKXTG9cVx3Q/w400-h133/spi_interface.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 3.19] SPI </span></div><p></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg83Uks3Hu1UTr50Bt5DsAnwTPKokgX50P4CO06FfoflRD7gOqcxvUi1CN2U69Nlig3N5ns9rbfljv1Qpkgntj__ZGQw5ViTmCtwojUtzokeNeqRWTxMs-486dNuA1rHyA9_NXvOzAsVJAx8BWnvTvvZcKR16qKvAvNtQon7B23qyJJIbNqDVbQvJDxGw/s2190/adxl345spi_bb.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="993" data-original-width="2190" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg83Uks3Hu1UTr50Bt5DsAnwTPKokgX50P4CO06FfoflRD7gOqcxvUi1CN2U69Nlig3N5ns9rbfljv1Qpkgntj__ZGQw5ViTmCtwojUtzokeNeqRWTxMs-486dNuA1rHyA9_NXvOzAsVJAx8BWnvTvvZcKR16qKvAvNtQon7B23qyJJIbNqDVbQvJDxGw/w640-h290/adxl345spi_bb.png" width="640" /></span></a></div><span><br /></span><div class="separator" style="clear: both; text-align: center;"><span>[그림 3.20] Raspberry Pi + ADXL345 spi sensor 연결 모습[출처 - 참고문헌 4]</span></div><span><div><span><br /></span></div><span style="color: #b45f06;">참고: adxl345 linux driver는 아래 위치에 있으니, 함께 분석해 보면 좋겠다.</span></span></div><div><span><div style="text-align: center;"><b>linux-5.4.179/drivers/iio/accel/adxl345_spi.c, adxl345_core.c</b></div><span>___________________________________________________________________</span><br /></span><p></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">지금까지 Orange Pi L1 LTS 보드를 가지고 i2c 용 device tree 및 device driver를 만드는 과정을 간략히 살펴 보았다.</span></p><p style="text-align: left;"><span><span style="color: #8e7cc3; font-family: Nunito;"><b>이는 약간 과장해서, h/w 보드를 하나 만들고, OS(openwrt - bootloader/kernel/rootfs)를 porting해서 올린 후, 필요한 device driver를 구현하는 일반적인 보드 개발 과정을 가정하고 정리한 것으로 이해해 주시면 좋겠다. 😂 </b></span><span style="font-family: Nunito;">그렇다면, 그 다음에 할일은 ...</span></span></p><p><span><br /></span></p><p><span><b style="background-color: #fff2cc;"><span style="font-family: Nunito;">이번 blog post에서 소개하는 OrangePi board는 2개의 ethernet port로 무장(?)하고 있는게 특징이다. 이는 OrangePi board를 router(정확히는 security gateway)로 활용할 수 있다는 뜻이기도 하다. </span><span style="font-family: Nunito;"> 이제 부터는 </span><span style="font-family: Nunito;"><span style="color: #b45f06;">Orange Pi L1 LTS 보드를 PQC 알고리즘을 장착한 security gateway로 만드는 방법</span>에 관하여 소개해 보고자 한다.</span></b></span></p><p><span style="font-family: Nunito;"><br /></span></p><p><b style="color: #3d85c6; font-family: Nunito;"><span style="font-size: x-large;">4. PQC(Post Quantum Cryptography) 개요</span></b></p><div style="text-align: left;"><span style="font-family: Nunito;"><span>PQC는 양자 computer가 곧 도래할 경우를 대비하여 등장한 공개키 기반의 암호 알고리즘으로 키 교환(KEM) 알고리즘과 전자 서명(DS) 알고리즘으로 구성되어 있다. </span></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito;"><span><span style="color: black;"><br /></span></span></span><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">a) PQC(Post-Quantum Cryptography) 개요</span></b></div><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp0YQ5naiNiWqpj685IeLzCu7TdTwA1CFBPcdZQvVndIujgiizYEp9YKbP4jxARdFhMaL8Rg6ESNaj4G1HkjaG1AUj11CJGDPBH_ZSLCi1bNwq6W_RWy365YHsTYBXr3s6hXrPp5fGJU-UAo01O7TQv2VQvSbjtkdXIXpq0uqmkgqAstAOG21KqMF7Pw/s896/post_quantum_cryptography_family.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="399" data-original-width="896" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp0YQ5naiNiWqpj685IeLzCu7TdTwA1CFBPcdZQvVndIujgiizYEp9YKbP4jxARdFhMaL8Rg6ESNaj4G1HkjaG1AUj11CJGDPBH_ZSLCi1bNwq6W_RWy365YHsTYBXr3s6hXrPp5fGJU-UAo01O7TQv2VQvSbjtkdXIXpq0uqmkgqAstAOG21KqMF7Pw/w640-h286/post_quantum_cryptography_family.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 4.1] PQC 알고리즘 군 [출처 - 참고 문헌 6]</span></div><p></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfecfOZmy5OZ3lI2FZLkmwiZqNBnIVuqPZekWF14s_c1MlRIXRcrD-c3nGVOFHDWIaEYzsAbO8Vei5pphOrBsr9ygzlDux8SUifE7_CRqqL4PR3ZXj-gWT-aZyc9iPOL3Moowj_tJDYjVstDJeKVzmLwUJ6vdKL2KCPZKPbnEKfYL4umcdlUm84RPS3A/s1208/pqc_nist_round3_kem_finalists.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="521" data-original-width="1208" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfecfOZmy5OZ3lI2FZLkmwiZqNBnIVuqPZekWF14s_c1MlRIXRcrD-c3nGVOFHDWIaEYzsAbO8Vei5pphOrBsr9ygzlDux8SUifE7_CRqqL4PR3ZXj-gWT-aZyc9iPOL3Moowj_tJDYjVstDJeKVzmLwUJ6vdKL2KCPZKPbnEKfYL4umcdlUm84RPS3A/w640-h276/pqc_nist_round3_kem_finalists.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.2] NIST PQC Round 3 KEM 후보간 비교[출처 - 참고문헌 7]</span></span></div><p></p><p><span style="color: #b45f06; font-family: Nunito;">참고: 특이하게도 CRYSTALS Kyber는 x25519보다도 실행 시간이 덜 걸린다(더 빠르다).</span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxkeKhVILdUO34wfXHlbWNvtl94VI1A8wwQpQGDTQBtXxJozSjpMf7H7nb7kMvLG6tivpsS0Zh3EZBvp8cIeGRhS2Ygxu7nXzkDhaYRHahxFcoxmC7rfsZf2onc9arUhBmxsX0q6Jk0t70BV5Vpv9J2k4hmGceuNE4sllPw5qUuj9LHU-m9amVZIETWA/s1204/pqc_nist_round3_signature_finalist.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="520" data-original-width="1204" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxkeKhVILdUO34wfXHlbWNvtl94VI1A8wwQpQGDTQBtXxJozSjpMf7H7nb7kMvLG6tivpsS0Zh3EZBvp8cIeGRhS2Ygxu7nXzkDhaYRHahxFcoxmC7rfsZf2onc9arUhBmxsX0q6Jk0t70BV5Vpv9J2k4hmGceuNE4sllPw5qUuj9LHU-m9amVZIETWA/w640-h276/pqc_nist_round3_signature_finalist.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 4.3] NIST PQC Round 3 DS 후보간 비교[출처 - 참고문헌 7]</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><br /></span></div><p><span style="font-family: Nunito;">NIST는 2022년에 들어서 드디어 최종 알고리즘(NIST PQC Standard)과 4 round 후보군을 아래와 같이 선정하였다.</span></p><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8r_eOAhUqS14F1ejsfO8MRAuez-5T4z-02s0X8emyqPrxJwQPzt8dt8aFbDBv-Biek0hEFTS8H-rH25SjaG4YJJzC7k4IlM4vH67gbgy-8lpXLBSDXj7JSOBYgPJOhGWtJNc7kq91wHNdi3wRVRMnpY21CbAvcYSOG6-KASYgkmObEU9h3CNchNdrSA/s772/nist_pqc_standard.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="375" data-original-width="772" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8r_eOAhUqS14F1ejsfO8MRAuez-5T4z-02s0X8emyqPrxJwQPzt8dt8aFbDBv-Biek0hEFTS8H-rH25SjaG4YJJzC7k4IlM4vH67gbgy-8lpXLBSDXj7JSOBYgPJOhGWtJNc7kq91wHNdi3wRVRMnpY21CbAvcYSOG6-KASYgkmObEU9h3CNchNdrSA/w640-h310/nist_pqc_standard.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4IO07Zf1i81q5McX4dQQZIL2Ei_H2bhk4KvmHd1BH2dTi8fEyKHptVEIe2E1-Msd4T7UaOr-z_8QFo66-aP0nPzYvChIJocEadsYgVjjvMqwIaY6ypKCotsTnid7YNimYJm4dwveOnecZgtAuwzQ1QT8EOWECXFvZGqrylzz1xOiXALk0rbHE81QRKQ/s768/nist_pqc_fourth_round_kem_candidate.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="285" data-original-width="768" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4IO07Zf1i81q5McX4dQQZIL2Ei_H2bhk4KvmHd1BH2dTi8fEyKHptVEIe2E1-Msd4T7UaOr-z_8QFo66-aP0nPzYvChIJocEadsYgVjjvMqwIaY6ypKCotsTnid7YNimYJm4dwveOnecZgtAuwzQ1QT8EOWECXFvZGqrylzz1xOiXALk0rbHE81QRKQ/w640-h238/nist_pqc_fourth_round_kem_candidate.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.4] NIST PQC Finalist [출처: 참고 문헌 8]</span></span></div><p></p><p><span style="color: #b45f06;">참고: 필자 개인적으로는 Classic McEliece가 매우 간결하면서도, 오랫동안 안정성이 검증된 알고리즘으로 4 round에서는 꼭 선정되기를 희망해 본다(단점: public & private key가 지나치게 큰 것이 문제). 😍</span></p><p><span> </span></p><p><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">b) 격자 기반 LWE(Learning with Errors)</span></b></p><div><span><span style="font-family: Nunito;">PQC 알고리즘은 대부분 수학적인 난제(NP-Hard)에 기초하고 있는데, 이 중 가장 hot한 알고리즘은 <b><u>Lattice(격자) 기반 문제(난제)</u></b>에 기초하고 있다고 해도 과언이 아닐 것이다. NIST 표준으로 선정된 <b><span style="color: #b45f06;">CRYSTALS Kyber</span></b>와 <b><span style="color: #b45f06;">Dilithium</span></b> 역시 Lattice 기반 LWE 문제를 기반으로 구현되어 있다. </span><span style="font-family: Nunito;">Lattice 기반의 Closest Vector Problem을 입체적으로 표현한 그림이 있어 여기에 옮겨 본다.</span></span><div style="text-align: center;"><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;"><span style="color: #990000;"><b><span style="background-color: #fcff01; font-size: large;">As + e = t</span><br /></b></span></span></div></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-LJkwymHLakE6xJQkJVtbRsq2mLX75EuhZR2q6K9_HdiaJdAzjeXvDwSZqJKBEULaNrzk4q06Rz7hCIxa27mHNF9WxHRCT6xRXje5J6qEZUipQR1goLtSFjGJw7Gvjvc6Ow4slyGC7wilZmPp710EQ20eNrkTtJgLlfW2CbDtqBjPVwk_CEOvURpI8g/s869/lattice_lwe.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="869" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-LJkwymHLakE6xJQkJVtbRsq2mLX75EuhZR2q6K9_HdiaJdAzjeXvDwSZqJKBEULaNrzk4q06Rz7hCIxa27mHNF9WxHRCT6xRXje5J6qEZUipQR1goLtSFjGJw7Gvjvc6Ow4slyGC7wilZmPp710EQ20eNrkTtJgLlfW2CbDtqBjPVwk_CEOvURpI8g/w640-h274/lattice_lwe.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.5] Lattice 기반 CVP(Closest Vector Problem) [출처: 참고문헌 17]</span></span></div><p></p><div><span style="font-family: Nunito;">위의 그림을 한마디로 정리하면, </span></div><div><span style="font-family: Nunito;"><b>"<span style="color: #a64d79;">A(행렬)라는 무한 차원 격자와 t vector 값을 알고 있는 상태에서 감춰진 에러 값 e vector가 주어질 경우, t에서 가장 가까운 s(vector)를 알아내는 것은 무지 무지 어렵다(양자 computer로도 불가능하다)</span>"</b></span></div><div><span><span style="font-family: Nunito;">라고 말할 수 있다. </span><span style="font-family: Nunito;">이때 행령 <b>A</b>와 <b>t</b>는 Public key로, Vector <b>s</b>는 Private key(or secret key)로 활용될 수 있다. 어떤까 대략 무슨 얘기를 하려는 것인지 감이 오는가 ? 😓</span></span></div><div><br /></div><p><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">c) KEM(Key Encapsulation Mechanism)</span></b></p><p><span>KEM은 PQC 기반의 키교환 방식을 뜻한다. KEM 절차를 간략히 정리해 보면 다음과 같다.</span></p><div style="text-align: left;"><span><b>(1)</b> Alice(Initiator)는 Key 쌍 (pk, sk)를 하나 만든 후, Bob(Responder)에게 pk(public key)를 전달한다.<br /></span><span><b>(2) </b>pk를 받은 Bob은 Enc(encapsulation) 함수를 이용하여 대칭키 K와 K를 암호화한 값 c를 만든 후, Alice에게 c 값을 전달한다.<br /></span><span><b>(3)</b> c 값을 수신한 Alice는 자신이 이미 가지고 있는 sk(secret key = private key)와 Dec(decapsulation) 함수를 이용해 대칭 키 K를 획득한다.<br /></span><span><b>(4) </b>이후, Alice와 Bob은 서로 공유하게 된 K 값을 이용해 암호 통신(예: AES, ChaCha20 등)을 수행하게 된다.</span></div><p><span><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuZgjJmTZEdkqdHMSw7Hw2Bks4Alw5UNgI5EN4LX920zhWFEzubFeikVd2noccAiiu7NcCDEeFx--0Lx5TZ2tStuxfAFYCAjU4DfGJGotoRZPTDizaD9oEy2lS2qHAqN9rvWVMElYpgAWIUakZHB-Go7lxZRyUhOL_DeVqjYJvEmBp-XSt1LRTlxTYsg/s849/pqc_kem.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="371" data-original-width="849" height="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuZgjJmTZEdkqdHMSw7Hw2Bks4Alw5UNgI5EN4LX920zhWFEzubFeikVd2noccAiiu7NcCDEeFx--0Lx5TZ2tStuxfAFYCAjU4DfGJGotoRZPTDizaD9oEy2lS2qHAqN9rvWVMElYpgAWIUakZHB-Go7lxZRyUhOL_DeVqjYJvEmBp-XSt1LRTlxTYsg/w640-h280/pqc_kem.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.6] PQC KEM 개요(1)</span></span></div><p></p><p><span><br /></span></p><p><span>KEM의 동작 원리를 좀 더 구체적으로 표현해 보면 아래 3개의 그림과 같다. 어떤가 ... 이해가 되는가 ? 😋</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqrh-DLLLRXA3-onT_uXU4ZfiSeHJwlnFSTSxBkGeYAu8GPoP7cVFQk5AObTR5CJPlXUEvZZh66BRZsfaeo0CZQOLW78jYS93epaHW0FiFX7D7vlyZfPFsCmD0Rez30X5O-_J6Q0aL1R7y0d3ibaJfWvBDyzLWX8xCWnwnMr3YL6eKd2kvcD0nYx0UtQ/s869/pqc_kem1.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="427" data-original-width="869" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqrh-DLLLRXA3-onT_uXU4ZfiSeHJwlnFSTSxBkGeYAu8GPoP7cVFQk5AObTR5CJPlXUEvZZh66BRZsfaeo0CZQOLW78jYS93epaHW0FiFX7D7vlyZfPFsCmD0Rez30X5O-_J6Q0aL1R7y0d3ibaJfWvBDyzLWX8xCWnwnMr3YL6eKd2kvcD0nYx0UtQ/w640-h314/pqc_kem1.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.7] PQC KEM 개요(2)</span></span></div><p></p><p><span style="font-family: Nunito;"><span><br /></span></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSJsw6HwnAoqoytvoW6HjmFbMm0YpYIThUH_1v08aQ8iU0dLC0npZnnb0sgVJTJIW0CbJN4WuooMVobpPIuDdlxrn1_8hAckwikQawpGvUzkBR2Nsnv_A-TM7EXojR5TVK2jGtkwgHRpfgLOesVAxO6SfWRlmmxUYZQvrPpREATdsaiX-LD-YoY962w/s966/pqc_kem2.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="454" data-original-width="966" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUSJsw6HwnAoqoytvoW6HjmFbMm0YpYIThUH_1v08aQ8iU0dLC0npZnnb0sgVJTJIW0CbJN4WuooMVobpPIuDdlxrn1_8hAckwikQawpGvUzkBR2Nsnv_A-TM7EXojR5TVK2jGtkwgHRpfgLOesVAxO6SfWRlmmxUYZQvrPpREATdsaiX-LD-YoY962w/w640-h300/pqc_kem2.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.8] PQC KEM 개요(3)</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-nhrBj5b244Apv79sr-R-6MGIhXQf-LZhhITSBN5nvn-K_BHAYrbGqmq9nph0sd2CyZgW7ZhW0U4GmYhJ9MZeut2o8rBRozhVfEJyG3rywePTxC0NR_5LYUTjDPLZHrEBtSUH7XSzTUMvXRidRg4sBQ2IsBFnGK0_hM3Wa6tNz1mDT8do48KJozg1yQ/s864/pqc_kem3.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="457" data-original-width="864" height="338" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-nhrBj5b244Apv79sr-R-6MGIhXQf-LZhhITSBN5nvn-K_BHAYrbGqmq9nph0sd2CyZgW7ZhW0U4GmYhJ9MZeut2o8rBRozhVfEJyG3rywePTxC0NR_5LYUTjDPLZHrEBtSUH7XSzTUMvXRidRg4sBQ2IsBFnGK0_hM3Wa6tNz1mDT8do48KJozg1yQ/w640-h338/pqc_kem3.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.9] PQC KEM 개요(4)</span></span></div><p></p><p><span><br /></span></p><p><b><span style="color: #38761d; font-size: large;">d) Digital Signature</span></b></p><p><span>PQC 기반의 서명/검증 알고리즘은 아래 그림으로 표현 가능한데, 서명/검증 절차를 간략히 요약해 보면 다음과 같다.</span></p><div style="text-align: left;"><span><b>(1)</b> Alice(Initiator)는 서명용 Key 쌍 즉 (pk, sk)를 하나 생성한 후, message M과 sk(secret key)를 이용하여 서명 값 sig를 생성한다.<br /></span><span><b>(2) </b>Alice는 (1)에서 생성한 sig 값과 더불어 pk(public key) 및 message M을 Bob(Responder)에게 전달한다.<br /></span><span><b>(3) </b>Alice로 부터 pk, sig, M을 수신한 Bob(Reponder)는 Verify 함수를 통해 서명 값을 검증해 낸다. 당연한 거지만 서명을 검증하는 verify 함수 내부는 PQC 알고리즘에 따라 서로 차이가 난다.<br /></span><span><b>(4) </b>Verify 결과 검증에 실패로 판단된 경우는 Alice를 신뢰할 수 없게 되며, 검증에 성공할 경우는 이후 통신을 이어나가게 된다.</span></div><p><span><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMBuDCiNMubi-vMb5-QRPhuO7v2An4fxgFwPdXX4Gn3cMH9yDO4qfblAffIwnVkgtGP-Vb9qj4TbjrSbp979Kw3JzmC-VAqEh8lU0pE5Vjc9rVsyDge8xQS_nW9nJWjkz4EuGdjrOwMx1GwaYXxTqaVtN9xodbXRjb2BfedrJp5ntEhXUic5dQnVuqFA/s667/pqc_ds.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="354" data-original-width="667" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMBuDCiNMubi-vMb5-QRPhuO7v2An4fxgFwPdXX4Gn3cMH9yDO4qfblAffIwnVkgtGP-Vb9qj4TbjrSbp979Kw3JzmC-VAqEh8lU0pE5Vjc9rVsyDge8xQS_nW9nJWjkz4EuGdjrOwMx1GwaYXxTqaVtN9xodbXRjb2BfedrJp5ntEhXUic5dQnVuqFA/w640-h340/pqc_ds.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.10] PQC Digital Signature 개요(1)</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito; text-align: left;"><span>서명 알고리즘은 KEM 보다는 난이도가 있다. 아래 몇장의 그림은 digital 서명의 탄생(?) 원리와 동작 방식을 정리한 것으로, PQC 알고리즘의 경우도 내부 동작 방식에 차이가 있을 뿐 기본 원리는 동일하다고 말할 수 있다.</span></span></div><div class="separator" style="clear: both; text-align: justify;"><span><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv5msCTcn_aKUT93CbEf3OWavbO7SZIQ8i6nXSDmyhWGwPI9-vbZokSx5oX_VZK9NJBRRJeYZ9dDxd8qyRvX177BE7JJ8CbBbHLhaE2eEGEh5DeCKOexqgi53_Nr4VDMlBIMBpmDXroawhK1MhAUVXoumvHme6z9_IJjV19gjj-2Fs3_9yNCBJBQWOxQ/s989/pqc_digital_signature0.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="460" data-original-width="989" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv5msCTcn_aKUT93CbEf3OWavbO7SZIQ8i6nXSDmyhWGwPI9-vbZokSx5oX_VZK9NJBRRJeYZ9dDxd8qyRvX177BE7JJ8CbBbHLhaE2eEGEh5DeCKOexqgi53_Nr4VDMlBIMBpmDXroawhK1MhAUVXoumvHme6z9_IJjV19gjj-2Fs3_9yNCBJBQWOxQ/w640-h298/pqc_digital_signature0.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.11] Digital Signature 개요(1) - 영지식 증명</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy8N_OWJjVDXqSeg4BqrB3uZ_CuD6rsYAv0ZIvDw8r3Bvh9bHkN_t6qH66K1LycqWqJkgtam296p8W2uDoTQjygzLYvh9YJ002V5smBjg9MbK1a6DgLj8hxYGkzYIS7MOdi-dpfCQNqGxSvhIuMO6FTU-72BApUYiqXNccuF_4V8cF9yVaL_alQUAjZA/s936/pqc_digital_signature1.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="474" data-original-width="936" height="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy8N_OWJjVDXqSeg4BqrB3uZ_CuD6rsYAv0ZIvDw8r3Bvh9bHkN_t6qH66K1LycqWqJkgtam296p8W2uDoTQjygzLYvh9YJ002V5smBjg9MbK1a6DgLj8hxYGkzYIS7MOdi-dpfCQNqGxSvhIuMO6FTU-72BApUYiqXNccuF_4V8cF9yVaL_alQUAjZA/w640-h324/pqc_digital_signature1.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.12] Digital Signature 개요(2) - Fiat-Shamir Heuristic 기반의 서명 알고리즘</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjut8ze8caQXk4m3uxL1sQoQdGM1F11BVyYy1iihfp2YmrWp4EvX3-WvDsIBJZpCjHoNKSSdUF9cTaIr2DD7sJCRnVXFJyDzrB6N5G4i4CONupU5P9KzDp7sGZbJnY8e9JBXwMIk9uwpA-GuL0HodppJwekHEEZMH51YVRpLbE48akpMbiyWtnCOM32QQ/s812/pqc_digital_signature3.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="453" data-original-width="812" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjut8ze8caQXk4m3uxL1sQoQdGM1F11BVyYy1iihfp2YmrWp4EvX3-WvDsIBJZpCjHoNKSSdUF9cTaIr2DD7sJCRnVXFJyDzrB6N5G4i4CONupU5P9KzDp7sGZbJnY8e9JBXwMIk9uwpA-GuL0HodppJwekHEEZMH51YVRpLbE48akpMbiyWtnCOM32QQ/w640-h358/pqc_digital_signature3.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.13] Digital Signature 개요(3) - DSA 서명/검증 알고리즘</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjXbdFsYnGj5PwY7I12AKGSRdSok1dKRm-PQH17jYPlzSEm7G4_S27H0Vw1NJD-cdIf6YUrfNg_8NLw46x_lVpGT8yqS8ypp_t2c9BztFhUSJdJ19p2Hb5-8T6tHI7DOaF3l0bjfveCo5gC61yKjN-trTjgmbeLl0tyCPuNXM-BVxOp_R3zxG6qMPbiA/s814/pqc_digital_signature4.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="476" data-original-width="814" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjXbdFsYnGj5PwY7I12AKGSRdSok1dKRm-PQH17jYPlzSEm7G4_S27H0Vw1NJD-cdIf6YUrfNg_8NLw46x_lVpGT8yqS8ypp_t2c9BztFhUSJdJ19p2Hb5-8T6tHI7DOaF3l0bjfveCo5gC61yKjN-trTjgmbeLl0tyCPuNXM-BVxOp_R3zxG6qMPbiA/w640-h374/pqc_digital_signature4.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.14] PQC CRYSTALS Dilithium(1)</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV4pGSCByRSbYDf69dS-rU27j0LufB2DjrssjsSEYTEf-1VTGsxWdMqmR6izJMYleTXc-kq5EvIeFqmVUyDdAGCUZeHRsQpgUwbSSdF19SdpNyLB7gkfTslYOo0lYozO4lO7l1Qb3vLA8b1UruhSa8J4ZrPcP1x8YQZzaa_bPy7KCayNeX2ZH0HnTeeA/s988/pqc_digital_signature5.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="480" data-original-width="988" height="310" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgV4pGSCByRSbYDf69dS-rU27j0LufB2DjrssjsSEYTEf-1VTGsxWdMqmR6izJMYleTXc-kq5EvIeFqmVUyDdAGCUZeHRsQpgUwbSSdF19SdpNyLB7gkfTslYOo0lYozO4lO7l1Qb3vLA8b1UruhSa8J4ZrPcP1x8YQZzaa_bPy7KCayNeX2ZH0HnTeeA/w640-h310/pqc_digital_signature5.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span>[그림 4.15] </span></span><span style="font-family: Nunito; text-align: left;">PQC CRYSTALS Dilithium(2)</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito; text-align: left;"><span style="color: #b45f06;">참고: CRYSTALS Dilithium 같은 알고리즘 코드를 그냥 무턱대고 들여다 봐서는 당췌 이해가 가질 않는다. 사전에 동작 원리를 이해하기 위한 노력이 선행되어야 한다.</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span><br /></span></span></div><p><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">e) PQC 관련 open source 모음</span></b></p><p><span style="font-family: Nunito;">PQC 관련 open source는 인터넷에서 쉽게 찾아볼 수 있는데, 그 중에서도 나름 의미가 있는 몇가지를 하나로 정리해 보았다.</span></p><div style="text-align: center;"><div style="text-align: left;"><b style="font-family: Nunito;"><span style="color: #674ea7;">[1] PQClean</span></b></div><span style="font-family: Nunito;"><a href="https://github.com/PQClean/PQClean">https://github.com/PQClean/PQClean</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/PQClean/PQClean"><br /><div style="text-align: left;"><b><span style="color: #674ea7;">[2] Open Quantum Safe</span></b></div></a></span><span style="font-family: Nunito;"><a href="https://openquantumsafe.org/">https://openquantumsafe.org/</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://openquantumsafe.org/"><br /><div style="text-align: left;"><b><span style="color: #674ea7;">[3] mupq</span></b></div></a></span><span style="font-family: Nunito;"><a href="https://github.com/mupq/pqm4">https://github.com/mupq/pqm4<br /></a></span><span style="font-family: Nunito;"><a href="https://github.com/mupq/pqm3">https://github.com/mupq/pqm3<br /></a></span><span style="font-family: Nunito;"><a href="https://github.com/mupq/pqriscv">https://github.com/mupq/pqriscv</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/mupq/pqriscv"><br /><div style="text-align: left;"><b><span style="color: #674ea7;">[4] pq-crystals</span></b></div></a></span><a href="https://cryptojedi.org/crypto/index.shtml"><span>https://cryptojedi.org/crypto/index.shtml</span></a></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/pq-crystals/kyber">https://github.com/pq-crystals/kyber</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/pq-crystals/dilithium">https://github.com/pq-crystals/dilithium</a></span></div><div style="text-align: left;"><span style="color: #674ea7; font-family: Nunito;"><b>[5] 기타</b></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://cryptojedi.org/crypto/index.shtml">https://cryptojedi.org/crypto/index.shtml</a></span></div><p><br /></p><p><b style="color: #3d85c6; font-family: Nunito;"><span style="font-size: x-large;">5. PQC 기반 WireGuard VPN Router 만들기</span></b></p><p><span style="font-family: Nunito;"><a href="https://www.wireguard.com/">WireGuard</a>와 관련해서는 필자의 다른 <a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">posting</a>을 통해 이미 몇차례 소개한 바 있다. </span></p><div style="text-align: center;"><span><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/09/wireguard-vpn.html<br /></a></span><a href="https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html">https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html</a><span style="font-family: Nunito;"><br /></span></span></div><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">이번 장에서는 PQC 알고리즘을 WireGuard와 접목하는 방법(일명 PQ-WireGuard)에 관하여 소개하고, 이를 이용하여 Orange Pi를 VPN router로 변모시키는 과정을 소개하고자 한다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4revk7w-69bNDb2qXL80Pe4ZgY_k9MpESGfKtKzkaB0HXW5GI6YqVVzsXl1pDxBOXqjgOiG5fOw-_56qiKsrjf5sYat1OuOxcv13L6qKfCv6PSxbu9lofjrR8gzC-JiT3Md7CdR5A6niuaCpKjSWna9Ft2pBVXeRN3ftpkwY4dm85cidClbZQey5XlQ/s943/tiny_pqc_router.png" style="margin-left: 1em; margin-right: 1em;"><span><img border="0" data-original-height="489" data-original-width="943" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4revk7w-69bNDb2qXL80Pe4ZgY_k9MpESGfKtKzkaB0HXW5GI6YqVVzsXl1pDxBOXqjgOiG5fOw-_56qiKsrjf5sYat1OuOxcv13L6qKfCv6PSxbu9lofjrR8gzC-JiT3Md7CdR5A6niuaCpKjSWna9Ft2pBVXeRN3ftpkwY4dm85cidClbZQey5XlQ/w640-h333/tiny_pqc_router.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span>[그림 5.1] PQC 기반의 Tiny VPN Router</span></div><div class="separator" style="clear: both; text-align: center;"><span><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b style="color: #38761d;"><span style="font-size: large;">a) Kernel code로 구현한 pq-wireguard 소개</span><br /></b></span><span style="font-family: Nunito;">이 절에서는 kernel 기반으로 구현한 pq-wireguard를 Orange Pi L1 Plus LTS에서 동작시키는 방법을 소개하고자 한다. 여기에서 소개하는 내용은 아래 논문의 내용을 기초로 하였다.</span></div><p style="text-align: center;"><span style="color: #b45f06; font-family: Nunito;"><b>Post-quantum WireGuard</b></span></p><p style="text-align: center;"><span style="font-family: Nunito;"><span style="font-family: "Noto Sans CJK KR";"><a href="https://eprint.iacr.org/2020/379.pdf">https://eprint.iacr.org/2020/379.pdf</a></span></span></p><p style="text-align: center;"><span style="font-family: Nunito;"></span></p><div style="text-align: center;"><span><a href="https://cryptojedi.org/peter/data/zitis-20211025.pdf">https://cryptojedi.org/peter/data/zitis-20211025.pdf</a></span></div><div><br /></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">PQ-Wireguard를 이해하기 위해서는 먼저 Wireguard handshaking(a.k.a Noise protocol)을 제대로 이해할 필요가 있다. </span><span style="font-family: Nunito;"><b>Wireguard handshaking</b>은 아래 그림에 표현되어 있는 것과 같이, <b>4번의 ECDH 수행 과정</b>이라고 말할 수 있다. 4번의 ECDH를 위해서는 Long-term curve25519 키 쌍과, 2분 간격으로 반복 생성되는 Ephemeral curve25519 키 쌍이 각각 필요하다. (이미 알고 있는 것 처럼) Long-term 키 쌍 중 public key 부분은 사전에 미리 교환되어 있어야만 한다. </span></div><div><span style="color: #e69138; font-family: Nunito;">참고: Wireguard는 인증서 없이 간접적인 방법(Implicit method)으로 상호 인증을 수행하는 protocol이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheBpgKo0eEfWmNJ9OL5Y2J8SME-I2AE0YgtzjF-ZHG6JXSnVr5ToMdy2HVvGSwEGoqvv_vJ071QLpycXRGc4iScUT4wjeOLu71ephmHPmRvX-qcqfLYgS7iuWHD2oPeii4XVgsvcQkL_pDNNsGPg2W4HYFW4sRIVsm3jo_692_zGG6QkuEBXnnVJgngA/s1257/wireguard_noise_handshaking.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="649" data-original-width="1257" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheBpgKo0eEfWmNJ9OL5Y2J8SME-I2AE0YgtzjF-ZHG6JXSnVr5ToMdy2HVvGSwEGoqvv_vJ071QLpycXRGc4iScUT4wjeOLu71ephmHPmRvX-qcqfLYgS7iuWHD2oPeii4XVgsvcQkL_pDNNsGPg2W4HYFW4sRIVsm3jo_692_zGG6QkuEBXnnVJgngA/w640-h330/wireguard_noise_handshaking.PNG" width="640" /></a></div></div><div style="text-align: center;"><span style="font-family: Nunito;">[그림 5.2] Wireguard handshaking 과정</span></div><div><br /></div><div><span style="font-family: Nunito;">한편, PQ-WireGuard는 ECDH를 KEM으로 변경한 protocol로 Long-term ECDH의 경우는 Classic McEliece 기반의 KEM으로, Ephemeral ECDH의 경우는 Saber(정확히는 Tweaked Saber)로 교체하였다고 보면 된다. </span><span style="font-family: Nunito;">각각의 내용을 요약해 보면 다음과 같다.</span></div><div><div class="separator" style="clear: both; text-align: center;"><p style="text-align: left;"></p></div><div style="background-color: white; color: #222222; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;">• <span style="color: black; font-weight: bold;">Long-term</span><span style="color: black;"> IND-CCA-secure </span><span style="color: black; font-weight: bold;">KEM</span><span style="color: black;"> : </span><span style="color: #0070c0; font-weight: bold;">Classic McEliece</span></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i><span style="color: #0070c0;"><b> - </b></span>코드 기반 암호 알고리즘</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - NIST PQC 후보 중 Ciphertext의 길이가 가장 작음(WireGuard Handshaking에 사용되므로 중요)</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - Public key size는 매우 크나, 사전에 전달된다면 크게 문제 될 것 없음.</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - Key 생성 시간이 오래 걸리지만, 역시 처음에 한번 발생하므로 역시 크게 문제가 안됨.</i></span></div><div style="background-color: white; color: #222222; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;">• <span style="color: black; font-weight: bold;">Ephemeral </span><span style="color: black;">IND-CPA-secure </span><span style="color: black; font-weight: bold;">KEM</span><span style="color: black;">: </span><span style="color: #c00000; font-weight: bold;">Tweaked Saber</span></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - 격자 기반(LWR) 암호 알고리즘</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - WireGuard는 2분 간격으로 키 생성(Ephemeral key)을 해야 하므로 빠른 알고리즘을 요구함.</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - Packet fragmentation 이 일어나지 않도록 public key size <= 928 bytes, ciphertext <= 984 bytes이어야 함(IPv6 packet 기준)</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - 1-RTT 유지 위해 중요</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - Level 3 후보군에서 선택</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - 특허 문제가 없어야 함</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="font-family: Nunito;"><i> - Tweaked (smaller, more lightweight) Saber</i></span></div><div style="background-color: white; line-height: 19.5px; margin-bottom: 0pt; margin-left: 0.25in; margin-top: 10pt; unicode-bidi: embed;"><span style="color: #e69138; font-family: Nunito;"><i>참고: 1-RTT는 보장할 수 없지만, Tweaked Saber를 CRYSTALS Kyber로 바꿔 보는 것도 좋을 듯 하다.</i></span></div><p></p><p><span style="font-family: Nunito;">_________________________________________________________________________________</span></p><p></p></div><div><br /></div><div><span style="font-family: Nunito;">아래 그림에서 보라색으로 표시된 부분이 Wireguard protocol에 PQC 알고리즘을 적용한 부분이 되겠다.</span></div><div><br /></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipSQdBamKROIU0sAGDlxm0QP-BIVaijfoYD7NlN5AspQuLsxwLJrYoB-ZIqtE8cCHL6lj_9X6FyiTs4hCOrXi9GZta38-AUYd82IfqBOJGwjt-9dxu35hWX8LwrgT2vo0K49yyPqO7Rekqtnr3rkAfrvOfSrGGj5ENxzIaH36HxUY88RK-6PbJn8YC7Q/s952/pq-wireguard_handshake.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="692" data-original-width="952" height="466" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipSQdBamKROIU0sAGDlxm0QP-BIVaijfoYD7NlN5AspQuLsxwLJrYoB-ZIqtE8cCHL6lj_9X6FyiTs4hCOrXi9GZta38-AUYd82IfqBOJGwjt-9dxu35hWX8LwrgT2vo0K49yyPqO7Rekqtnr3rkAfrvOfSrGGj5ENxzIaH36HxUY88RK-6PbJn8YC7Q/w640-h466/pq-wireguard_handshake.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtdsA-anSMe3ihCpvDulo6afLl0T-ALBqY3jOuf1HN0b0hSpgeBiV9kfNyDXyXbDGgjM9Lhe8Q4hYyPJ0MYEof3U-x_Gt3psVhMeofq6MMzZ_tqvENMUJyJlPPlw2DN0VNQ3pqCJjB5vet7hITgHsmruiSUgypJTcMoLC-kBBSYYi42UDAlO6v6rQGDA/s944/pq-wireguard_hanshake2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="322" data-original-width="944" height="218" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtdsA-anSMe3ihCpvDulo6afLl0T-ALBqY3jOuf1HN0b0hSpgeBiV9kfNyDXyXbDGgjM9Lhe8Q4hYyPJ0MYEof3U-x_Gt3psVhMeofq6MMzZ_tqvENMUJyJlPPlw2DN0VNQ3pqCJjB5vet7hITgHsmruiSUgypJTcMoLC-kBBSYYi42UDAlO6v6rQGDA/w640-h218/pq-wireguard_hanshake2.png" width="640" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 5.3] PQ-Wireguard Handshaking 과정</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p><span style="font-family: Nunito;">지금부터는 아래와 같은 네트워크 구성에서 Orange Pi와 AWS EC2 각각에 PQ-WireGuard를 올리는 과정을 소개하도록 하겠다.</span></p><p style="text-align: center;"><b style="background-color: #d9ead3;">PC(notebook) => Orange Pi L1 Plus LTS(wg0:10.0.0.5) => Internet <= AWS EC2(wg0:10.0.0.2)</b></p><div style="text-align: left;"><b><span style="color: #b45f06; font-size: medium;"><br /></span></b></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">b) Orange Pi 위에 PQ-Wireguard 올리기</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">아래 내용은 Ubuntu 18.04 or 20.04 환경을 기준으로 정리한 것이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div><b><span style="color: #a64d79; font-family: Nunito;"><비 x86 machine에의 porting 전략></span></b></div><div><span style="font-family: Nunito;">[1] mceliece code는 x86_64용 avx2 환경에 최적화되어 있으니, PQClean code로 교체하자.</span></div><div><i><span style="font-family: Nunito;"> - Avx2 code 는 모두 제거하자 (mc_buf 관련 코드는 제거 )</span></i></div><div><i><span style="font-family: Nunito;"> - User space 용 C header 는 kernel porting 시 대부분 제거되어야 함 .</span></i></div><div><i><span style="font-family: Nunito;"> - Kbuild 파일 중, 사용하지 않는 파일은 모두 제거하자 .</span></i></div><div><span style="font-family: Nunito;">[2] mceliece code는 wg tool code에도 포함되어 있음.</span></div><div><i><span style="font-family: Nunito;"> - PQClean code로 교체하자 . Kernel code와는 달리 거의 대부분의 PQClean code 사용 가능.</span></i></div><div><span style="font-family: Nunito;">[3] ephemeral code(saber)는 대부분 그대로 사용하되, fips202.[ch]는 PQClean(common 폴더)의 것을 사용하자.</span></div><div><span style="font-family: Nunito;">[4] kernel build 시, -Wframe-larger-than=2048 관련 warning 수정 [매우 중요]</span></div><div><i><span style="font-family: Nunito;"> - Stack 에 buffer 크기가 2048 이상을 사용하는 함수는 모두 kmalloc으로 수정하자 . 이걸 수정하지 않으면 system이 뻗어 버리게 된다 .</span></i></div><div><span style="font-family: Nunito;">[5] Noise handshaking code (noise.c) 중 mceliece code 호출 부분은 새로 porting한 PQClean 함수로 적절히 교체하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div></div><div style="text-align: left;"><b><span style="color: #38761d; font-family: Nunito;">[wireguard.ko build 하기]</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>cd pqwireguard-tiny/WireGuard/src</b><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>vi Makefile</b></span></div><div style="text-align: left;"><div><span style="font-family: Nunito;">..</span></div><div><span style="font-family: Nunito;">KERNELDIR =YOUR_PATH/<b>openwrt/build_dir/target-aarch64_generic_musl/linux-rockchip_armv8/linux-5.4.179</b></span></div><div><span style="font-family: Nunito;">..</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>make clean; make</b></span></div><div><div><span style="font-family: Nunito;">$ ls -l wireguard.ko</span></div><div><span style="font-family: Nunito;">-rw-r--r-- 1 pi pi 333336 May 8 09:35 <b>wireguard.ko </b><= for ARM aarch64</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ ls -l tools/wg</span></div><div><span style="font-family: Nunito;">-rwxr-xr-x 1 pi pi 152112 May 8 09:35 <b>tools/wg </b><= for x86_64</span></div></div><div><span style="color: #e69138; font-family: Nunito;">참고: wg tool에 대한 Makefile을 수정하지 않고 build했으므로, 일단은 x86_64용 binary가 만들어진다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><b><span style="color: #38761d; font-family: Nunito;">[libmnl build 하기]</span></b></div><div><div><span style="font-family: Nunito;">예전 wg tool은 libmnl을 사용한다. 따라서 libmnl을 download 받아 cross-compile을 해 두어야 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>export ARCH=arm64</b></span></div><div><span style="font-family: Nunito;">$ <b>export STAGING_DIR=YOUR_PATH/openwrt/staging_dir</b></span></div><div><span style="font-family: Nunito;">$ <b>export PATH=YOUR_PATH/openwrt/staging_dir/toolchain-aarch64_generic_gcc-8.4.0_musl/bin:$PATH</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>git clone git://git.netfilter.org/libmnl</b></span></div><div><span style="font-family: Nunito;">$ <b>cd libmnl/</b></span></div><div><span style="font-family: Nunito;">$ <b>mkdir output</b></span></div><div><span style="font-family: Nunito;">$ <b>./autogen.sh</b></span></div><div><span style="font-family: Nunito;">$ <b>./configure --host=aarch64-openwrt-linux-musl --enable-shared --prefix=$(pwd)/output</b></span></div><div><span style="font-family: Nunito;">$ <b>make</b></span></div><div><span style="font-family: Nunito;">$ <b>make install</b></span></div></div><div><div><span style="font-family: Nunito;">$ cd output/lib</span></div><div><span style="font-family: Nunito;">$ <b>file libmnl.so.0.2.0</b></span></div><div><span style="font-family: Nunito;">libmnl.so.0.2.0: ELF 64-bit LSB shared object, <b>ARM aarch64</b>, version 1 (SYSV), dynamically linked, with debug_info, not stripped</span></div></div><div><span style="font-family: Nunito;"><br /></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #38761d;">[wg tool build 다시 하기]</span><br /></b>$ cd pqwireguard-tiny/WireGuard/src/tools<br />$ <b>vi Makefile<br /></b>..<br />CFLAGS += -IYOUR_PATH/pqwireguard-tiny/libmnl/output/include<br />LDLIBS += -LYOUR_PATH/pqwireguard-tiny/libmnl/output/lib -lmnl</span></div><div style="text-align: left;"><span style="font-family: Nunito;">..<br />CC := aarch64-openwrt-linux-musl-gcc<br />LD := aarch64-openwrt-linux-musl-ld<br />..</span></div><div style="text-align: left;"><span style="font-family: Nunito;">~</span></div><p><span style="font-family: Nunito;">$ cd ..</span></p><p><span style="font-family: Nunito;">$ <b>make clean; make</b></span></p><p><span style="font-family: Nunito;">$ <b>file tools/wg </b></span></p><p><span style="font-family: Nunito;">tools/wg: ELF 64-bit LSB executable, <b>ARM aarch64</b>, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, with debug_info, not stripped</span></p><div style="text-align: left;"><span style="font-family: Nunito;">자, 이번에는 aarch64용으로 제대로 build가 되었다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /><b><span style="color: #38761d;">[target board에 wireguard binary 복사하기]</span></b><br />앞서 build 한 wireguard.ko, wg 및 libmnl.so 등을 target board로 복사(scp 이용)하도록 한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">root@OpenWrt:~/workspace/pq-wireguard# ls -al<br />drwxr-xr-x 3 root root 4096 Jan 25 01:47 .<br />drwxr-xr-x 4 root root 4096 Jan 25 00:59 ..<br />-rwxr-xr-x 1 1000 1000 977 Jan 25 01:37 libmnl.la<br />lrwxrwxrwx 1 root root 15 Jan 25 01:44 libmnl.so -> libmnl.so.0.2.0<br />lrwxrwxrwx 1 root root 15 Jan 25 01:44 libmnl.so.0 -> libmnl.so.0.2.0<br />-rwxr-xr-x 1 1000 1000 79680 Jan 25 01:37 libmnl.so.0.2.0<br />-rwxr-xr-x 1 root root 222512 Jan 25 01:44 wg<br />-rw-r--r-- 1 root root 5604768 Jan 25 00:59 wireguard.ko<br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b><span style="color: #674ea7; font-family: Nunito; font-size: medium;"><Target board에서 pq-wireguard 돌려 보기></span></b></div><div style="text-align: left;"><span style="font-family: Nunito;"># cd ~/workspace/pq-wireguard</span></div><div style="text-align: left;"><span style="font-family: Nunito;"># <b>export LD_LIBRARY_PATH=/root/workspace/pq-wireguard:$LD_LIBRARY_PATH</b></span></div><div style="text-align: left;"><span style="color: #e69138; font-family: Nunito;">참고: wg tool을 돌리기 위해 libmnl.so가 필요하므로, ld library path 설정을 해 준다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"> </span></div><div style="text-align: left;"><div><span style="font-family: Nunito;">Orange pi용 openwrt 21.02에는 이미 wireguard가 포함되어 있다. 따라서 먼저 wireguard를 내려 주도록 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>rmmod wireguard</b></span></div><div><span style="font-family: Nunito;"># <b>rmmod libchacha20poly1305</b></span></div><div><span style="font-family: Nunito;"># <b>rmmod libblake2s</b></span></div><div><span style="color: #e69138; font-family: Nunito;">참고: 무엇을 내려 주어야 하는지는 wireguard를 내려 보면 알 수 있다. dmesg 명령을 통해 kernel error를 확인해 보기 바란다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>insmod ./wireguard.ko</b></span></div><div><div><span style="font-family: Nunito;">root@OpenWrt:/# [ 231.072485] wireguard: WireGuard 0.0.20191219-158-gfc6f000-dirty loaded. See www.wireguard.co.</span></div><div><span style="font-family: Nunito;">[ 231.073383] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;"># <b>mkdir wg_config; cd wg_config</b></span></div><div><span style="font-family: Nunito;"># <b>../wg mckey privkey pubkey</b></span></div><div><span style="font-family: Nunito;">root@OpenWrt:~/workspace/pq-wireguard/wg_config# ls -la</span></div><div><span style="font-family: Nunito;">drwxr-xr-x 2 root root 4096 Jan 25 01:48 .</span></div><div><span style="font-family: Nunito;">drwxr-xr-x 3 root root 4096 Jan 25 01:47 ..</span></div><div><span style="font-family: Nunito;">-rw-r--r-- 1 root root 13568 Jan 25 01:48 privkey</span></div><div><span style="font-family: Nunito;">-rw-r--r-- 1 root root 524160 Jan 25 01:48 pubkey</span></div></div><div><span style="color: #e69138; font-family: Nunito;">참고: McEliece privte/public key 쌍(level 3)을 하나 만든다. 이때 만들어진 pubkey는 수동으로 aws ec2에 전달해 주어야 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;"># <b>vi wg0.conf</b></span></div><div><span style="font-family: Nunito;">wg0.conf 파일을 열어 아래와 같이 interface 및 peer 설정을 해 주도록 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">[Interface] <span style="color: #e69138;">//내 interface(orangepi) 설정을 해 준다.</span></span></div><div><span style="font-family: Nunito;">McEliecePrivateKey = /root/workspace/pq-wireguard/wg_config/privkey</span></div><div><span style="font-family: Nunito;">McEliecePublicKey = /root/workspace/pq-wireguard/wg_config/pubkey</span></div><div><span style="font-family: Nunito;">ListenPort = 59760</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">[Peer] <span style="color: #e69138;"> //상대방(aws ec2) 설정을 해준다.</span></span></div><div><span style="font-family: Nunito;">McEliecePublicKey = /root/workspace/pq-wireguard/wg_config/awsec2/pubkey</span></div><div><span style="font-family: Nunito;">AllowedIPs = 10.0.0.2/32</span></div><div><span style="font-family: Nunito;">Endpoint = 13.124.203.0:51820</span></div><div><span style="font-family: Nunito;">~</span></div></div><div><span style="color: #e69138; font-family: Nunito;">참고: 사전에 미리 peer의 pubkey를 전달 받아, 위의 디렉토리에 맞게 복사해 두어야 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;"># <b>ip link add dev wg0 type wireguard</b></span></div><div><span style="font-family: Nunito;"># <b>ip addr add 10.0.0.5/24 dev wg0</b></span></div><div><span style="font-family: Nunito;"># <b>ip link set wg0 up</b></span></div><div><span style="font-family: Nunito;"># <b>../wg setconf wg0 /root/workspace/pq-wireguard/wg_config/wg0.conf</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>ifconfig wg0</b></span></div><div><span style="font-family: Nunito;"># <b>../wg show</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTRDj7aGzboN0t_O7tZ-7glhd2eeRW6WJgSByeupkpS1-Q2KHpEl_JHBsJfNAAFzrFAAtt4hpw6TF7_i6F37g38h_ueSDri571CCm9ngy7XNpsEZasgS-ivCrxwgzY3s3mCDZI-NzHryMymslnY0JEYvAQd_D1q9KtJiISPqKyzJwFX4-j125lu6yIVw/s767/orangepi_pqwireguard_show.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="470" data-original-width="767" height="392" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTRDj7aGzboN0t_O7tZ-7glhd2eeRW6WJgSByeupkpS1-Q2KHpEl_JHBsJfNAAFzrFAAtt4hpw6TF7_i6F37g38h_ueSDri571CCm9ngy7XNpsEZasgS-ivCrxwgzY3s3mCDZI-NzHryMymslnY0JEYvAQd_D1q9KtJiISPqKyzJwFX4-j125lu6yIVw/w640-h392/orangepi_pqwireguard_show.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.4] Orange Pi: pq-wireguard wg0 interface 명령 및 wg show 명령 실행 모습</span></div><div><span style="color: #e69138; font-family: Nunito;">참고: Wireguard와는 달리 PQ-Wireguard의 경우는 fingerprint라는 항목을 사용하여, 길이가 아주 길어 출력하기 힘든 Classic McEliece의 public key를 대신하고 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">root@OpenWrt:~/workspace/pq-wireguard/wg_config# <b>ping 10.0.0.2</b></span></div><div><span style="font-family: Nunito;">aws ec2의 vpn ip(10.0.0.2)로 ping을 시도한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">PING 10.0.0.2 (10.0.0.2): 56 data bytes</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.2: seq=0 ttl=64 time=4.888 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.2: seq=1 ttl=64 time=5.151 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.2: seq=2 ttl=64 time=5.240 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.2: seq=3 ttl=64 time=4.446 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.2: seq=4 ttl=64 time=4.524 ms</span></div><div><span style="font-family: Nunito;">^C</span></div><div><span style="font-family: Nunito;">--- 10.0.0.2 ping statistics ---</span></div><div><span style="font-family: Nunito;">5 packets transmitted, 5 packets received, 0% packet loss</span></div><div><span style="font-family: Nunito;">round-trip min/avg/max = 4.446/4.849/5.240 ms</span></div><div><span style="color: #e69138; font-family: Nunito;">참고: 위와 같이 ping이 성공하려면 aws ec2에도 적절한 설정이 이미 진행되어 있어야만 한다.</span></div><div><br /></div><div><b style="color: #38761d; font-family: Nunito;"><span style="font-size: large;">c) AWS EC2 위에 PQ-Wireguard 올리기</span></b></div><div><span style="font-family: Nunito;">아래 내용은 Ubuntu 18.04 환경을 기준으로 정리한 것이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><b><span style="color: #38761d; font-family: Nunito;">[kernel upgrade]</span></b></div><div><span style="font-family: Nunito;">$ <b>sudo apt --fix-broken install</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo apt-get dist-upgrade -y</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo reboot</b></span></div></div><div><div><span style="font-family: Nunito;">$ <b>uname -r</b></span></div><div><span style="font-family: Nunito;">5.4.0-1094-aws</span></div></div><div><span style="color: #e69138; font-family: Nunito;">참고: 위 과정은 필요시 최초 한번만 해 주면 된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">$ cd ~/pqwireguard/WireGuard/src</span></div><div><span style="font-family: Nunito;">$ <b>vi Makefile</b></span></div><div><span style="font-family: Nunito;"># SPDX-License-Identifier: GPL-2.0</span></div><div><span style="font-family: Nunito;">#</span></div><div><span style="font-family: Nunito;"># Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">KERNELRELEASE ?= $(shell uname -r)</span></div><div><span style="font-family: Nunito;">#KERNELDIR ?= /lib/modules/$(KERNELRELEASE)/build</span></div><div><span style="font-family: Nunito;">KERNELDIR = <span style="color: #b45f06;">/usr/src/linux-headers-5.4.0-1094-aws </span> # 이 부분을 OS version과 일치 시켜야 함.</span></div><div><span style="font-family: Nunito;">PREFIX ?= /usr</span></div><div><span style="font-family: Nunito;">DESTDIR ?=</span></div><div><span style="font-family: Nunito;">SRCDIR ?= $(PREFIX)/src</span></div><div><span style="font-family: Nunito;">DKMSDIR ?= $(SRCDIR)/wireguard</span></div><div><span style="font-family: Nunito;">DEPMOD ?= depmod</span></div><div><span style="font-family: Nunito;">~</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">$ <b>make clean; make</b></span></div><div><div><span style="font-family: Nunito;">$ ls -l wireguard.ko </span></div><div><span style="font-family: Nunito;">-rw-rw-r-- 1 ubuntu ubuntu 618304 Jan 25 04:03 <b>wireguard.ko</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>sudo cp tools/wg /usr/bin/wg.pqc</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">$ <b>sudo insmod ./wireguard.ko</b></span></div><div><span style="font-family: Nunito;">insmod: ERROR: could not insert module ./wireguard.ko: Invalid module format</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">[ 222.799577] wireguard: exports duplicate symbol blake2s_final (owned by kernel)</span></div><div><span style="font-family: Nunito;">[ 4796.090494] wireguard: exports duplicate symbol blake2s_update (owned by kernel)</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #e69138; font-family: Nunito;">참고: 위의 에러 message를 없애기 위해 crypto/zinc/blake2s/blake2s.c file의 blake2s_final(), blake2s_update() codes 부분을 강제로 막아 두었다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>sudo insmod ./wireguard.ko</b></span></div><div><span style="font-family: Nunito;">$ <b>lsmod | grep wireguard</b></span></div><div><span style="font-family: Nunito;">wireguard 503808 0</span></div><div><span style="font-family: Nunito;">ip6_udp_tunnel 16384 1 wireguard</span></div><div><span style="font-family: Nunito;">udp_tunnel 16384 1 wireguard</span></div></div><div><span style="font-family: Nunito;"><span style="color: #e69138;">참고: udp_tunnel, ip6_udp_tunnel이 구동되지 않았을 경우에는 "Unknown symbol udp_sock_create4"과 같은 에러가 발생하게 되니, </span><span style="color: #e69138;">wireguard를 구동하기 전에 각각에 대해 modprobe udp_tunnel; </span><span style="color: #e69138;">modprobe ip6_udp_tunnel</span><span style="color: #e69138;">해 주어야 한다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>wg.pqc mckey privkey pubkey</b></span></div><div><span style="color: #e69138; font-family: Nunito;">참고: 여기서 만든 McEliece public, private key를 /wg_config/awsec2에 복사한다.</span></div><div><b><span style="font-family: Nunito;"><br /></span></b></div><div><div><span style="font-family: Nunito;">$ <b>vi wg0.conf</b></span></div><div><span style="font-family: Nunito;">[Interface]</span></div><div><span style="font-family: Nunito;">McEliecePrivateKey = /wg_config/awsec2/privkey <span style="color: #e69138;">// 이 부분을 앞 단계에서 맞춰 주어야 함.</span></span></div><div><span style="font-family: Nunito;">McEliecePublicKey = /wg_config/awsec2/pubkey</span></div><div><span style="font-family: Nunito;">ListenPort = 51820</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">[Peer]</span></div><div><span style="font-family: Nunito;">McEliecePublicKey = /wg_config/orangepi/pubkey <span style="color: #e69138;">// 사전에 orange pi pubkey를 복사하여 이 곳에 위치시켜야 함.</span></span></div><div><span style="font-family: Nunito;">AllowedIPs = 10.0.0.5/32</span></div><div><span style="font-family: Nunito;">Endpoint = 0.0.0.0:0</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">$ <b>sudo ip link add dev wg0 type wireguard</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo ip addr add 10.0.0.2/24 dev wg0</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo ip link set wg0 up</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo /usr/bin/wg.pqc setconf wg0 ./wg0.conf</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$<b> ifconfig wg0</b></span></div><div><span style="font-family: Nunito;">$ <b>sudo wg.pqc show</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE5qNL3K5P-AlWx3dCJkXLMrwe0olIe60ne5W-zB2bMP0MBo1lz170WH23MQ57LIUK8YwgM-L73Cv6WrMPJq3dm65OeMaLpBh_tmoflafatN3eQrCDfbhO29tr8IE4RKc4NTBuFAEbX6Viagi0bOCBI8u27x-kD8G9v_e7oiriRhTc9geLjCvCGLG0iA/s827/aws_ec2_pqwireguard_show.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="468" data-original-width="827" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE5qNL3K5P-AlWx3dCJkXLMrwe0olIe60ne5W-zB2bMP0MBo1lz170WH23MQ57LIUK8YwgM-L73Cv6WrMPJq3dm65OeMaLpBh_tmoflafatN3eQrCDfbhO29tr8IE4RKc4NTBuFAEbX6Viagi0bOCBI8u27x-kD8G9v_e7oiriRhTc9geLjCvCGLG0iA/w640-h362/aws_ec2_pqwireguard_show.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.5] AWS EC2: pq-wireguard wg0 interface 명령 및 wg show 명령 실행 모습</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="font-family: Nunito;">$ <b>ping 10.0.0.5</b></span></div><div><span style="font-family: Nunito;">Orange pi vpn ip(10.0.0.5)로 ping을 시도한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">PING 10.0.0.5 (10.0.0.5) 56(84) bytes of data.</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.5: icmp_seq=1 ttl=64 time=4.53 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.5: icmp_seq=2 ttl=64 time=4.60 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.5: icmp_seq=3 ttl=64 time=4.61 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.5: icmp_seq=4 ttl=64 time=4.66 ms</span></div><div><span style="font-family: Nunito;">64 bytes from 10.0.0.5: icmp_seq=5 ttl=64 time=4.42 ms</span></div><div><span style="font-family: Nunito;">^C</span></div><div><span style="font-family: Nunito;">--- 10.0.0.5 ping statistics ---</span></div><div><span style="font-family: Nunito;">5 packets transmitted, 5 received, 0% packet loss, time 4007ms</span></div><div><span style="font-family: Nunito;">rtt min/avg/max/mdev = 4.428/4.570/4.669/0.102 ms</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">OK, 여기까지 상호간 ping이 되었다면 정상적으로 build 및 환경 설정이 이루어진 것이다.</span></div><div><br /></div><div>______________________________________________________</div><div><p><span style="background-color: #fff2cc; font-family: Nunito;"><b><여기서 잠깐></b></span></p><p><span style="font-family: Nunito;">PQ-Wireguard를 Go 언어로 구현(PQC 알고리즘: CRYSTALS Kyber512 탑재)한 project도 있다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/kudelskisecurity/pq-wireguard">https://github.com/kudelskisecurity/pq-wireguard</a></span></p><p style="text-align: center;"><a href="https://research.kudelskisecurity.com/2021/07/08/adding-quantum-resistance-to-wireguard/">https://research.kudelskisecurity.com/2021/07/08/adding-quantum-resistance-to-wireguard/</a></p><p style="text-align: center;"><span><br /></span></p><p><span style="color: #674ea7; font-family: Nunito;"><b><Ubuntu 18.04 desktop></b></span></p><p><span style="font-family: Nunito;">$ <b>go version</b></span></p><p><span style="font-family: Nunito;"></span></p><p><span style="font-family: Nunito;">go version go1.15 linux/amd64</span></p><p><span style="color: #b45f06; font-family: Nunito;">참고: go version이 최신 버젼이면 gvisor에서 에러가 발생하니 주의를 요한다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;">$ <b>git clone https://github.com/kudelskisecurity/pq-wireguard</b></span></p><p><span style="font-family: Nunito;">$ <b>pq-wireguard</b></span></p><p><span style="font-family: Nunito;">$ <b>go build</b></span></p><div><span style="font-family: Nunito;">$ ls -la<br /></span><span style="font-family: Nunito;">total 6488<br /></span><span style="font-family: Nunito;">drwxrwxr-x 12 chyi chyi 4096 1월 22 22:02 .<br /></span><span style="font-family: Nunito;">drwxrwxr-x 4 chyi chyi 4096 12월 26 16:04 ..<br /></span><span style="font-family: Nunito;">drwxrwxr-x 8 chyi chyi 4096 12월 26 16:04 .git<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 269 12월 26 16:04 .gitignore<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1023 12월 26 16:04 COPYING<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 866 12월 26 16:04 Makefile<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 3897 12월 26 16:04 README.md<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 conn<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 device<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 359 12월 26 16:04 go.mod<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 41400 12월 26 16:04 go.sum<br /></span><span style="font-family: Nunito;">drwxrwxr-x 3 chyi chyi 4096 12월 26 16:04 ipc<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 5267 12월 26 16:04 main.go<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1927 12월 26 16:04 main_windows.go<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 6640 12월 26 16:04 peerA.conf<br /></span><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 6639 12월 26 16:04 peerB.conf<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 ratelimiter<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 replay<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 rwcancel<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 tai64n<br /></span><span style="font-family: Nunito;">drwxrwxr-x 2 chyi chyi 4096 12월 26 16:04 tests<br /></span><span style="font-family: Nunito;">drwxrwxr-x 5 chyi chyi 4096 12월 26 16:04 tun<br /></span><span style="font-family: Nunito;">-rwxrwxr-x 1 chyi chyi 6498006 1월 22 22:02 <b>wireguard</b></span></div><p><span style="font-family: Nunito;"></span></p></div><div><br /></div><div><span style="font-family: Nunito;">이렇게 build한 pq wireguard를 구동시키는 방법은 위의 site에 자세히 소개되어 있으니, 확인해 보기 바란다.</span></div><div><span style="font-family: Nunito;">______________________________________________________</span></div><div><br /></div><div><br /></div><div><b style="color: #38761d; font-family: Nunito; font-size: x-large;">d) Orange Pi를 VPN Router로 만들기</b></div><div>자, 모든 것이 준비되었으니, 이제 부터는 Orange Pi를 VPN router로 만들어 보도록 하자. Orange Pi L1 Plus LTS는 태생부터 router로 동작하도록 설계되어 있다. 따라서 여기서 해 주어야 할 부분은 새로 추가된 vpn interface 관련 내용을 firewall에서 열어 주는 것 뿐이다.</div><div><br /></div><div># <b>netstat -nr</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4iIN7v1oVw8jGX27T3c_TmTheV0W7wqj4nVE_g7jSwye_nYdWUkD36GKgjXXRJ7DhldlaEEq_m8v-id0rIKVXYqdkW-jzuo8gduZCtpnc8to__hObC6R7j6VDDN6iODR-JLfoz3Uj9Ai_mErHGo9cTCicC9QvcBg3Y-dvTJuid1YhTQWSGznScfS_ZA/s740/orangepi_netstat_nr.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="164" data-original-width="740" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4iIN7v1oVw8jGX27T3c_TmTheV0W7wqj4nVE_g7jSwye_nYdWUkD36GKgjXXRJ7DhldlaEEq_m8v-id0rIKVXYqdkW-jzuo8gduZCtpnc8to__hObC6R7j6VDDN6iODR-JLfoz3Uj9Ai_mErHGo9cTCicC9QvcBg3Y-dvTJuid1YhTQWSGznScfS_ZA/w640-h142/orangepi_netstat_nr.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.6] 라우팅 테이블 확인</span></div><br /><div><span style="font-family: Nunito;"><b><span style="color: #990000;"><firewall 설정하기></span></b><br /></span></div><div><div><span style="font-family: Nunito;">SSH or console login 후, 아래 명령을 일일이 실행 준다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># Add the firewall zone</span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci add firewall zone</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].name='wg'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].input='ACCEPT'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].forward='ACCEPT'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].output='ACCEPT'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].masq='1'17</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].mtu_fix='1'</b></span></div><div><span style="font-family: Nunito;"># Add the WireGuard interface to it</span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@zone[-1].network='wg0'</b></span></div><div><span style="font-family: Nunito;"># Forward WAN and LAN traffic to/from it</span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci add firewall forwarding</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].src='wg'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].dest='wan'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci add firewall forwarding</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].src='wg'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].dest='lan'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci add firewall forwarding</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].src='lan'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].dest='wg'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci add firewall forwarding</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].src='wan'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci set firewall.@forwarding[-1].dest='wg'</b></span></div><div><span style="font-family: Nunito;">root@mango:~# <b>uci commit firewall</b></span></div><div><span style="font-family: Nunito;">root@mango:~#<b> /etc/init.d/firewall restart</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><b><span style="color: #990000; font-family: Nunito;"><LuCI에서 wg interface 만들기></span></b></div><div><span style="font-family: Nunito;">다음으로 webui에 login 후, Network => Interface 메뉴에서 wg0 interface를 하나 추가해 준다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_OjDZoYIK4HciUM_JEAIZWJWZaTxjGwxqYBSgSBsMgKF_y-O_r5XVYef1Gm2zLJwo1BQiUi386GU4CxZtUY485FzDPMwSatnGdKGifFBWvZutqMGYBGkA0OMVc-nANJ_KgFLBmdQJ_YIClGS84jWnhpj5oDwB21G5h_LqF4r3q2seTjjx_ukdNStd5A/s1142/orangepi_webui_wg0_interface.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="875" data-original-width="1142" height="490" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_OjDZoYIK4HciUM_JEAIZWJWZaTxjGwxqYBSgSBsMgKF_y-O_r5XVYef1Gm2zLJwo1BQiUi386GU4CxZtUY485FzDPMwSatnGdKGifFBWvZutqMGYBGkA0OMVc-nANJ_KgFLBmdQJ_YIClGS84jWnhpj5oDwB21G5h_LqF4r3q2seTjjx_ukdNStd5A/w640-h490/orangepi_webui_wg0_interface.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.7] webui에서 wg interface 생성 모습</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><b><span style="color: #990000; font-family: Nunito;"><firewall 설정 변경></span></b></div><div><span style="font-family: Nunito;">마지막으로 webui Network => Firewall 메뉴에서 Forward rule을 Accept로 변경해 준다. 이후 Save & Apply 버튼을 눌러 주도록 한다.</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTFXtBzduU1N8NEOYnRPuAnnHu5QyE5MBFcD4ns60B3A-50E4mmzbpJ26C8eK77WZAyDgTFqujY_Xs6ezJ4YnyYBykFtgtb3-vWoKvipcGPe5cWIAyV8wnsN8PyMUelxZQOKrNbIAgtriZMM30nNmNLs-NbgKdy9NQB29FTv66otGiRZfH8jDDpg8p8Q/s1131/orangepi_webui_firewall.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="954" data-original-width="1131" height="540" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTFXtBzduU1N8NEOYnRPuAnnHu5QyE5MBFcD4ns60B3A-50E4mmzbpJ26C8eK77WZAyDgTFqujY_Xs6ezJ4YnyYBykFtgtb3-vWoKvipcGPe5cWIAyV8wnsN8PyMUelxZQOKrNbIAgtriZMM30nNmNLs-NbgKdy9NQB29FTv66otGiRZfH8jDDpg8p8Q/w640-h540/orangepi_webui_firewall.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.8] webui에서 firewall 설정 변경</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><p><span style="font-family: Nunito;">자, 이제 모든 설정이 끝났다. 이 상태에서 내부망의 PC로 부터 AWS EC로 ping을 시도해 본다. 정상적으로 통신이 되는가 ?</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtM-KJTsEN8mwppQLawi0-pB3imPsukv4jJnARm5bZMu_pdLY7X53D2qYx2MevkytsNLtuECLQ0HtMz-K3TOM_ThIUEvbDpQZvLSKDOElVg5HzpQrMnw548ocsDPKOxfkkUT14k05FyNNgWgjpq6hd5sN8fNqZiTJPsW_WSMPavgho4OgCIpOC0PUAA/s573/orangepi_router.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="573" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrtM-KJTsEN8mwppQLawi0-pB3imPsukv4jJnARm5bZMu_pdLY7X53D2qYx2MevkytsNLtuECLQ0HtMz-K3TOM_ThIUEvbDpQZvLSKDOElVg5HzpQrMnw548ocsDPKOxfkkUT14k05FyNNgWgjpq6hd5sN8fNqZiTJPsW_WSMPavgho4OgCIpOC0PUAA/w400-h141/orangepi_router.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.9] 내부망의 PC에서 VPN peer로 ping 하는 모습</span></div><p></p><p><span style="font-family: Nunito;"><span style="text-align: center;"><br /></span></span></p><p style="text-align: left;"><span style="font-family: Nunito;">지금까지 Orange Pi L1 Plus LTS board를 가지고 크게 아래 2가지를 확인해 보았다.</span></p><p style="text-align: left;"><i><b><span style="color: #990000; font-family: Nunito;"> 1. i2c device driver 추가</span></b></i></p><p style="text-align: left;"><i><b><span style="color: #990000; font-family: Nunito;"> 2. PQ-Wireguard 기반 VPN router 설정</span></b></i></p><p style="text-align: left;"><span style="font-family: Nunito;">부족한 부분은 추후 다른 blog post를 통해 보강 예정이다. 끝까지 읽어 주셔서 감사드린다. 😎</span></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>6. References</b></span></p><div style="text-align: left;"><span><span style="font-family: Nunito;"><b>[1]</b> </span><a href="https://drive.google.com/drive/folders/1VLsrHLXRNGINbXcuxSsCtvX1430Pjmmt/OrangePi_R1_Plus_LTS_RK3328_User_Manual_v2.0.pdf" style="font-family: Nunito; text-align: center;"><span style="color: black;">OrangePi_R1_Plus_LTS_RK3328_User_Manual_v2.0.pdf</span><br /></a></span><div><span><span><b>[2]</b> https://rockchip.fr/RK3328%20datasheet%20V1.2.pdf<br /></span><span><b>[3]</b> Linux Driver Development for Embedded Processors 2nd edition, Alberto Liberal de los Rios<br /></span><span><b>[4]</b> https://www.friendlyelec.com/index.php?route=product/product&product_id=284</span></span></div><div><span><span><b>[5]</b> https://elinux.org/images/1/1e/I2C-SPI-ELC-2020.pdf</span></span></div><div><span><span><b>[6] </b>https://s3.amazonaws.com/files.douglas.stebila.ca/files/research/presentations/20230118-QuantumDays.pdf</span><br /></span></div><div><span><b>[7]</b> https://s3.amazonaws.com/files.douglas.stebila.ca/files/research/presentations/20220822-SAC-part1.pdf</span></div><div><span><b>[8] </b>https://csrc.nist.gov/News/2022/pqc-candidates-to-be-standardized-and-round-4</span></div><div><span><b>[9] </b>https://www.youtube.com/watch?v=FUb75AUXMvw&ab_channel=Chaos-WestTV</span></div><div><span><b>[10]</b> https://eprint.iacr.org/2020/379.pdf</span></div><div><span><b>[11]</b> https://cryptojedi.org/peter/data/zitis-20211025.pdf</span></div><div><span><b>[12]</b> https://csrc.nist.gov/CSRC/media/Presentations/pq-wireguard-we-did-it-again/images-media/session-5-raynal-pq-wireguard.pdf</span></div><div><b>[13]</b><span> CYSTALS-Kyber: a CCA-secure module-lattice-based KEM, Joppe Bos </span></div><div><span><div><b>[14]</b> CRYSTALS-Dilithium-April2018.pdf</div><div><b>[15]</b> https://cryptojedi.org/papers/dilithium-20170627.pdf</div><div><div><b>[16]</b> Active Implementation of End-to-End Post-Quantum Encryption,Anton Tutoveanu, University of Wollongong</div><div><b>[17]</b> https://www.youtube.com/watch?v=FUb75AUXMvw&ab_channel=Chaos-WestTV</div><div><b>[18]</b> https://www.youtube.com/watch?v=zsEj28SFyCs&ab_channel=MojtabaBishehNiasar</div><div><b>[19] </b>Lattice-based NIST Candidates - Abstractions and Ninja Tricks, Thomas Prest PQShield European Cyber Week</div></div></span></div><div><span><b>[20]</b> and Google~</span></div></div><p><span style="font-family: Nunito; font-size: medium;"><br /></span></p><p><span style="font-family: Nunito; font-size: medium;"><br /></span></p><p style="text-align: right;"><span style="color: #3d85c6; font-family: Nunito; font-size: large;"><b>Slowboot</b></span></p><p><span style="font-family: Nunito; font-size: medium;"><br /></span></p><p><span style="font-family: Nunito;"><br /></span></p></div><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br />Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0대한민국 경기도 수원시37.2635727 127.02860099.7821772627362833 91.872350900000015 64.744968137263712 162.1848509tag:blogger.com,1999:blog-6346200245600677355.post-74455782059611990182023-01-26T20:26:00.002+09:002023-01-28T21:26:26.868+09:00Raspberry Pi 4와 Zymbit Zymkey 4i 연동하기<p><span style="font-family: Nunito;">이번 시간에는 Raspberry Pi 4와 i2c 장치인 <a href="https://www.zymbit.com/zymkey/">Zymbit Zymkey 4i HSM</a>(Hardware Security Module)을 연동하는 내용을 다뤄 보고자 한다. 😎</span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyZ38RkxrCLmrEXtvU6MrMR2ZZmet5EXvVpV8Ui4MSlgA5emvbJVZ0gYv9O5Fm7Z-5mD8s-Cfe5Gs5QTVVwQS52LtLwGRmlkeYEnaiIbElvWGBJMOxGbLdG-pp3rEvY8Qw0bCdoJ8ez5MMjS3yetIbRmizikehc6NrUK7PJwmB5fatKjhH69bM9si6tg/s569/61LQAYnRF4L._AC_SX569_.jpg" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="410" data-original-width="569" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyZ38RkxrCLmrEXtvU6MrMR2ZZmet5EXvVpV8Ui4MSlgA5emvbJVZ0gYv9O5Fm7Z-5mD8s-Cfe5Gs5QTVVwQS52LtLwGRmlkeYEnaiIbElvWGBJMOxGbLdG-pp3rEvY8Qw0bCdoJ8ez5MMjS3yetIbRmizikehc6NrUK7PJwmB5fatKjhH69bM9si6tg/s320/61LQAYnRF4L._AC_SX569_.jpg" width="320" /></span></a></div><p></p><div style="text-align: left;"><br /></div><div style="text-align: center;"><span style="color: #ffa400; font-family: Nunito; font-size: large;"><b>i2c device + HSM(crypto chip)</b></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span><i><span style="font-family: Nunito;"><b>목차</b><br /></span><span style="font-family: Nunito;">1. Zymbit Zymkey4i HSM 디바이스 소개<br /></span><span style="font-family: Nunito;">2. Raspberry Pi4에 Zymkey4i 붙이기<br /></span><span style="font-family: Nunito;">3. Zymkey4i API 사용해 보기</span><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">4. References</span></i><span style="font-family: Nunito;"><br /><span style="color: #e69138;">Keyword: Zynkey4i, HSM, i2c</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><p style="text-align: left;"><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">1. Zymbit Zymkey4i HSM 디바이스 소개</span></b></p><p><span style="font-family: Nunito;">Zymbit Zymkey4i는 아래와 같은 용도로 사용되는 hardware security module이다. HSM이 무엇을 하는 것인지는 아래 site에 잘 설명되어 있으니, 한번 훑어 보시기 바란다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://blog.naver.com/PostView.nhn?blogId=mds_datasecurity&logNo=221950138311&parentCategoryNo=&categoryNo=36&viewDate=&isShowPopularPosts=false&from=postView">https://blog.naver.com/PostView.nhn?blogId=mds_datasecurity&logNo=221950138311&parentCategoryNo=&categoryNo=36&viewDate=&isShowPopularPosts=false&from=postView</a></span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW6oZn-RfdjxeBKh8lgY2e74aSW7ZVlAnbslAs5dep9OjKDRjvrMYdhod-pWyowJCJ1qC84aE3Px0Zlx-G5-NAwZl2Hr0Gv7vhTt_1iWXOd-4JAmYtx24A5aj6HiJNna6Wx8shYlsO3Sajd4byIMb1bP5mS8P1U9ZFN609DfwsWJoWIFZ8iLc54VwnHA/s1192/zymkey4i_overview.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="514" data-original-width="1192" height="277" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW6oZn-RfdjxeBKh8lgY2e74aSW7ZVlAnbslAs5dep9OjKDRjvrMYdhod-pWyowJCJ1qC84aE3Px0Zlx-G5-NAwZl2Hr0Gv7vhTt_1iWXOd-4JAmYtx24A5aj6HiJNna6Wx8shYlsO3Sajd4byIMb1bP5mS8P1U9ZFN609DfwsWJoWIFZ8iLc54VwnHA/w640-h277/zymkey4i_overview.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.1] Zymbit Zymkey4i 개요(1)</span></span></div><p></p><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7NPWkx0VBhH060Rp2r5HFv76zkRn0601gWp-nBShBNLuI2TF4yFXrUG7d_0aqvGATQmt4c2HTV9aI0ARK_f5wIXzm4m8vVehv3i3Jp4B8LD1P4czWCoPrY9hTpOAFkfW3LWOs_-5-6d56dBP9ICwHzLV64sZGf0Zo_AGGxCoErYURdelskGTe8bmsA/s1128/zymkey4i_overview2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="582" data-original-width="1128" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7NPWkx0VBhH060Rp2r5HFv76zkRn0601gWp-nBShBNLuI2TF4yFXrUG7d_0aqvGATQmt4c2HTV9aI0ARK_f5wIXzm4m8vVehv3i3Jp4B8LD1P4czWCoPrY9hTpOAFkfW3LWOs_-5-6d56dBP9ICwHzLV64sZGf0Zo_AGGxCoErYURdelskGTe8bmsA/w640-h330/zymkey4i_overview2.png" width="640" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.2] Zymbit Zymkey4i 개요(2)</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><p><span style="font-family: Nunito;">Zymkey4i는 Raspberry Pi 4와 i2c 통신을 한다. 따라서 Raspberry Pi 4에서는 i2c controller가 사용 가능하도록 enable되어 있어야만 한다.</span></p><p><span style="font-family: Nunito;"><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYjY_icpuOPB0o0Swazr-BI3VLZ7yJC0g9HPMqod41VDBaz0QchllqGJlFNwf92rrsfxQuyuo5SypnaFs6jKrvGP4M4wL2oG8W4yMoTs_S4Ug6IJPdpXM6DNGw6SaabpRR1YliyNrmvgejEZBTFHYzuePapWIDw0Rn8LXdqg94K9xZvhYx_tRpMhvNwg/s1678/ZK4-top-bottom.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1210" data-original-width="1678" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYjY_icpuOPB0o0Swazr-BI3VLZ7yJC0g9HPMqod41VDBaz0QchllqGJlFNwf92rrsfxQuyuo5SypnaFs6jKrvGP4M4wL2oG8W4yMoTs_S4Ug6IJPdpXM6DNGw6SaabpRR1YliyNrmvgejEZBTFHYzuePapWIDw0Rn8LXdqg94K9xZvhYx_tRpMhvNwg/w400-h289/ZK4-top-bottom.png" width="400" /></a></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span style="text-align: left;">[그림 1.3] Zymkey4i hardware(1)</span></span></div><p></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTzSaiEh13xOdfy-ugMOeLaoQBQJ5D0ou2IHhjbzuajIu2zXqtYxp58e-0Q8Y8E5ea4LqGCCr9Pdgzp5RXbz5R2y741jiQtiB6eQ-2FFIJOTSxl16rNKVzSVlmTuvhJsSM-Y1W2qQPckWI-sDHRRQYV7evKsICZwwfWMylXTP-lIKYjBnrWR6obZVD7w/s1106/ZK4-pinout.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="1106" data-original-width="928" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTzSaiEh13xOdfy-ugMOeLaoQBQJ5D0ou2IHhjbzuajIu2zXqtYxp58e-0Q8Y8E5ea4LqGCCr9Pdgzp5RXbz5R2y741jiQtiB6eQ-2FFIJOTSxl16rNKVzSVlmTuvhJsSM-Y1W2qQPckWI-sDHRRQYV7evKsICZwwfWMylXTP-lIKYjBnrWR6obZVD7w/w335-h400/ZK4-pinout.png" width="335" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.4] Zymkey4i hardware(2) - pinmap</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><p><span style="font-family: Nunito;">Zymkey4i는 <b><u>Microchip ATECC508A CryptoAuthentication chip</u></b>(이게 핵심이구먼 😍)을 기반으로 하고 있다.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpQrsOHdrJNGnBIDD5-ll4ulIo4gZvWOkUZSlfuZGtco6aOuP51pc7i_UXzkvHwAp8Ng8QvYBL-B-aW430C2SBbPgyOIiN_8HX3z6VRSlzFZeo75RSFEkZKMRH4YYClctHxRWgMvT1Z35BKFi42pAtspL0TfojvfVK_W32AdavsKjNTU7ZgN7QyOi7A/s802/ATECC508A-3BX-Regular.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="802" data-original-width="800" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpQrsOHdrJNGnBIDD5-ll4ulIo4gZvWOkUZSlfuZGtco6aOuP51pc7i_UXzkvHwAp8Ng8QvYBL-B-aW430C2SBbPgyOIiN_8HX3z6VRSlzFZeo75RSFEkZKMRH4YYClctHxRWgMvT1Z35BKFi42pAtspL0TfojvfVK_W32AdavsKjNTU7ZgN7QyOi7A/w199-h200/ATECC508A-3BX-Regular.jpg" width="199" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.5] Zymkey4i main MCU - microchip ATECC508A</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">Microchip ATECC508A CryptoAuthentication chip(ARM Cortex-M0 급) </span><span style="background-color: #f9f9f8; color: #333333; font-family: Nunito;">관련 datasheet는 참고 문헌 [6, 7]을 참고하기 바란다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #e69138;">참고: 국내 제품 중에 위 chip과 유사한 제품으로 <a href="http://www.ictk.com">ICTK Holdings</a> 사에서 개발한 PUF(Physically Unclonable Function) G3K가 있다. 😝</span></span></div><p></p><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;"><span style="font-family: "Noto Sans CJK KR";">__________________________________________________________</span></span></p><p><span style="color: #b45f06; font-family: Nunito;"><b style="background-color: #fff2cc;"><여기서 잠깐></b></span></p><div style="text-align: center;"><div style="text-align: justify;"><span style="font-family: Nunito;">그렇다면, Microchip ATECC508A를 직접 제어하는 i2c device driver source나 다른 example code는 없을까 ? 우선 </span><span style="font-family: Nunito;">Linux kernel source code를 뒤져 보니, 아래 코드가 보인다.</span></div><div style="text-align: justify;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;">https://github.com/torvalds/linux/blob/master/drivers/crypto/atmel-ecc.c</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /><div style="text-align: left;">좀 더 찾아 보니, 아래 site에 <span style="text-align: left;">Microchip ATECC508A 등을 사용하기 위한 다양 library와 example이 있다.</span></div><div style="text-align: left;"><span style="text-align: left;"><br /></span></div></span><span style="font-family: Nunito; font-size: medium;"><a href="https://github.com/MicrochipTech/cryptoauthlib"><b>https://github.com/MicrochipTech/cryptoauthlib</b></a></span></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS68DASO3dHMZ5VTY0XrZhpqECMOIP_v9Eif58SNA5e20LIMkCmNZ-dpl1nXFPi3doOo9_40Fx0fIo4foPR8INUCxtTYaeDH73CS_RRxhlbk_Q8V2Yt51pDhPwn266Ieq_yowylkvdeuhW-24JqcLEE9un7b1E6xa--hsuPA7o0E1hCnWd6lv8Cfo5aA/s1422/microchip_cryptoauthlib.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="946" data-original-width="1422" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhS68DASO3dHMZ5VTY0XrZhpqECMOIP_v9Eif58SNA5e20LIMkCmNZ-dpl1nXFPi3doOo9_40Fx0fIo4foPR8INUCxtTYaeDH73CS_RRxhlbk_Q8V2Yt51pDhPwn266Ieq_yowylkvdeuhW-24JqcLEE9un7b1E6xa--hsuPA7o0E1hCnWd6lv8Cfo5aA/w400-h266/microchip_cryptoauthlib.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.6] Microchip CryptoAuthLib github</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbvAFe_aObqDqP9V2qc2TOw_vNahV0UeumxyZdfMZRBp8K-wAOPKIRxU9q8brTFCh_pJz4CgaMJH4cmfrUDi-MWPFmw50LQGQzrzIaxLC8rZJ1liBaSYC8WDGTf59LCi92R2PvEGFKKJXyZIAPKcTTYTDXUjmMrjDewBdiTVZ3Ew4LviSYxiLKUt2qVA/s1280/220624-spg-diag-cryptoauthlib-block-diagram-5x7.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="913" data-original-width="1280" height="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbvAFe_aObqDqP9V2qc2TOw_vNahV0UeumxyZdfMZRBp8K-wAOPKIRxU9q8brTFCh_pJz4CgaMJH4cmfrUDi-MWPFmw50LQGQzrzIaxLC8rZJ1liBaSYC8WDGTf59LCi92R2PvEGFKKJXyZIAPKcTTYTDXUjmMrjDewBdiTVZ3Ew4LviSYxiLKUt2qVA/w640-h456/220624-spg-diag-cryptoauthlib-block-diagram-5x7.jpeg" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;">[그림 1.7] Microchip CryptoAuthLib library architecture [출처: 참고문헌 9]</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;">개발 보드도 판매한다. Hmm, 조금 비싼 것 같긴 한데, 그래도 한번 구매해서 사용해 보아야겠다 ㅋ.</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://www.microchip.com/en-us/products/security/trust-platform">https://www.microchip.com/en-us/products/security/trust-platform</a></span></div><span style="font-family: Nunito; text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0uYSrcX_OG1TIecM41hJEAmK1wfaTTOClSA6L5bn4rA8SOxZMcjtd7_zG9wVjI2HlE_1jaNSn41hU0-9tXIY-bBd_T3m9oTka1jt8_AyQFMZioPeZFoQQEAsZn0E7qnYzLE9Jo8Gprqn2kKp8du6xdiUmiRya4Eh7vWaiWLKJN9Uhi-yPdXnoFEOCgQ/s798/2179-170227-atmel-88ckscktsoic-xpro-conected.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="798" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0uYSrcX_OG1TIecM41hJEAmK1wfaTTOClSA6L5bn4rA8SOxZMcjtd7_zG9wVjI2HlE_1jaNSn41hU0-9tXIY-bBd_T3m9oTka1jt8_AyQFMZioPeZFoQQEAsZn0E7qnYzLE9Jo8Gprqn2kKp8du6xdiUmiRya4Eh7vWaiWLKJN9Uhi-yPdXnoFEOCgQ/s320/2179-170227-atmel-88ckscktsoic-xpro-conected.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.8] Microchip Cryptochip 관련 개발 board - </span></span><span style="color: #53575a; font-family: Nunito; text-align: left;">AT88CKSCKTSOIC-XPRO</span></div><span style="font-family: Nunito;"><div><span style="font-family: Nunito;"><br /></span></div><span style="color: #e69138;">참고: chip을 하나 만들었으면, 최소한 이런 정도의 내용은 구비되어 있어야 하지 않을까 ? 그래야 남들이 그 chip을 제대로 사용하지 ... 갑자기 반만을 </span>😂</span><p style="text-align: left;">__________________________________________________________</p><p><span style="font-family: Nunito;"><br /></span></p><p><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">2. Raspberry Pi4에 Zymkey4i 붙이기</span></b></p><p><span style="font-family: Nunito;">이번 장에서는 Zymjkey4i를 Raspberry Pi 4에 설치하는 과정을 소개하고자 한다. 이 장에서 소개하는 내용은 아래 site의 문서 내용을 기초로 하였다.</span></p><p style="text-align: center;"><a href="https://www.farnell.com/datasheets/2674017.pdf"><span style="font-family: Nunito;">https://www.farnell.com/datasheets/2674017.pdf</span></a></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zymbit.com/getting-started/zymkey4/quickstart/">https://docs.zymbit.com/getting-started/zymkey4/quickstart/</a></span></p><div><span style="font-family: Nunito;"><br /><b><Zymkey4i setup 절차 요약></b></span></div><div><span style="font-family: Nunito;">Zymkey4i는 아래와 같은 절차에 따라 h/w & s/w 설치 후, test program을 만들어 돌려 보면 된다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><dl style="background-color: white; box-sizing: border-box; margin-bottom: 1rem; margin-top: 0px;"><dt style="box-sizing: border-box; font-weight: 700;"><span style="font-family: Nunito;"><span style="color: #222222;">[1] Installing the hardware : </span><span style="color: #b45f06;">h/w device 장착</span></span></dt><dd style="box-sizing: border-box; color: #222222; margin-bottom: 0.5rem; margin-left: 0px; max-width: 80%;"><span style="font-family: Nunito;"><i>Install the battery on the Zymkey4, and connect it to the host single-board computer (SBC).</i></span></dd><dt style="box-sizing: border-box; font-weight: 700;"><span style="font-family: Nunito;"><span style="color: #222222;">[2] Establish an I<span style="box-sizing: border-box; line-height: 0; position: relative; top: -0.5em; vertical-align: baseline;">2</span>C connection : </span><span style="color: #b45f06;">raspberry pi 4 i2c 설정 enable</span></span></dt><dd style="box-sizing: border-box; color: #222222; margin-bottom: 0.5rem; margin-left: 0px; max-width: 80%;"><span style="font-family: Nunito;"><i>Enable the I<span style="box-sizing: border-box; line-height: 0; position: relative; top: -0.5em; vertical-align: baseline;">2</span>C bus on the host device in order to be able to communicate with the Zymkey.</i></span></dd><dt style="box-sizing: border-box; font-weight: 700;"><span style="font-family: Nunito;"><span style="color: #222222;">[3] Install the client software : </span><span style="color: #b45f06;">zymkey s/w package 설치</span></span></dt><dd style="box-sizing: border-box; color: #222222; margin-bottom: 0.5rem; margin-left: 0px; max-width: 80%;"><span style="font-family: Nunito;"><i>These utilities provided by Zymbit are necessary to interact with the hardware module.</i></span></dd><dt style="box-sizing: border-box; font-weight: 700;"><span style="font-family: Nunito;"><span style="color: #222222;">[4] Test the installation : </span><span style="color: #b45f06;">test program 시험</span></span></dt><dd style="box-sizing: border-box; color: #222222; margin-bottom: 0.5rem; margin-left: 0px; max-width: 80%;"><span style="font-family: Nunito;"><i>Your Zymkey is now temporarily bound to your SBC and ready for use in developer mode.</i></span></dd><div style="color: #222222;"><span style="font-family: Nunito;"><br /></span></div><div style="color: #222222;"><span style="font-family: Nunito;">위의 quickstart 문서에 설치 과정이 상세히 요약되어 있으니, 여기에서는 주요 부분만 언급하고 넘어가도록 하자.</span></div><div style="color: #222222;"><span style="font-family: Nunito;"><br /></span></div></dl></div><p><b><span style="color: #38761d; font-family: Nunito; font-size: large;">a) Zymkey4i h/w 장착하기</span></b></p><p><span style="font-family: Nunito;">아래와 같이 zymkey4i를 Raspberry 확장 pin(처음 10개)에 스르륵 연결한다(꽂는다는 표현이 맞겠다).</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBKK4SNKqQn-BRzPxGSvlpcRZWQ4C-7kDVM643YFr3kr3sVUIA6OTAPJfK8KpXj5V22we7bHBXMprBiMR444AjL6d9f4VXywx-2AMgXLrSBNpjKo-MTQH7eauP6hjXdJrKbDLlrN6cqbFlkgT-emdRA98dk2jose2SXagV54s_fRU3nKU-zfxesMrCvA/s1304/ZK4-hw-install-1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="872" data-original-width="1304" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBKK4SNKqQn-BRzPxGSvlpcRZWQ4C-7kDVM643YFr3kr3sVUIA6OTAPJfK8KpXj5V22we7bHBXMprBiMR444AjL6d9f4VXywx-2AMgXLrSBNpjKo-MTQH7eauP6hjXdJrKbDLlrN6cqbFlkgT-emdRA98dk2jose2SXagV54s_fRU3nKU-zfxesMrCvA/w400-h268/ZK4-hw-install-1.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 2.1] Zymkey4i를 Raspberry Pi 4에 붙이기(1)</span></span></div><p></p><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeEQCUaT96O570NdifC4PObNl7YaFBsMOXE3jhp0L6SPT-HKWJG8yZ7pvBU35ngnbPXIB0rrgBTIV33HHa4VzcIe27Jsfo4WL8ah8nc9MF5jPJkEz3Ve6BwvdNwuAgCa5UsiCAqvMmAfcIbdQ49A9iDHUwRRjUZKIldZxSpZ2KrVZnusjbkAamfvXOoA/s1380/ZK4-hw-install-2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="976" data-original-width="1380" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeEQCUaT96O570NdifC4PObNl7YaFBsMOXE3jhp0L6SPT-HKWJG8yZ7pvBU35ngnbPXIB0rrgBTIV33HHa4VzcIe27Jsfo4WL8ah8nc9MF5jPJkEz3Ve6BwvdNwuAgCa5UsiCAqvMmAfcIbdQ49A9iDHUwRRjUZKIldZxSpZ2KrVZnusjbkAamfvXOoA/w400-h283/ZK4-hw-install-2.png" width="400" /></span></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 2.2] Zymkey4i를 Raspberry Pi 4에 붙이기(2)</span></span></div><p><span style="color: #e69138;">참고: 문서에는 coin battery가 필요한 것으로 되어 있는데, 없어도 기본 동작에는 (아직까지는) 문제가 없는 것 같다.</span></p><p><span style="color: #e69138;"><br /></span></p><p>다음으로 해 주어야 할 일은 Raspberry Pi 4의 i2c 설정을 enable 시켜 주는 것이다.</p><p>$ <b><span style="font-family: Nunito;">sudo raspi_config</span></b></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFm1P-Q5K_2qOSlB-xceS-V8e9i03PRbh7DpUDxZQO8E8_YPKy59tNck-43NhCQ1grXpui0RQL3Se_Gj2jF3dJzGIRe29nQHXEguiPOY2foXBNHnRQi4E_eCq0baL4JqWBR88VdHmhrKDchQRk0OIe2JypNtYbuZdYifCVHZwjltnl6AlgK03neofMbQ/s948/rpi4_raspi_config.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="749" data-original-width="948" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFm1P-Q5K_2qOSlB-xceS-V8e9i03PRbh7DpUDxZQO8E8_YPKy59tNck-43NhCQ1grXpui0RQL3Se_Gj2jF3dJzGIRe29nQHXEguiPOY2foXBNHnRQi4E_eCq0baL4JqWBR88VdHmhrKDchQRk0OIe2JypNtYbuZdYifCVHZwjltnl6AlgK03neofMbQ/w400-h316/rpi4_raspi_config.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.3] raspberry pi raspi_config 설정 - i2c enable 설정</span></div><p><span style="color: #e69138; font-family: Nunito;">참고: 위의 설정 대신 raspberry pi 4 cpu BCM2711의 device tree를 직접 수정하는 방법도 생각해 볼 수 있다. 일단 나중에 해 보기로 하고 일단은 pass~</span></p><p><span style="font-family: Nunito;">____________________________________________________________</span></p><p><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><여기서 잠깐></b></span></p><p><span style="font-family: Nunito;">Raspberry pi용 linux kernel source를 build 후 사용해 보고 싶다면 어찌해야 하나 ? 아래 site에 관련 내용이 잘 설명되어 있으니, 참조하기 바란다.</span></p><p style="text-align: center;"><span style="font-family: Nunito;"><a href="http://www.wearedev.net/298?PHPSESSID=6130f2208f35379a121a8f83cd827e6d">http://www.wearedev.net/298?PHPSESSID=6130f2208f35379a121a8f83cd827e6d</a></span></p><div style="text-align: left;"><span style="font-family: Nunito;">Device tree는 아래 파일 내용을 살펴 보아야 한다.</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 10072 Jan 26 18:26 bcm2711-rpi-4-b.dts</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 10199 Jan 26 18:26 bcm2711-rpi-400.dts</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 10915 Jan 26 18:26 bcm2711-rpi-cm4.dts</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 7270 Jan 26 18:26 bcm2711-rpi-cm4s.dts</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 3985 Jan 26 18:26 bcm2711-rpi-ds.dtsi</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 1818 Jan 26 18:26 bcm2711-rpi.dtsi</span><br /><span style="font-family: Nunito;">-rw-rw-r-- 1 chyi chyi 26015 Jan 26 18:26 bcm2711.dtsi</span></div><div style="text-align: left;"><span style="font-family: Nunito;">chyi@sun:~/linux/arch/arm/boot/dts$ ls -l bcm2711*</span></div><p><span style="font-family: Nunito;">____________________________________________________________</span></p><p><span style="font-family: Nunito;"><br /></span></p><div style="text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #38761d; font-size: large;">b) Zymkey4i 용 s/w 설치하기</span></b><br />Zymkey4i는 Raspberry Pi에서만 동작하는 모양이다. 아래 방법을 이용하여 설치를 진행하도록 한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">pi@raspberrypi:~/workspace/zymkey $ <b>curl -G https://s3.amazonaws.com/zk-sw-repo/install_zk_sw.sh | sudo bash<br /></b> <span style="font-size: x-small;">% Total % Received % Xferd Average Speed Time Time Time Current<br /></span><span style="font-size: x-small;"> Dload Upload Total Spent Left Speed<br />100 5399 100 5399 0 0 6079 0 --:--:-- --:--:-- --:--:-- 6073<br />armv7l<br />Get:1 http://raspbian.raspberrypi.org/raspbian bullseye InRelease [15.0 kB]<br />Get:2 http://archive.raspberrypi.org/debian bullseye InRelease [23.6 kB] <br />Get:3 http://raspbian.raspberrypi.org/raspbian bullseye/main armhf Packages [13.2 MB]<br />Get:4 http://archive.raspberrypi.org/debian bullseye/main armhf Packages [311 kB]<br />Get:5 http://raspbian.raspberrypi.org/raspbian bullseye/contrib armhf Packages [60.2 kB] <br />Get:6 http://raspbian.raspberrypi.org/raspbian bullseye/non-free armhf Packages [106 kB] <br />Fetched 13.8 MB in 10s (1327 kB/s) <br />Reading package lists... Done<br />Building dependency tree... Done<br />Reading state information... Done<br />135 packages can be upgraded. Run 'apt list --upgradable' to see them.<br />Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple<br />Collecting inotify<br /> Downloading https://www.piwheels.org/simple/inotify/inotify-0.2.10-py3-none-any.whl (13 kB)<br />Collecting nose<br /> Downloading https://www.piwheels.org/simple/nose/nose-1.3.7-py3-none-any.whl (154 kB)<br /> |████████████████████████████████| 154 kB 186 kB/s <br />Installing collected packages: nose, inotify<br />Successfully installed inotify-0.2.10 nose-1.3.7<br />Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple<br />Collecting pycurl<br /> Downloading https://www.piwheels.org/simple/pycurl/pycurl-7.45.2-cp39-cp39-linux_armv7l.whl (294 kB)<br /> |████████████████████████████████| 294 kB 127 kB/s <br />Installing collected packages: pycurl<br />Successfully installed pycurl-7.45.2<br />Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple<br />Collecting progress<br /> Downloading https://www.piwheels.org/simple/progress/progress-1.6-py3-none-any.whl (11 kB)<br />Installing collected packages: progress<br />Successfully installed progress-1.6<br />Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple<br />Collecting python-gnupg<br /> Downloading https://www.piwheels.org/simple/python-gnupg/python_gnupg-0.5.0-py2.py3-none-any.whl (18 kB)<br />Installing collected packages: python-gnupg<br />Successfully installed python-gnupg-0.5.0<br />done.<br />Importing Zymbit Packages gpg key... done.<br />Installing /etc/apt/sources.list.d/zymbit.list...done...Updating now.<br />Hit:1 http://raspbian.raspberrypi.org/raspbian bullseye InRelease <br />Hit:2 http://archive.raspberrypi.org/debian bullseye InRelease <br />Get:3 https://s3.amazonaws.com/zk-sw-repo-rc-23.01/apt-repo-bullseye bullseye InRelease [2504 B]<br />Get:4 https://s3.amazonaws.com/zk-sw-repo-rc-23.01/apt-repo-bullseye bullseye/main armhf Packages [1784 B]<br />Fetched 4288 B in 2s (2340 B/s) <br />Reading package lists... Done<br />Building dependency tree... Done<br />Reading state information... Done<br />131 packages can be upgraded. Run 'apt list --upgradable' to see them.<br />Installing Zymkey Packages... % Total % Received % Xferd Average Speed Time Time Time Current<br /> Dload Upload Total Spent Left Speed<br />100 11491 100 11491 0 0 13471 0 --:--:-- --:--:-- --:--:-- 13455<br />Rebooting now...<br />Connection to 192.168.8.224 closed by remote host.<br />Connection to 192.168.8.224 closed.</span></span></div><p style="text-align: left;"><span style="font-family: Nunito;"></span></p><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span>부팅 후, 설치된 </span>내용을 대략적으로 확인해 보면 다음과 같다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">$ <b>ps aux|grep zk</b><br />zymbit 784 0.1 0.1 24744 4356 ? S<sl 08:48 0:00 <b>/usr/bin/zkifc -s /var/lib/zymbit/</b><br /></span></div><div style="text-align: left;"><span style="color: #e69138; font-family: Nunito;">참고: zymkey4i는 위와 같이 zkifc라는 daemon이 항상 떠 있는 구조이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div><span style="font-family: Nunito;">pi@raspberrypi:~ $ <b>systemctl status zkifc</b></span></div><div><span style="font-family: Nunito;">● zkifc.service - Zymkey Interface Connector</span></div><div><span style="font-family: Nunito;"> Loaded: loaded (/etc/systemd/system/zkifc.service; enabled; vendor preset: enabled)</span></div><div><span style="font-family: Nunito;"> Active: active (running) since Mon 2023-01-23 08:48:36 GMT; 31s ago</span></div><div><span style="font-family: Nunito;"> Process: 781 ExecStartPre=/bin/bash -c mkdir -p /run/zkstatus && chown -R zymbit.zymbit /ru></span></div><div><span style="font-family: Nunito;"> Process: 783 ExecStartPre=/bin/sleep 0.5 (code=exited, status=0/SUCCESS)</span></div><div><span style="font-family: Nunito;"> Main PID: 784 (zkifc)</span></div><div><span style="font-family: Nunito;"> Tasks: 3 (limit: 4915)</span></div><div><span style="font-family: Nunito;"> CPU: 172ms</span></div><div><span style="font-family: Nunito;"> CGroup: /system.slice/zkifc.service</span></div><div><span style="font-family: Nunito;"> └─784 /usr/bin/zkifc -s /var/lib/zymbit/</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">Jan 23 08:48:35 raspberrypi systemd[1]: Starting Zymkey Interface Connector...</span></div><div><span style="font-family: Nunito;">Jan 23 08:48:36 raspberrypi systemd[1]: Started Zymkey Interface Connector.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWHvA07J4nJjCSR_oEwYA6NtXB9WeEbkqyyr2pjKVgwbOQQLFrIwNgUGuJ9nC9plfEXFg0Iyrtnr0b1VYKhREm56Cxtm7YMQSWw896T_ohj8hs8gk_Eft9k4rpJZZ5jMUdMEvv0J_VfiSP20kQlIY-ouATdF6Q1H4_Iw8jhb9FgMpFAgbe0bXXcBd8oQ/s892/zymbit_zkifc_start_stop.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="748" data-original-width="892" height="536" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWHvA07J4nJjCSR_oEwYA6NtXB9WeEbkqyyr2pjKVgwbOQQLFrIwNgUGuJ9nC9plfEXFg0Iyrtnr0b1VYKhREm56Cxtm7YMQSWw896T_ohj8hs8gk_Eft9k4rpJZZ5jMUdMEvv0J_VfiSP20kQlIY-ouATdF6Q1H4_Iw8jhb9FgMpFAgbe0bXXcBd8oQ/w640-h536/zymbit_zkifc_start_stop.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.4] zkifc service start/stop 모습</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">zkifc daemon을 구동할 때 사용되는 /var/lib/zymbit 디렉토리도 새로 만들어 졌다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>pi@raspberrypi:<b>/var/lib/zymbit </b>$ ls -al</div><div>total 20</div><div>drwxr-xr-x 4 zymbit zymbit 4096 Jan 20 00:52 .</div><div>drwxr-xr-x 27 root root 4096 Jan 20 00:52 ..</div><div>drwx------ 2 zymbit zymbit 4096 Jan 25 00:22 <b>32EAF189356E232311B66890A0152E4382BB9A5BE93442DBC11F703A45E9204A</b></div><div>-rw-r--r-- 1 root root 251 Dec 10 2021 <b>ntp_str.json</b></div><div>drwxrwxr-x 3 root zk_pkcs11 4096 Jan 20 00:52 <b>zk_pkcs11</b></div><div><br /></div><div><div>pi@raspberrypi:/var/lib/zymbit $ <b>sudo ls -l 32EAF189356E232311B66890A0152E4382BB9A5BE93442DBC11F703A45E9204A/</b></div><div>total 8</div><div>-rw------- 1 zymbit zymbit 32 Jan 25 00:22 <b>s1_fp_salt.bin</b></div><div>-rw------- 1 zymbit zymbit 600 Jan 26 04:35 <b>state</b></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #a64d79; font-family: Nunito;">끝으로, 아래 위치에 C, C++용으로 application을 개발하기 위해 필요한 library와 header 파일이 보인다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>cd /lib; </b><b>ls -l libzk*</b></span></div><div><span style="font-family: Nunito;"><div>lrwxrwxrwx 1 root root 12 Jan 23 08:46 libzk.so -> libzk.so.1.1</div><div>-rw-r--r-- 1 pi pi 42244 Sep 23 22:21 libzk.so.1.1</div><div>-rw-r--r-- 1 root root 54576 Sep 23 22:21 libzkAppUtilsClassCPP.so</div><div>-rw-r--r-- 1 root root 50328 Sep 23 22:21 libzk_app_utils.so</div><div>-rw-r--r-- 1 root root 663240 Jan 9 2020 libzk_pkcs11.so</div><div><br /></div><div>pi@raspberrypi:~/workspace/zymkey/C $ <b>ls -l /usr/include/zymkey/</b></div><div>total 128</div><div>-rw-r--r-- 1 root root 58460 Sep 23 22:21 zkAppUtilsClass.h</div><div>-rw-r--r-- 1 root root 65060 Sep 23 22:21 zk_app_utils.h</div><div>-rw-r--r-- 1 root root 395 Sep 23 22:21 zk_b64.h</div></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">지금까지의 내용을 토대로 대략적인 s/w 구조를 예상해 보면 다음과 같다. </span></div><div style="text-align: left;"><span style="color: #674ea7; font-family: Nunito;"><br /></span></div><div style="text-align: center;"><b><span style="background-color: #d9ead3; font-family: Nunito;">[1] Example(with API & zk library) => zkifc daemon => i2c => zymkey4i(<span style="text-align: justify;">Microchip ATECC508A)</span></span></b></div><div style="text-align: center;"><span style="background-color: white; font-family: Nunito;">or</span></div><div style="text-align: center;"><b><span style="background-color: #d9ead3; font-family: Nunito;">[2] Example(with API) => zk library => i2c => zymkey4i(<span style="text-align: justify;">Microchip ATECC508A)</span></span></b></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><div style="text-align: left;"><b style="color: #3d85c6; font-family: Nunito; font-size: xx-large;">3. Zymkey4i API 사용해 보기</b></div><span style="font-family: Nunito;"><div style="text-align: left;"><br /></div><div style="text-align: left;">이번 장에서는 아래 site의 내용을 기초로 하여 Zymkey4i API를 사용하는 방법을 소개해 보고자 한다.</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: center;"><a href="https://docs.zymbit.com/api/c_api/">https://docs.zymbit.com/api/c_api/</a></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><div style="text-align: left;"><div style="font-family: "Noto Sans CJK KR";"><b><span style="color: #38761d; font-family: Nunito; font-size: large;">a) python example 돌려 보기</span></b></div><div>우선, Quickstart 문서에 있는 python 예제 코드 2개를 내려 받아 돌려 보도록 한다.</div><div><br /></div><div><span style="font-family: Nunito;"><div>pi@raspberrypi:~/workspace/zymkey $ <b>python3 ./zk_app_utils_test.py </b></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing data lock...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Original Data</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">01 02 03 04</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Encrypted Data</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">68 4E CE 63 00 00 15 D8 C1 32 59 4C 17 4A 1F 2F</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">2D 3E 01 1E 7A CF 5C F6 5B 7F CA 54 86 65 2D 7B</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7A 74 A8 F0 0A CA 2C 33 6A 1A 15 7D E9 BF 62 E4</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">C2 06 30 31 75 7E F1 6F 1C 6E CD D3 7C 57 72 5E</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">1E 33 08 D7 12 83 65 A2 8E 96 FE FA A1 A8 7C 39</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">8C 56 5C 77 40 85 CC E4</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing data unlock...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Decryped Data</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">01 02 03 04</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Turning LED on...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing get_random() with 512 bytes...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">86 D0 64 73 B7 15 1F C5 90 CC 48 A8 A5 80 C2 C3</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">3F 15 4C EC F5 B4 5D 10 63 B8 D1 FA 4E 88 60 AB</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7F 30 51 27 7D C7 71 F9 5E 3D 06 59 C9 8B AF DC</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">B4 74 68 BA FE 2A 01 B7 82 DA 4E CB D1 4A 96 3F</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">0C 41 64 CC 72 AA ED C3 93 51 95 B4 47 9F 07 C1</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">B0 47 1D 18 9A 98 76 6C 20 43 72 AD A3 6A A6 40</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">BC A3 F3 C6 F0 AE D9 F4 2E 6D 7A 0F A9 7D 08 2E</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">4C 28 0B D5 DA B7 4A 6C 7C 3B 2C 6D 45 5C 25 D2</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">B6 90 E2 00 FC 11 09 FF 64 E2 B7 43 E2 86 26 63</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">6D D1 76 95 3A 5D 32 11 9F 91 0E 66 D5 AD 79 6F</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">F9 B9 38 86 FE 8B C6 95 29 8C 28 B8 1D 48 54 B6</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">8F 99 2F DB 95 0E 33 26 BF C9 8A E6 E5 DB 56 F5</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">BE BC 11 17 2E 0C 8B 56 63 45 5C 81 79 CB 18 8E</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">FE 7D 69 40 BE 5F A2 71 0F FD 46 F4 0F EB 8D 1F</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7C 77 F3 FD 4D E9 5F E2 CB D8 C1 ED AA 1B 2C 87</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">48 54 43 35 5C A8 35 94 6C BD 5C 7A F1 D9 B3 91</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">4C CE 0F FE 73 C6 AC 05 F5 67 E6 4B D3 D3 A1 EC</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">A8 1E 93 E6 A7 AD B9 31 B7 74 91 8A 4A C6 E9 14</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">F0 95 64 C0 C1 77 1E 0A E3 75 7D B8 D6 77 07 24</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7A 30 1E B7 23 B3 90 55 E2 3F E6 E6 C2 6A 82 50</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">FA 2D 08 9C 3D 71 0A BA 62 A9 D3 D2 A4 58 19 A8</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">41 E5 49 28 B9 88 6F 8F 38 56 82 17 F2 86 61 36</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">72 80 8E 32 84 66 C7 FF 82 86 D2 74 AF 87 91 05</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">97 E5 35 70 38 83 3F 8E F4 BF 7B 21 84 96 78 A7</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">8B 47 C4 78 3F C2 51 D4 35 89 9A EA A5 8E 52 D8</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">96 5F 23 4E BA BA 95 81 35 F2 6E B1 B5 2E A4 C7</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7B EE D3 8A 69 00 32 D7 44 39 B1 35 D1 47 F7 65</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">1A 21 01 D4 10 28 F3 38 9F E3 8C 86 7C A2 76 C2</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">86 4D D8 B1 F2 99 96 61 9E BF 4B 81 A1 22 CE 4B</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">13 35 0C 98 1E 73 A8 CE A5 DB F0 8D B9 55 42 64</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">FC 40 03 1C E6 0D F8 21 77 D2 23 C9 4D D1 75 B9</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">62 71 24 D5 10 89 13 30 D2 3A 72 ED 1E 29 5E 84</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Turning LED off...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Flashing LED off, 500ms on, 100ms off...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing zkCreateRandDataFile with 1MB...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Turning LED off...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing get_ecdsa_public_key()...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">38 21 3C 8C E8 3C CF 42 7A EE F5 13 FD 3A 02 3F</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">C8 80 88 60 73 A5 95 A7 1C C4 C5 C4 21 61 38 17</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">EC C0 B4 D6 66 FC 66 7D 29 32 E0 1E 21 E8 A2 C1</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">7F 83 CD 57 5D 2B F7 91 9B D6 14 F3 EB 6D 40 AA</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Testing create_ecdsa_public_key_file()...</span></div><div style="font-family: "Noto Sans CJK KR";"><br /></div><div>pi@raspberrypi:~/workspace/zymkey $ <b>python3 ./zk_crypto_test.py </b></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Signing data...OK</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Verifying data...OK</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Verifying tainted data...FAIL, yay!</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Generating random block from Zymkey (131072 bytes)...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Encrypting random block...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Decrypting encrypted block...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">PASS: Decrypted data matches original random data</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;">Done!</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;"><br /></span></div><div>뭔가 제대로 동작하는 느낌이다. 이 대목에서 python code 내용 설명은 생략 ~ 😋</div><div style="font-family: "Noto Sans CJK KR";"><span style="font-size: x-small;"><br /></span></div></span></div></div></div><div style="text-align: center;"><br /></div><div style="text-align: justify;"><b style="font-family: "Noto Sans CJK KR"; text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: large;">b) C API를 이용한 초간단 예제 프로그램 작성하기</span></b></div><div style="text-align: left;">아무리 찾아 보아도 API 설명 부분만 있고, C or C++ example code가 안 보인다. 사용하기 쉽게 만들어져 있어서 그런가 추측해 본다. 암튼, API 문서를 참조하여 간단한 예제를 하나 만들어 보도록 하자.</div><div style="text-align: left;"><br /></div><div style="text-align: justify;"><span style="text-align: left;">__________________________________________________________________________</span></div></span><i><span style="font-family: Nunito;"><div style="text-align: left;">#include <stdio.h></div></span><span style="font-family: Nunito;"><div style="text-align: left;">#include <stdlib.h></div></span><span style="font-family: Nunito;"><div style="text-align: left;">#include "<b><span style="color: #b45f06;">zk_app_utils.h</span></b>"</div></span><span style="font-family: Nunito;"><div style="text-align: left;">int main()</div></span><span style="font-family: Nunito;"><div style="text-align: left;">{</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> <b>zkCTX ctx;</b></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> int ret;</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkOpen</b>(&ctx);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkOpen() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkOpen() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkCreateRandDataFile</b>(ctx, "./test1.txt", 512);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkCreateRandDataFile() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkCreateRandDataFile() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> uint8_t *rdata = (uint8_t *)malloc(sizeof(uint8_t) * 512);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkGetRandBytes(</b>ctx, &rdata, 512);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetRandBytes() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetRandBytes() is OK\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (rdata)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> free(rdata);</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkSaveECDSAPubKey2File</b>(ctx, "./publickey", 1);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkSaveECDSAPubKey2File() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkSaveECDSAPubKey2File() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkLEDOff</b>(ctx);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkLEDOff() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkLEDOff() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkLEDOn</b>(ctx);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkLEDOn() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkLEDOn() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> char *model_str = malloc(sizeof(char) * 128);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkGetModelNumberString</b>(ctx, &model_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetModelNumberString() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetModelNumberString() is OK\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (model_str) {</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("model_str --------------> [%s]\n", model_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> free(model_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> }</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> char *serial_num_str = malloc(sizeof(char) * 128);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkGetModelNumberString</b>(ctx, &serial_num_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetModelNumberString() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkGetModelNumberString() is OK\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (serial_num_str) {</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("serial_num_str --------------> [%s]\n", serial_num_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> free(serial_num_str);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> }</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> ret = <b>zkClose</b>(ctx);</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> if (ret != 0)</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkClose() failed\n");</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> else</div></span><span style="font-family: Nunito;"><div style="text-align: left;"> printf("zkClose() is OK\n");</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;"> return ret;</div></span><span style="font-family: Nunito;"><div style="text-align: left;">}</div></span></i><span style="font-family: Nunito;"><div style="text-align: left;">__________________________________________________________________</div><div style="text-align: left;"><br /></div><div style="text-align: left;">Raspberry Pi 내에 library와 header 파일이 있으니, Pi에서 직접 compile해 보도록 하자. 간단한 program이니 Makefile 까지 만들 필요도 없다.</div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;">$ <b>gcc -o test1 test1.c -I/usr/include/zymkey/ -lzk_app_utils</b></div><div style="text-align: left;">$ <b>./test1</b></div><div style="text-align: left;"><br /></div><div style="text-align: left;">OK가 출력되고, LED도 on/off되는 것으로 보아 정상 동작하는 것 같다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHI2oEhL1Qtpd-MsQQLvjnmeIFJsuI7i4RllLJOqzcUkci-y8Lrh7cx24_cwpKIjArx8fvS0GOYgS5tfyQjcJ6WHVFMoRbDFZKYXHwJ0q3s04xs-xIZzIXup6LXyt5ggUWpDpvnQgQthJrk0UhCVucqRdhACPo9hXx0qvUFCvRTJtbnQH2bJTk1lbZbw/s885/zymbit_c_test.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="885" height="328" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHI2oEhL1Qtpd-MsQQLvjnmeIFJsuI7i4RllLJOqzcUkci-y8Lrh7cx24_cwpKIjArx8fvS0GOYgS5tfyQjcJ6WHVFMoRbDFZKYXHwJ0q3s04xs-xIZzIXup6LXyt5ggUWpDpvnQgQthJrk0UhCVucqRdhACPo9hXx0qvUFCvRTJtbnQH2bJTk1lbZbw/w640-h328/zymbit_c_test.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] zymbit C example 돌려 보기</div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="color: #e69138;">참고: 관련 library와 header 파일을 Ubuntu PC로 꺼내어 cross-compile해 보는 것도 하나의 방법이 될 수 있겠다.</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito; font-size: large;">c) C API를 이용한 좀 더 복잡한 예제 코드 작성해 보기</span></b></div><div style="text-align: left;">이 절에서는 아래 header file 내용을 기초로하여, 좀 더 심오한(?) 기능 시험(ECDH, ECDSA, TLS ...)을 진행해 보도록 하겠다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjKuD3Mtc_3oiJBRGM5Fy95NmtmNFEoisOQQdRnOxwgGmTPACK5x-IMlkVhKk4fzkjjESxTt8usLbPeRch0EgPPfOSS18kmezGVwjpeKBKPKT0peCgmzIi-z078-EZ-VlwEm8CLMw_qvn1A6SqQwCKk4taq4hGouPnqGtXBSu7gJAWiIwhKjcP80-E0g/s902/zymbit_zk_app_utils_h.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="902" data-original-width="809" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjKuD3Mtc_3oiJBRGM5Fy95NmtmNFEoisOQQdRnOxwgGmTPACK5x-IMlkVhKk4fzkjjESxTt8usLbPeRch0EgPPfOSS18kmezGVwjpeKBKPKT0peCgmzIi-z078-EZ-VlwEm8CLMw_qvn1A6SqQwCKk4taq4hGouPnqGtXBSu7gJAWiIwhKjcP80-E0g/w574-h640/zymbit_zk_app_utils_h.png" width="574" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] /usr/include/zymkey/zk_app_utils.h 파일 내용</div></span></div><div style="text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b>이 부분은 독자 여러분의 몫이다. 앗, 뭣이라고요 ~ <span style="color: #6aa84f;">😋</span></b></div><div style="text-align: left;"><b><span style="color: #6aa84f; font-family: Nunito;"><br /></span></b></div><div style="text-align: left;"><br /></div></span><span style="font-family: Nunito;"><div style="text-align: left;">지금까지 Zymkey4i i2c device를 Raspberry Pi 4에 붙이고, zymkey4i가 제공하는 다양한 API를 이용하여 HSM의 맛(?)을 살짝 확인해 보는 시간을 가져 보았다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;">내용 중 부족한 부분은 다음 blog post를 통해 계속 보강하도록 하겠다. 끝까지 읽어 주셔서 감사드린다. 💢</div><div style="text-align: left;"><br /></div></span></div><p><span style="font-family: Nunito;"><br /></span></p><p><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">4. References</span></b></p><div style="text-align: left;"><span style="font-family: Nunito;"><b>[1]</b> https://www.zymbit.com/wp-content/uploads/2018/12/Zymbit-Data-Sheet-Zymkey-4i-DATA-SHEET-04100910A2.pdf<br /></span><span style="font-family: Nunito;"><b>[2] </b>https://docs.zymbit.com/getting-started/zymkey4/quickstart/<br /></span><span style="font-family: Nunito;"><b>[3]</b> https://www.hackster.io/sabrinaZ/zymkey4i-security-module-for-raspberry-pi-259d84<br /></span><span style="font-family: Nunito;"><b>[4]</b> https://docs.zymbit.com/api/c_api/<br /></span><span style="font-family: Nunito;"><b>[5] </b>https://www.farnell.com/datasheets/2674017.pdf</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b>[6]</b><span style="color: #990000;"><b> </b>https://ww1.microchip.com/downloads/en/DeviceDoc/20005928A.pdf</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b>[7] </b>https://content.arduino.cc/assets/mkr-microchip_atecc508a_cryptoauthentication_device_summary_datasheet-20005927a.pdf</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b>[8] </b>https://ww1.microchip.com/downloads/en/Appnotes/Atmel-8984-CryptoAuth-CryptoAuthLib-ApplicationNote.pdf - <span style="color: #990000;">microchip cryptoauthlib 설명서</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b>[9] </b>https://www.microchip.com/en-us/products/security/security-ics/cryptoauthentication-family</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span><b>[10]</b> </span>Integration of Security Hardware Module Zymkey 4i With Raspberry Pi, Rizzo Mungka Rechie 1 ; Nur Nabila Mohamed2; Yusnani Mohd Yussoff 3 ; Lucyantie Mazalan 4 ; Suhairi Mohd Jawi 5 ; Mohd Saufy Rohmad 6</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><p><span style="font-family: Nunito;"><br /></span></p><p><span style="font-family: Nunito;"><br /></span></p><p style="text-align: right;"><b><span style="font-family: Nunito;">Slowboot</span></b></p><p style="text-align: right;"><span style="font-family: Nunito;"><br /></span></p><br />Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-75555712691802810252020-12-02T14:09:00.001+09:002020-12-02T14:12:45.808+09:00ESP32로 알아보는 FreeRTOS<div style="text-align: left;"><span style="font-family: Nunito;">이번 시간에는 Wi-Fi & Bluetooth 기능을 저가로 공급하여 유명해진 Espressif 사의<span style="color: #a64d79;"><b> </b><a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> </span>보드를 사용하여, RTOS OS 중에서 현재 가장 많은 사용자 층을 확보하고 있는 <a href="https://www.freertos.org/">FreeRTOS</a>를 소개해 보고자 한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnm1NOPuSi6_exYLGR7UC7MU_p2sudquAQkjr0LN7nu-yKPIpigbUCuHYVjtOPWq8igJ4bUz-CcXKOIE1PpSZ6mZSKSQDi4j8OLTF6F-gGOHt4g3e4O2a2heNfPs7ZPybEJHyEMsS4mbiV/s364/freertos.jpeg" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="138" data-original-width="364" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnm1NOPuSi6_exYLGR7UC7MU_p2sudquAQkjr0LN7nu-yKPIpigbUCuHYVjtOPWq8igJ4bUz-CcXKOIE1PpSZ6mZSKSQDi4j8OLTF6F-gGOHt4g3e4O2a2heNfPs7ZPybEJHyEMsS4mbiV/w219-h83/freertos.jpeg" width="219" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; margin-left: 1em; margin-right: 1em;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaPBqyMTDCV4WZie4d4kn_xbdtpUqAhSRKMrikSD1HO0yI8xluSuv9vQk79B877Of2JvObgtpRKqyxGxaVul_UGqBDeQf9tkHhKTyPVIVuqfU9yw9RJ3OyjDTD6G8FAxNE6yvCTt675obl/s800/attack_logo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="357" data-original-width="800" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaPBqyMTDCV4WZie4d4kn_xbdtpUqAhSRKMrikSD1HO0yI8xluSuv9vQk79B877Of2JvObgtpRKqyxGxaVul_UGqBDeQf9tkHhKTyPVIVuqfU9yw9RJ3OyjDTD6G8FAxNE6yvCTt675obl/s320/attack_logo.png" width="320" /></a></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="font-family: Nunito; font-size: medium;">목차</span></b></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;">1. ESP32와 FreeRTOS</span></i></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;">2. ESP-IDF SDK 소개</span></i></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;">3. FreeRTOS Programming</span></i></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;">4. 아직 못다한 이야기</span></i></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;">5. References</span></i></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #e69138; font-family: Nunito;"><span><i>IT에 입문한지 어느새 25년째다. </i><i>AI, Big Data, Cloud, IoT, Robot, Drone, Autonomous Vehicle, Blockchain, 3D printing ... </i></span><i><span>예전에도 분명히 그랬을 텐데, 최근 몇년 동안의 IT 시장의 눈부신 변화가 유독 더 크게 다가오는 것은 것은 왜일까 ? 변화를 따라잡지 못하면 도태되고 말 것이라는 불안감이 엄습해 온다. 이럴 때는 어찌해야 할까 ? 답은 간단하다. 자신이 그동안 열심히 해 오던 분야를 더 깊이 파고 또 파는 것이다. 아무리 새로운 기술이 등장하고, 그 변화의 속도를 도져히 따라 잡을 수 없을 것 같아도, 이러한 기술들이 과연 어디에서 나왔겠는가 ? 내가 오늘 하는 작은 일을 결코 가볍게 여기지 말자</span><span style="font-size: x-small;">~ 😎</span></i></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">1. ESP32와 FreeRTOS</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이번 장에서는 ESP32와 FreeRTOS에 관하여 간략히 살펴 보고자 한다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">a) ESP32 overview</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">ESP32는 <a href="https://www.espressif.com/en/products/socs/esp8266">ESP8266</a>으로 유명한 Espressif 사에서 만든 Wi-Fi & Bluetooth용 저가의 chip(Wi-Fi/BLE SoC)이다. 그런데 저가의 chip이라고 해서 우습게(?) 볼 일이 아닌 것이, ESP32 자체는 <a href="https://mirrobo.ru/wp-content/uploads/2016/11/Cadence_Tensillica_Xtensa_LX6_ds.pdf">Xtensa LX6(Dual-core 32bit) RISC CPU</a>(</span><span style="font-family: Nunito;">160Mhz or 240Mhz)</span><span style="font-family: Nunito;">를 기반으로 하고 있는 엄연한 32bit microprocessor이다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1u83QxG9W2rNmU0XXPNEfyMqJREAxKCw0m89290hjfpKZrOq9ef_lhLa7lvqC0ey1blbhFePnBLQAfYpoVv5mABvI8kIazwRuZbPt8wuNmI_ev4HRffdh0sHLjIrBc3RYnvvC5OmJPKxz/s1234/esp32_espressif.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="557" data-original-width="1234" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1u83QxG9W2rNmU0XXPNEfyMqJREAxKCw0m89290hjfpKZrOq9ef_lhLa7lvqC0ey1blbhFePnBLQAfYpoVv5mABvI8kIazwRuZbPt8wuNmI_ev4HRffdh0sHLjIrBc3RYnvvC5OmJPKxz/w400-h180/esp32_espressif.png" width="400" /></span></a></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.1] Espressif ESP32 SoC<b> [출처 - <a href="https://www.espressif.com/">https://www.espressif.com/</a>]</b></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkIvHF5nagEDplF6tyTt4PiF4nnBWZkxjOiyX5pp3mUcKtInbJj_elJPUcxq2i0o_d-qiNnLORw7aCZZkBdKsds_N9aYo0JxgS84hYYQhb4BQ0DKEJKx-mSlSU0XO3oN3zEZqtQQfmsgam/s642/esp32_functional_block_diagram.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="537" data-original-width="642" height="335" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkIvHF5nagEDplF6tyTt4PiF4nnBWZkxjOiyX5pp3mUcKtInbJj_elJPUcxq2i0o_d-qiNnLORw7aCZZkBdKsds_N9aYo0JxgS84hYYQhb4BQ0DKEJKx-mSlSU0XO3oN3zEZqtQQfmsgam/w400-h335/esp32_functional_block_diagram.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.2] ESP32 SoC 블럭도</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidvndKrZIgX1uKliLDDWxnT9t70yI0sis8iQTuHiixbOpGIeAtF9aCyIQl2FZf_NScuBBZPO9bL2t4ouLjYeuqrQ05-Ni3aPBIOl8YW72JxQUouqdMFgTe3pwG5K2La0y5OA3lr9UaA4sI/s600/ESP8266_vs_ESP32.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="310" data-original-width="600" height="233" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidvndKrZIgX1uKliLDDWxnT9t70yI0sis8iQTuHiixbOpGIeAtF9aCyIQl2FZf_NScuBBZPO9bL2t4ouLjYeuqrQ05-Ni3aPBIOl8YW72JxQUouqdMFgTe3pwG5K2La0y5OA3lr9UaA4sI/w453-h233/ESP8266_vs_ESP32.png" width="453" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.3] ESP8266 vs ESP32 스펙 비교 <b>[출처 - 참고문헌 7]</b></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: white; color: #b45f06; font-family: Nunito; text-align: left;">📌 이정도 spec이라면 RAM 크기만 좀 더 보강된다면 linux도 충분히 돌릴 수 있을 것 같다.</span></div><div class="separator" style="clear: both; text-align: justify;"><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white;"><span style="font-family: Nunito;">따라서 여기에서는 ESP32를 WiFi or Bluetooth용 device로 생각해서 Arduino의 주변 장치로 활용하기 보다는, ESP32를 CPU로 하여 단독으로 동작하는 방식을 활용하고자 한다. 아래 그림은 ESP32를 사용하여 만들어진 보드 중 하나인 ESP32 DeviKit이다. 실제로 (이와 유사한) ESP32를 기반으로 하는 다양한 업체의 다양한 종류의 보드가 저가로 판매되고 있다.</span></span></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3rHtk1pCaMTZHjkctMdZAiSOYA_xTij91L3UwSVYLXxPllyk-xMzZieHJQoCKytwzRd5tKZDSq2LZW4ZLXTEbydODFhTy_k4AIXY0gC-eUBV3xaO1ySQlRyAnoNE9fdg_O4X3TQBJVI_S/s768/esp3-768x352.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="352" data-original-width="768" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3rHtk1pCaMTZHjkctMdZAiSOYA_xTij91L3UwSVYLXxPllyk-xMzZieHJQoCKytwzRd5tKZDSq2LZW4ZLXTEbydODFhTy_k4AIXY0gC-eUBV3xaO1ySQlRyAnoNE9fdg_O4X3TQBJVI_S/w400-h184/esp3-768x352.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.4] ESP32를 사용한 board(device kit) 예</span></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">ESP8266 및 ESP32는 Arduino or Raspberry Pi 만큼이나 워낙 유명하기 때문에 여기에서 부연 설명을 할 필요가 없어 보인다. 따라서 다음 장에서는 곧 바로 <b>ESP-IDF</b> 환경 설정으로 넘어가도록 하겠다.</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">b) FreeRTOS overview</span></b></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><a href="https://www.freertos.org/">FreeRTOS</a>는 Richard Barry가 만들어 현재까지 가장 많은 사용자 층을 확보하고 있는 open source RTOS로, 아래 그림에서 보는 바와 같이 embedded linux에 이어 사용률 2위(2019년 기준)에 오를 정도로 그 기세가 대단하다(<span style="color: #6fa8dc;">필자도 사실 이정도까지 FreeRTOS가 널리 사용되고 있는 줄은 몰랐다 </span>😅).</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii5FK6GsAMU2gPLW12T9M9jLs2W_lDKjWBTAGyNoYB6UybbJn2sOENZpbl3sxoFtEty2bFk2kzFtoIFEU-iZ1W39kUtxM7uD3ZeGfKAzbQGoydo0ng0JBvMplevc7G5EZZShyphenhypheno3ldwNk4P/s1286/embedded_os_study.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="768" data-original-width="1286" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEii5FK6GsAMU2gPLW12T9M9jLs2W_lDKjWBTAGyNoYB6UybbJn2sOENZpbl3sxoFtEty2bFk2kzFtoIFEU-iZ1W39kUtxM7uD3ZeGfKAzbQGoydo0ng0JBvMplevc7G5EZZShyphenhypheno3ldwNk4P/w640-h382/embedded_os_study.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.5] 2019년 기준 향후 1년간 사용할 것으로 예상되는 Embedded OS 순위 <b>[출처 - 참고문헌 4]</b></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 이 자료는 미국(58%), EMEA(21%), APAC(21%)의 엔지니어들을 대상으로 조사한 결과이다. 조사 대상 중 EMEA(유럽 외)나 아시아권의 비중이 낮은 것이 좀 아쉽다.</span></div><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">사실 FreeRTOS 자체는 <a href="https://www.zephyrproject.org/">Zephyr</a>나 <a href="https://os.mbed.com/mbed-os/">mbedOS</a>와는 달리 kernel core 자체만을 제공하고 있기 때문에, 나머지 부분(device driver, network stack, 주변 library 등)은 칩 제조사에서 자신들의 환경에 맞게 작업한 후, SDK 형태로 배포하는 방식을 따른다(예: Espressif ESP-IDF).</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white;">이런 상황에서 Amazon은 최근에 FreeRTOS를 인수하여 (kernel 이외의 기능을 보강하여) <a href="https://github.com/aws/amazon-freertos">Amazon FreeRTOS</a> 형태로 배포하고 있다. <span style="color: #990000;">왜 </span></span><span style="background-color: white;"><span style="color: #990000;">Cloud 업체인 Amazon에서 뜬금없이 FreeRTOS를 인수했을까 ?</span> 답은 간단하다. 이는 IoT 시장의 폭발은 Cloud 시장의 그것과 직결되기 때문이다. 쉽게 말해 IoT 기기를 효과적으로 사용/관리하기 위해서는 Cloud(서버)와의 연결이 필수적인데, 현재 가장 많은 사용자 층을 확보한 FreeRTOS를 AWS와 잘 연동하도록 만들어</span><span style="background-color: white;">(Amazon FreeRTOS를 사용할 수 밖에 없도록 만들어)</span><span style="background-color: white;"> 재 배포하는 것은 그만큼 AW$ cloud 시장을 확장하는 효과를 가져올 것이 자명하기 때문이다. 이는 M$에서 발빠르게 Azure cloud에 맞는 <a href="https://github.com/azure-rtos">Azure RTOS</a>를 밀고 있는 것과도 맥을 같이한다고 보아야 할 것이다.</span><span style="background-color: white;"> 근데, Google은 뭐하나 ? 😂</span></span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN5ZmbkCcP0i2PEikAfCXw9avW7w5ikyaN4EFOPXRGWvp_qwv0gI6X6lgiQjvXeD2F-UpJHfQiqKyIa-XH1NCg33EYp7Naq1_bo1hC-Ki0F42n_ApvPPMIuaPLbv8OgJ8gcuRPI3Q2Qggr/s2210/amazon-freertos-1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="1002" data-original-width="2210" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiN5ZmbkCcP0i2PEikAfCXw9avW7w5ikyaN4EFOPXRGWvp_qwv0gI6X6lgiQjvXeD2F-UpJHfQiqKyIa-XH1NCg33EYp7Naq1_bo1hC-Ki0F42n_ApvPPMIuaPLbv8OgJ8gcuRPI3Q2Qggr/w400-h181/amazon-freertos-1.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.6] Amazon FreeRTOS <b>[출처 - 참고문헌 5]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b style="background-color: #ffe599;"><span style="font-family: Nunito;"><앞으로 눈여겨 보아야 할 RTOS></span></b></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;">1. <a href="https://aws.amazon.com/ko/freertos/getting-started/">Amazon's AWS FreeRTOS</a> : 목적은 AWS Cloud 😓</span></i></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;">2. <a href="https://azure.microsoft.com/en-us/services/rtos/">Microsoft's Azure RTOS</a> : 목적은 Azure Cloud 😓</span></i></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;">3. <a href="https://os.mbed.com/mbed-os/">ARM's mbedOS</a> : 목적은 ARM Cortex-M series chips 😒</span></i></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;">4. <a href="https://www.zephyrproject.org/">Linux foundation's Zephyr Project</a> : Open source project 😃</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><i>5. <a href="https://nuttx.apache.org/">Apache's NuttX</a> </i><i>: Open source project 😃</i></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">앞으로 누가 RTOS 시장의 패권을 거머쥘지는 예측하기 어려우나, 위의 조사 결과로 보아 당분간 FreeRTOS의 아성을 무너뜨리기는 쉽지 않아 보인다. <span style="color: #45818e;">그래도 개인적으로는 Zephyr의 비상을 기대해 본다 ...</span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcYrgo96N5BTlnCJh7-nxmO-CCit6M9W1j3ggFbYyzrxVFz_twfOj_Z8QtgqwuPhW-Ug2o9sBl2doa-tSuMmBjsW3UllEZFfLMpEH3yqTek7MBKcEOU6svf5yNJOTEKn96suv-NDcUgblL/s20/zephyr_small_logo.png" style="color: #6aa84f; margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="19" data-original-width="20" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcYrgo96N5BTlnCJh7-nxmO-CCit6M9W1j3ggFbYyzrxVFz_twfOj_Z8QtgqwuPhW-Ug2o9sBl2doa-tSuMmBjsW3UllEZFfLMpEH3yqTek7MBKcEOU6svf5yNJOTEKn96suv-NDcUgblL/s16000/zephyr_small_logo.png" /></a><br /><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">2. ESP-IDF SDK 소개</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이번 장에서는 Espressif 사에서 만든 ESP-IDF 개발 환경(or SDK)을 소개해 보고자 한다. </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">a) ESP-IDF 개요</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">ESP-IDF는 마치 Amazon FreeRTOS 처럼, FreeRTOS kernel과 주변 기능(device driver, network stack, security 기능, ...)을 하나로 통합하여 ESP series 보드에 맞게 최적화 시킨 RTOS(or SDK)이다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRY1Uk2L7mhTyhOtipDP1pZUcDuYWHpCtCv0tFbfFEX1gRdlR0Kg4qooUHIT910aNCFFZi5cQAwcY6hjqMhTNUgQY8jeK07iQHtCTtxT8HIkkz0Gfdxweg6_qX3tajOfQK-NLbYVbdUobL/s1151/esp_idf_arch.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="379" data-original-width="1151" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRY1Uk2L7mhTyhOtipDP1pZUcDuYWHpCtCv0tFbfFEX1gRdlR0Kg4qooUHIT910aNCFFZi5cQAwcY6hjqMhTNUgQY8jeK07iQHtCTtxT8HIkkz0Gfdxweg6_qX3tajOfQK-NLbYVbdUobL/w400-h131/esp_idf_arch.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.1] Espressif ESP-IDF 아키텍쳐<b> [출처 - <a href="https://www.espressif.com/">https://www.espressif.com/</a>]</b></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 Espressif에서는 FreeRTOS를 그대로 사용하지 않고 자신들의 CPU에 맞게 최적화(예: dual core CPU 상황을 고려하여 API 기능 확장)하여 배포하고 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">Espressif사는 ESP-IDF 외에도 아래와 같이 몇가지 흥미로운 framework & library 개발 환경을 제공하고 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGywyD0xx1-2tVO57nKP7zQf6AzRMG0tfbbqaCwqNq8Fs_WQOZg8RObWKeCMJvHDaJczFXVZu2IolMb4DZLPi0hlHvx_xf1VZiEsZ0u-IQV4cxkG51HbF1koMQFt704ySMruVVZZcbC6AW/s1151/esp32_frameworks.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="615" data-original-width="1151" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGywyD0xx1-2tVO57nKP7zQf6AzRMG0tfbbqaCwqNq8Fs_WQOZg8RObWKeCMJvHDaJczFXVZu2IolMb4DZLPi0hlHvx_xf1VZiEsZ0u-IQV4cxkG51HbF1koMQFt704ySMruVVZZcbC6AW/s320/esp32_frameworks.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.2] Espressif frameworks and libraries <b>[출처 - <a href="https://www.espressif.com/en/products/sdks/esp-idf">https://www.espressif.com/en/products/sdks/esp-idf</a>]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">b) Target board</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이번 posting에서 사용할 target board는 ESP32 기반 보드 중 주변에서 쉽게 구할 수 있는 <b>NodeMCU-32S</b>이다.</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito;"><span style="font-size: 14.85px;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpVZm2KX3upXDhr7VTGRYp2erPEqL84Kj2TwH714jVBuNTzvh9L4rKgZ_XtQ9T3dX6MyFyeLA5CpWp5jaucSDhrVXpPtrlKbzrB-Fu03411IRRyZd8rOPRHY-PnXGcMX4dzNOT0we4emyH/s225/nodemcu.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" height="193" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpVZm2KX3upXDhr7VTGRYp2erPEqL84Kj2TwH714jVBuNTzvh9L4rKgZ_XtQ9T3dX6MyFyeLA5CpWp5jaucSDhrVXpPtrlKbzrB-Fu03411IRRyZd8rOPRHY-PnXGcMX4dzNOT0we4emyH/w193-h193/nodemcu.jpeg" width="193" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjum0NVvP20_nOQDXZsPFDKSDV3HdE5Uh4OA0zP6cvq9UqidPNxa6ioBNM3_HuXD1-tY-yijCJJNlw1Qt6Q5R7q7Nk2BofAaRhFjHLplPJNS2APZbop5unEQexCSmwF8a1af-smixgx2_jz/s600/nodemcu.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="600" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjum0NVvP20_nOQDXZsPFDKSDV3HdE5Uh4OA0zP6cvq9UqidPNxa6ioBNM3_HuXD1-tY-yijCJJNlw1Qt6Q5R7q7Nk2BofAaRhFjHLplPJNS2APZbop5unEQexCSmwF8a1af-smixgx2_jz/w200-h200/nodemcu.jpg" width="200" /></a></span></div><span style="font-family: Nunito;"> <br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.3] NodeMCU-32S</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06;">📌 (국내에서) 배송비 포함하여 </span><span style="color: #b45f06;"><span>11,800원에 구매하였다.</span></span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #b45f06;"><span style="font-family: Nunito; font-size: 14.85px;"><br /></span></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">c) ESP-IDF 환경 설정하기</span></b></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">자, 그럼 이제 부터 본격적으로 ESP-IDF 환경 설정에 들어가 보도록 하자. 언제나 그렇듯 Ubuntu 환경(18.04 desktop)을 기준으로 하자. <span style="background-color: white;">ESP-IDF는 당연히 Windows, macOS에서도 환경 설정이 가능하다. 하지만 필자는 언제나 그렇듯 Ubuntu에서 작업한다. 😎</span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html#"><span style="font-family: Nunito;">https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html#</span></a></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: #800180; font-family: Nunito;"><install전 사전 준비 작업></span></b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 10</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><i> => ESP-IDF에 포함된 python은 version 3를 기준으로 동작한다. 따라서 python3을 default로 변경하도록 하자.</i></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">update-alternatives: using /usr/bin/python3 to provide /usr/bin/python (python) in auto mode</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>python</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Python 3.6.9 (default, Oct 8 2020, 12:12:24) </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">[GCC 8.4.0] on linux</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Type "help", "copyright", "credits" or "license" for more information.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">>>> exit</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Use exit() or Ctrl-D (i.e. EOF) to exit</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">>>> exit()</span></div></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">$<b> sudo apt-get install git wget flex bison gperf python python-pip python-setuptools cmake ninja-build ccache libffi-dev libssl-dev</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><i> => 추가로 필요한 ubuntu package를 설치하자.</i></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">$ <b>sudo usermod -a -G dialout $YOURID</b></span></div><div class="separator" style="clear: both; text-align: left;"><i><span style="font-family: Nunito;"><span> => </span>super user 권한 없이 <span>flash(firmware writing) 명령 실행을 위해 반드시 필요하다. 즉, /dev/ttyUSB* 파일에 접근할 수 있도록 설정해 주도록 한다.</span></span></i></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: #800180; font-family: Nunito;"><ESP-IDF 설치></span></b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ mkdir esp32; cd esp32</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>git clone -b v4.1 --recursive https://github.com/espressif/esp-idf.git</b></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => git으로 부터 source code를 내려 받는다. 양이 좀 많아 오래 걸린다.</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ ls -la</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">합계 12</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">drwxr-xr-x 3 chyi chyi 4096 11월 20 11:03 .</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">drwxr-xr-x 3 chyi chyi 4096 11월 20 11:03 ..</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">drwxr-xr-x 9 chyi chyi 4096 11월 20 11:05 <b>esp-idf</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ cd esp-idf/</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ ls -la</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">합계 176</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 9 chyi chyi 4096 11월 20 11:05 .</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 11월 20 11:03 ..</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 682 11월 20 11:05 .editorconfig</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 8916 11월 20 11:05 .flake8</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 9 chyi chyi 4096 11월 20 11:05 .git</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 4 chyi chyi 4096 11월 20 11:05 .github</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 1197 11월 20 11:05 .gitignore</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 4870 11월 20 11:05 .gitlab-ci.yml</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2389 11월 20 11:05 .gitmodules</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 538 11월 20 11:05 .readthedocs.yml</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 4537 11월 20 11:05 CMakeLists.txt</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2406 11월 20 11:05 CONTRIBUTING.rst</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 15087 11월 20 11:05 Kconfig</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 11358 11월 20 11:05 LICENSE</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 5780 11월 20 11:05 README.md</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 5669 11월 20 11:05 README_CN.md</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2821 11월 20 11:05 SUPPORT_POLICY.md</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2516 11월 20 11:05 SUPPORT_POLICY_CN.md</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 723 11월 20 11:05 add_path.sh</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #6aa84f; font-size: x-small;">drwxr-xr-x 71 chyi chyi 4096 11월 20 11:05 </span><span style="color: #990000; font-size: x-small;">components</span></span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 5 chyi chyi 4096 11월 20 11:05 docs</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 15 chyi chyi 4096 11월 20 11:05 examples</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2059 11월 20 11:05 export.bat</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 2099 11월 20 11:05 export.ps1</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #6aa84f; font-size: x-small;">-rw-r--r-- 1 chyi chyi 4816 11월 20 11:05</span><span style="color: #990000; font-size: x-small;"> export.sh</span></span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 529 11월 20 11:05 install.bat</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 657 11월 20 11:05 install.ps1</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #6aa84f; font-size: x-small;">-rwxr-xr-x 1 chyi chyi 357 11월 20 11:05</span><span style="color: #990000; font-size: x-small;"> install.sh</span></span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">drwxr-xr-x 2 chyi chyi 4096 11월 20 11:05 make</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 971 11월 20 11:05 requirements.txt</span></div><div class="separator" style="clear: both;"><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 1958 11월 20 11:05 sdkconfig.rename</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #6aa84f; font-size: x-small;">drwxr-xr-x 21 chyi chyi 4096 11월 20 11:05</span><span style="color: #990000; font-size: x-small;"> tools</span></span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #800180; font-family: Nunito;"><toolchain 설치></span></b></div></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">$ <b>./install.sh</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><i> => Xtensa LX6 RISC CPU에 맞는 toolchain을 자동으로 설치한다.</i></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito; font-size: x-small;">...</span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Successfully built future</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Installing collected packages: click, pyserial, future, ipaddress, six, pycparser, cffi, enum34, cryptography, pyparsing, pyelftools</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">Successfully installed cffi-1.14.3 click-7.1.2 cryptography-3.2.1 enum34-1.1.10 future-0.18.2 ipaddress-1.0.23 pycparser-2.20 pyelftools-0.27 pyparsing-2.3.1 pyserial-3.4 six-1.15.0</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">All done! You can now run:</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;"> . ./export.sh</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>. ./export.sh</b></span></div></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => 환경 설정(file path, toolchain path 지정 등)을 역시 자동으로 해 준다.</span></i></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 시스템 재부팅 시마다 해 주어야 하므로 ~/.bashrc에 넣어주면 편리할 수 있다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">d) hello world 예제 돌려 보기</span></b></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">환경 설정이 마무리 되었으니 hello world 예제를 돌려 보도록 하자. 그전에 아래 그림과 같이 USB cable을 이용하여 target board와 PC를 연결해 주도록 한다.</span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_uT_mw_nPPAPwpAIhXL9_0SFRzJEw0mz_6dc-sV-rTgOomNd97pBCwTC5HdWxkY_hCtlmAzrF-I4Vg46gJ6NZHg1_infV7x7tLW_4JKR4aEBT_gREN13EPkaRXnb_HprrrKmR4K6kzUhE/s506/what-you-need1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="377" data-original-width="506" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_uT_mw_nPPAPwpAIhXL9_0SFRzJEw0mz_6dc-sV-rTgOomNd97pBCwTC5HdWxkY_hCtlmAzrF-I4Vg46gJ6NZHg1_infV7x7tLW_4JKR4aEBT_gREN13EPkaRXnb_HprrrKmR4K6kzUhE/s320/what-you-need1.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.4] Target board에 firmware image 올리기 <b>[출처 - 참고문헌 1]</b></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 위 그림은 예제 program을 하나 build하여 target board에 설치하는 과정을 보여준다.</span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;">ESP-IDF의 example은 일반적으로 아래와 같은 형태로 구성되어 있다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjIdNIgO41CNszMwmmKJrSkSTlmxhFLKrvQEBq3-pix7MY8Kg3MpoSQZ-3GHR8Llv8Le9bIJUyMMZGNBmWQwFXqd4Fueww7iTSpKE14zqCjhlhMCzDJdF63S9EkwqAgnxGcOX9IWJZeCtO/s695/esp32_example_project.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="695" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjIdNIgO41CNszMwmmKJrSkSTlmxhFLKrvQEBq3-pix7MY8Kg3MpoSQZ-3GHR8Llv8Le9bIJUyMMZGNBmWQwFXqd4Fueww7iTSpKE14zqCjhlhMCzDJdF63S9EkwqAgnxGcOX9IWJZeCtO/w640-h246/esp32_example_project.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: transparent;">[그림 2.5] example project 구성 </span><b style="background-color: transparent;">[출처 - 참고문헌 1]</b></div></span></div><div class="separator" style="clear: both;"><span style="background-color: white;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 ESP-IDF의 build system은 이전 posting에서 소개한 zephyr project의 그것과 유사하게 CMake와 Ninja/Make로 구성되어 있다. 또한 ESP-IDF는 idf.py로 build하고, zephyr는 west(python script)로 build하는 것도 유사하다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 CMake, Ninja/Make로 build system을 구성하는 것이 최근 trend인 듯하다 - Zephyr, AWS FreeRTOS, Azure RTOS 등이 모두 그렇게 되어있다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span>$ </span><b><span>c</span>d examples/get-started/hello_world</b></span></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => hello_world 디렉토리로 이동한다.</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuanp0XvBcRLBAw1JhZuWdNUE3hSnOToUhK0TAbZjuXhmu0DNj1Lm3HgHQ_utsmTSLg0Zi3jBGtMdOKRieb9lHA17Knp7iIhCVJUMLJXkDbTYCwbjuV8zOdSSL-KqNCoTiP2szFYF-NJpw/s788/esp32_hello_world_main.c.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="739" data-original-width="788" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiuanp0XvBcRLBAw1JhZuWdNUE3hSnOToUhK0TAbZjuXhmu0DNj1Lm3HgHQ_utsmTSLg0Zi3jBGtMdOKRieb9lHA17Knp7iIhCVJUMLJXkDbTYCwbjuV8zOdSSL-KqNCoTiP2szFYF-NJpw/s320/esp32_hello_world_main.c.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.6] hello_world_main.c 파일 내용</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 ESP-IDF application의 main 함수는 app_main( )이다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$<b> idf.py menuconfig</b></span></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => compile(build)을 위한 환경 설정을 한다.</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj929HTESWGZTHvhZiWHGCvbmqcQBGKEhOnIFiDzEIlGZLifF4GErJHIQ74OQFDiAyT6AiAlqUEVdcDpwxBTIZnK8zpb0YYvrznEPP97JkKuej6Ga5GZ3QBddqwRAqyDbrPz6MYP-UboY4B/s978/esp32_idfpy_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="626" data-original-width="978" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj929HTESWGZTHvhZiWHGCvbmqcQBGKEhOnIFiDzEIlGZLifF4GErJHIQ74OQFDiAyT6AiAlqUEVdcDpwxBTIZnK8zpb0YYvrznEPP97JkKuej6Ga5GZ3QBddqwRAqyDbrPz6MYP-UboY4B/w400-h256/esp32_idfpy_menuconfig.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy6lkknfOsCf5EaH5lbiPOno9j_mLpdZ9x4kbyhcB0CAC9gpsvFlMVYSY-nAfz9oNMb0ZTFnPAHmJwIrEglp34f6gMELQBW0RTOWmvYj8uLr9T1d4XNHh61rp-5cAz5o3dp9-NSWI72QZL/s983/esp32_idfpy_menuconfi2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="631" data-original-width="983" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy6lkknfOsCf5EaH5lbiPOno9j_mLpdZ9x4kbyhcB0CAC9gpsvFlMVYSY-nAfz9oNMb0ZTFnPAHmJwIrEglp34f6gMELQBW0RTOWmvYj8uLr9T1d4XNHh61rp-5cAz5o3dp9-NSWI72QZL/w400-h256/esp32_idfpy_menuconfi2.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.7] idf.py menuconfig 명령 실행 모습</span></div><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 ESP-IDF는 linux kernel 처럼 Kconfig를 이용하여 환경 설정을 한다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">menuconfig로 변경된 내용은 현재 directory의 sdskconfig 파일에 저장된다. 이는 linux kernel의 .config와 동일한 방식이라고 볼 수 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh374q2EYN2fNdSctgzk6nWrxmrrJFgYRMfONxOwfoRURSFHuv-417J_SM1nLsdD6fw1g-wJW7quOWsH7XYzi5nxchi3qGBwwrBaPI1ytOcynpPCjcqOaWTHPrtrH87qRbO0QZFybF9NhYb/s984/esp32_sdkconfig.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="608" data-original-width="984" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh374q2EYN2fNdSctgzk6nWrxmrrJFgYRMfONxOwfoRURSFHuv-417J_SM1nLsdD6fw1g-wJW7quOWsH7XYzi5nxchi3qGBwwrBaPI1ytOcynpPCjcqOaWTHPrtrH87qRbO0QZFybF9NhYb/s320/esp32_sdkconfig.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.8] sdkconfig 파일 내용 확인</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; text-align: center;">$ <b>idf.py build</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; text-align: center;"><i> => compile을 시도한다. 결과는 build 디렉토리에 생긴다.</i></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; text-align: center;"><br /></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh26m7I9lABbk54SfZXJKA6wtjivPnynXCbOHWxpSACrTlT5DSIH6Q0RPaoZbxTKbcpCPzCpluZWsr7Yaj17EzbstNt8Dw4mOY3d0V_O8uYxEurjGgehN58GIKy1RM5YeC362Zu9n8BvqNZ/s850/esp32_idfpy_build_result.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="577" data-original-width="850" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh26m7I9lABbk54SfZXJKA6wtjivPnynXCbOHWxpSACrTlT5DSIH6Q0RPaoZbxTKbcpCPzCpluZWsr7Yaj17EzbstNt8Dw4mOY3d0V_O8uYxEurjGgehN58GIKy1RM5YeC362Zu9n8BvqNZ/s320/esp32_idfpy_build_result.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.9] build 결과물 확인</span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; text-align: center;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB1 flash</b></span></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => build 디렉토리에 생성된 hello-world.bin 파일을 target board에 writing하도록 한다.</span></i></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => -p 다음에는 실제 Ubuntu에서 인식된 USB2serial device file 명을 입력해준다.</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnhfSn1v9Qk3waEbW7qEUcr6uJd5kt2fXSuhBmAq2Iupfg077xrsdZeqCaFtufxGlQ3DiiiuVG8QbVqX70uesIeB3AIZqVvgsb_ekL6mIpvnoIGToyYNj_X5XHah4UveI0YVGIaOzdWKQc/s990/esp32_idfpy_flash.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="687" data-original-width="990" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnhfSn1v9Qk3waEbW7qEUcr6uJd5kt2fXSuhBmAq2Iupfg077xrsdZeqCaFtufxGlQ3DiiiuVG8QbVqX70uesIeB3AIZqVvgsb_ekL6mIpvnoIGToyYNj_X5XHah4UveI0YVGIaOzdWKQc/s320/esp32_idfpy_flash.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.10] target board에 firmware image write하기</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 위 명령 실행 시 아래와 같은 메시지를 뿌리며 flash fail이 날 수 있는데, 이는 '<b>sudo usermode -a -G dialout $YOURID</b>' 내용이 반영되지 않았기 때문으로 이를 해결하려면 logout or reboot 후 다시 시도해 주면 된다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-size: 14.85px;"><span style="color: #674ea7; font-family: Nunito;">...</span></span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-size: 14.85px;"><span style="color: #674ea7; font-family: Nunito;">serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyUSB1: [Errno 13] Permission denied: '/dev/ttyUSB1'</span></span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-size: 14.85px;"><span style="color: #674ea7; font-family: Nunito;">...</span></span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB1 monitor</b></span></div><div class="separator" style="clear: both;"><i><span style="font-family: Nunito;"> => Serial console을 통해 target board에 올라간 firmware의 동작을 확인한다.</span></i></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 이 명령 대신 minicom(115200, 8N1)등을 이용해도 된다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYb7FOnHEIV3uZXUvhiIsdfcLecy5WEIcXv4Z0b8owUJc4_MfRMeBYGn_mPhUPucIg3toR9SvA-Hp6eg0UjUGpdIR7r3CqJu5oOiNyyilBVBzPqhyphenhyphencVQpDx73e8YXIqAdBGS7uJT7GVdAP/s1151/esp32_idfpy_monitor.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="835" data-original-width="1151" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYb7FOnHEIV3uZXUvhiIsdfcLecy5WEIcXv4Z0b8owUJc4_MfRMeBYGn_mPhUPucIg3toR9SvA-Hp6eg0UjUGpdIR7r3CqJu5oOiNyyilBVBzPqhyphenhyphencVQpDx73e8YXIqAdBGS7uJT7GVdAP/s320/esp32_idfpy_monitor.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.11] target board에 올라간 hello world program 동작 확인하기</span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #f1c232; font-family: Nunito; font-size: x-small;"><br /></span></div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">...</span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">...<br /></span><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">W (297) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">I (307) cpu_start: Starting scheduler on PRO CPU.</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">I (0) cpu_start: Starting scheduler on APP CPU.</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Hello world!</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">This is ESP32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 2MB external flash</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 10 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 9 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 8 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 7 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 6 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 5 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 4 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 3 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 2 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 1 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting in 0 seconds...</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">Restarting now.</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito; font-size: x-small;">ets Jun 8 2016 00:22:57</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">아래 내용은 debugging(w/ GDB)시, OpenOCD와 JTAG을 이용하고, </span><span style="font-family: Nunito;">flash writing & monitoring을 위해서는 </span><span style="font-family: Nunito;">esptool.py(idf.py에서 호출)와 USB2UART 장치를 이용할 수 있음을 하나의 그림으로 표현한 것이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPgEFd1zfkAFO3h2PKfZL1psttmVFu0kaZX_S_DnHi-kvTYR2ZlxSF9qYc85b2R7VjseD2giOU8sKU2nr_3Peh_WZF3aSW1IJI2-Exz2-I7z3zKXH3yYUwJwPj289jL1-sRxQCp_HcScod/s710/esp32_jtag_debugging.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="377" data-original-width="710" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPgEFd1zfkAFO3h2PKfZL1psttmVFu0kaZX_S_DnHi-kvTYR2ZlxSF9qYc85b2R7VjseD2giOU8sKU2nr_3Peh_WZF3aSW1IJI2-Exz2-I7z3zKXH3yYUwJwPj289jL1-sRxQCp_HcScod/w400-h213/esp32_jtag_debugging.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.12] JTAG debugging 및 flash writing & monitoring <b>[출처 - 참고문헌 1]</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">e) application startup flow</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">ESP32 SoC는 일반적인 32bit microprocessor와 마찬가지로 아래와 같은 (전형적인) 부팅 방식을 따른다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">bootloader(ROM) -> application(SPI flash)</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 참고로 ESP32는 secure boot(flash encryption)도 지원한다(편의상 여기에서는 소개하지 않음).</span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">Application image는 flash에 배치되는데, 아래 두개의 그림은 4MB SPI flash의 파티션 table의 구성 예를 보여준다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">먼저 아래 그림은 가장 기본적인 예(table layout)로 1개의 application(= factory app)이 0x10000(64KB) offset에 배치된 모습을 나타낸다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPxIO-afP4AyrrqG6WRXkGH1dLUU5fpI1WtbQorR1KKYWWdI1AOYH0XRRO1R8weUyS-nIB_lIoIcWxwWD0foW_zivs-ACBApb_53FIVWdDFnZr9MCdbMIlwuo7FSNI1B5Uoy5TaNGFVuS/s695/esp32_partition_table_basic.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="104" data-original-width="695" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmPxIO-afP4AyrrqG6WRXkGH1dLUU5fpI1WtbQorR1KKYWWdI1AOYH0XRRO1R8weUyS-nIB_lIoIcWxwWD0foW_zivs-ACBApb_53FIVWdDFnZr9MCdbMIlwuo7FSNI1B5Uoy5TaNGFVuS/w640-h96/esp32_partition_table_basic.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.13] ESP32 flash 파티션 테이블 예 - factory app 영역 할당 <b>[출처 - 참고문헌 1]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">한편, 다음 그림은 factory app 이외에도 2개의 OTA app 영역이 할당된 모습을 보여준다. 이때 어떤 녀석으로 부팅할지는 otadata 파티션 정보를 참조하여 bootloader가 결정하게 된다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdOShTt4ug3SQK9SCUj0l0hX1tt3ZfenXwoYpiD8HNQPNHNJ6wAPBgTl8Ri3gu0BilVGVbQSjZaL_jWdAyxM3P4d86wMtJrCwH9LDjioJVmKldEoxPE9qj6cvtzpAj9Qcu13KFeuCvYbk9/s695/esp32_partition_table_ota.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="155" data-original-width="695" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdOShTt4ug3SQK9SCUj0l0hX1tt3ZfenXwoYpiD8HNQPNHNJ6wAPBgTl8Ri3gu0BilVGVbQSjZaL_jWdAyxM3P4d86wMtJrCwH9LDjioJVmKldEoxPE9qj6cvtzpAj9Qcu13KFeuCvYbk9/w640-h142/esp32_partition_table_ota.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.14] ESP32 flash 파티션 테이블 예 - 1개의 factory app 및 2개의 OTA 영역 할당 <b>[출처 - 참고문헌 1]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 OTA(Over The Air)가 의미하는 것은 network(예: wifi)으로 firmware image를 download 받아 flash에 설치한다는 뜻이다. </span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">다음으로 알아볼 내용은 system reset 부터 application main 함수 - <i>app_main( )</i> - 까지의 코드 흐름에 관한 것이다. 특별한 설명 보다는 하나의 그림으로 이를 대신하고자 한다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ0TllnEsnRaxDartSnwKiUhFxUT3U3BK_wGRiN8kaJ96YicD-smI43TSfxpJnyvGafHb0VWUcdcLTrPdbcCu4NArd0k5EIVG6bPgLLYjs2-WnoixWw8hM_r0eZj4IEL25tl6rHf1SP-Q9/s661/esp32_main_call_flow.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="652" data-original-width="661" height="395" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ0TllnEsnRaxDartSnwKiUhFxUT3U3BK_wGRiN8kaJ96YicD-smI43TSfxpJnyvGafHb0VWUcdcLTrPdbcCu4NArd0k5EIVG6bPgLLYjs2-WnoixWw8hM_r0eZj4IEL25tl6rHf1SP-Q9/w400-h395/esp32_main_call_flow.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.15] ESP32의 booting flow - app_main( ) 함수 호출 과정</span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">___________________________________________________________________</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이상으로 ESP32용 SDK인 ESP-IDF를 설치하고, 간단한 예제 program 하나를 target board에서 돌려 보았다. 하나의 시스템을 제대로 이해하기 위해서는 파악해야 할 내용이 참으로 많다. (여기서는 수박 겉핥기 식으로 간략히 살펴 보았으니) 보다 자세한 사항은 아래 page 내용을 참조하기 바란다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html"><span style="font-family: Nunito;">https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html</span></a></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;"><b>3. FreeRTOS Programming</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이번 장에서는 ESP32 target board 상에서 몇가지 FreeRTOS 예제 program을 돌려 보고, 이를 분석해 보도록 하겠다. </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #45818e;">당초 계획은 아래 문서에서 설명하는 예제를 중심으로 FreeRTOS의 주요 개념(task, queue, timer, interrupt, event group 등)을 하나씩 상세히 소개하는 것이었으나, 시간 & 지면 관계상 ESP-IDF 예제 중 freertos API를 다양하게 사용하는 것을 골라 분석해 보는 것으로 이를 대신하고자 한다.</span> 😂</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">FreeRTOS를 제대로 이해하기 위해서는 우선적으로 아래 문서를 정독할 필요가 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #ff00fe; font-family: Nunito;"><a href="https://www.freertos.org/Documentation/RTOS_book.html">Mastering the FreeRTOS Real Time Kernel - A Hands On Tutorial Guide</a></span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">1장에서 언급한 바와 같이 FreeRTOS는 kernel core만으로 구성되어 있다. Code도 아주 간결하여 아래에 보이는 C(header file 포함) 파일이 전부이다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzoKXJDZLyqfnMZ9l6kPHkeapxCZm7MExStjWJhGkTgDZTbZ60BMPetvxWI_w7ss7Cw5idki4pGzxcUAnvRg9my3ofBDFebYz03pr7XGwIz0v59Xkh8i7X3qegRReaZ9GpqoTV73SN1-pc/s698/freertos_source.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="379" data-original-width="698" height="217" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzoKXJDZLyqfnMZ9l6kPHkeapxCZm7MExStjWJhGkTgDZTbZ60BMPetvxWI_w7ss7Cw5idki4pGzxcUAnvRg9my3ofBDFebYz03pr7XGwIz0v59Xkh8i7X3qegRReaZ9GpqoTV73SN1-pc/w400-h217/freertos_source.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.1] FreeRTOS source codes</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 FreeRTOS는 지난 15년간 (마치 street fighter 처럼) field에서 직접 부딪치며 튼튼하게 발전한 OS이다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">a) FreeRTOS 주요 개념</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">RTOS에서 task의 개념은 매우 중요하다. RTOS application은 task의 묶음이라고 해도 과언이 아닌데, 각각의 task는 자신만의 context 내에서 실행된다. 특정 시점에 동작하는 task는 오직 한개 뿐이며, task scheduler가 각각의 task가 언제 실행될 지를 결정하게 된다. Task는 또한 자신만의 stack을 할당 받게 되는데, 만일 task swap(교체)이 발생하여 다른 task가 실행된다면, 현재 task의 실행 context 정보는 자신의 stack에 저장되게 된다. 그래야 이 정보를 토대로 나중에 다시 실행될 때 이전 상태를 유지할 수 있는 것이다. </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #ff00fe; font-family: Nunito;"><b><Task and Scheduling></b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">FreeRTOS task는 두가지 상태 즉, <b><span style="color: #38761d;">Running</span> </b>state와 <b><span style="color: #990000;">Not Running</span></b> state(= <b><span style="color: #990000;">Blocked</span></b> state)를 갖게 되며, 상황에 따라 아래 [그림 3.2]와 같이 상태 전환(천이) 과정을 겪게 된다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinNEd2OWJaGuI6PIS7fsN11yuua9iMWxPvbJKapANaPFQxOLG8xQRrPQqSHE1UFFRBzg-C129QCMradUqfhwahm2DttEuWabTgL8NTZWPq6YKDO0w97v7vOM-qfG1FWi33NmO1IBwaZvX3/s604/freertos_task_states.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="314" data-original-width="604" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinNEd2OWJaGuI6PIS7fsN11yuua9iMWxPvbJKapANaPFQxOLG8xQRrPQqSHE1UFFRBzg-C129QCMradUqfhwahm2DttEuWabTgL8NTZWPq6YKDO0w97v7vOM-qfG1FWi33NmO1IBwaZvX3/s320/freertos_task_states.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.2] freertos task states <b>[출처 - 참고문헌2]</b></span></div><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1nZj13CSK_euq2X4KnHp7p5TXyJBBLTFJ3ZJeOZsWZ2y0CG28bjbpvZp4_bBwIml5OaMP5zs7u7NQr_on-ryt5js_8Mf0dkmGwoPi7x4HMZB5wRncux9zQN1qkFoHdLptJBp1NEE89RA/s659/freertos_task_state_machine.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="659" data-original-width="531" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1nZj13CSK_euq2X4KnHp7p5TXyJBBLTFJ3ZJeOZsWZ2y0CG28bjbpvZp4_bBwIml5OaMP5zs7u7NQr_on-ryt5js_8Mf0dkmGwoPi7x4HMZB5wRncux9zQN1qkFoHdLptJBp1NEE89RA/s320/freertos_task_state_machine.png" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.3] freertos task state machine <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: justify;"><span style="background-color: white; color: #b45f06; font-family: Nunito; text-align: left;">📌 task state & transition 부분은 Linux kernel의 그것과 크게 다르지 않다.</span></div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">FreeRTOS는 동일한 우선순위를 갖는 task가 일정한 시간 간격(time slice)를 두고 CPU를 사용할 수 있도록 하기 위해 <b>tick interrupt</b>(h/w timer를 이용하여 구현)라는 개념을 사용한다. <b><span style="color: #674ea7;">Task scheduler</span></b>는 tick interrupt가 발생할 때마다 next task가 누가될 지를 결정하게 된다. 아래 그림은 우선 순위가 동일한 2개의 task(Task1, Task2) 중 Task1이 실행되던 상태에서 tick interrupt가 발생했고, Kernel(task scheduler)이 다음번 task로 Task2를 선택한 모습을 보여준다.</span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhHj9qw-a1Whc2W4i_lOgChhi44cq1jdx9Pyi5tz25v3AXSjSHBXqFDP-MSUnBkbKb8v3fBI2iAY3wWgZZJbScadyEp7iIdgfGxwgkGzY_T5Puwpp3F2FZxzSlA0ER1TYhpSx009GDkdKh/s645/freertos_task_mgmt1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><span style="color: black;"><br /></span><img border="0" data-original-height="509" data-original-width="645" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhHj9qw-a1Whc2W4i_lOgChhi44cq1jdx9Pyi5tz25v3AXSjSHBXqFDP-MSUnBkbKb8v3fBI2iAY3wWgZZJbScadyEp7iIdgfGxwgkGzY_T5Puwpp3F2FZxzSlA0ER1TYhpSx009GDkdKh/s320/freertos_task_mgmt1.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] freertos task management 1 - scheduler의 역할 <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;">한편 아래 그림은 <b>idle task</b>의 개념을 설명하기 위한 것으로, 2개의 Task2, Task1이 차례로 vTaskDelay( ) 함수(일정시간 지연시 호출함)를 호출하여 각각 Blocked state로 전환될 경우, CPU를 사용하는 task가 하나도 남지 않아 program이 종료될 수 있으므로, 이때 idle task를 사용하여 이 문제를 해결할 수 있게 된다. Idle task는 CPU에 부담을 주지 않는 task를 말한다. </span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ651wF4RLlzfvAFfD8vkyYipjdk9RuiNbu3e-61l86rRu9Hd6iWJ6NXnKMxVu1FVXpRb5rWy_3OTpV6dQhcUSvB_To3agWwhLCL4ByB8tFQODV7NlIF-bNC9ORiPuHWvrNfAg_tSB8TaL/s770/freertos_task_mgmt2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="495" data-original-width="770" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZ651wF4RLlzfvAFfD8vkyYipjdk9RuiNbu3e-61l86rRu9Hd6iWJ6NXnKMxVu1FVXpRb5rWy_3OTpV6dQhcUSvB_To3agWwhLCL4ByB8tFQODV7NlIF-bNC9ORiPuHWvrNfAg_tSB8TaL/w400-h258/freertos_task_mgmt2.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] freertos task management 2 - idle task의 역할 <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">(FreeRTOSConfig.h 파일 설정에 따라 달라질 수 있지만) FreeRTOS는 기본적으로 preemptive scheduling을 사용한다. 즉, 우선 순위가 높은 task가 그렇지 못한 task로 부터 CPU를 가로챌 수 있다는 뜻이다. </span><span style="background-color: white; font-family: Nunito;"><b>FreeRTOS는 real-time behavior를 위해 각각의 task에 부여한 우선순위를 엄격하게 다룬다.</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsn0abiJt9UBE0OD-4o-u7Cb0FNJDheRBM0jeswrGiv7iWWj6Aa6UhMHHpNv1Nsgusq06w4sdNMDlWWlGGD0HlDm2hrb5GYF8f3ToLV9QIAICKMZuB-yGbW5uGG3jNK5_jNXqlsh0NY4CN/s741/freertos_preemption_scheduling.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="374" data-original-width="741" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsn0abiJt9UBE0OD-4o-u7Cb0FNJDheRBM0jeswrGiv7iWWj6Aa6UhMHHpNv1Nsgusq06w4sdNMDlWWlGGD0HlDm2hrb5GYF8f3ToLV9QIAICKMZuB-yGbW5uGG3jNK5_jNXqlsh0NY4CN/w400-h203/freertos_preemption_scheduling.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] freertos task management 3 - task 우선 순위 및 preemption <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 역시 정도의 차이는 있으나 task scheduling 부분도 </span><span style="background-color: white; color: #b45f06; font-family: Nunito;">(개념으로 볼 때) </span><span style="background-color: white; color: #b45f06; font-family: Nunito;">Linux kernel의 그것과 별반 다르지 않다. 물론 Real-time이라는 부분에서는 엄격한 차이를 보이긴 하지만 말이다. 예를 들어 linux의 경우 work queue로 던져진 task의 경우 언제 실행될 지 예측할 수가 없다. FreeRTOS에서는 이러한 방식을 절대로 용납하지 않는다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b style="color: #ff00fe; font-family: Nunito;"><Queue></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">FreeRTOS는 둘 이상의 task 간 or interrupt와 task 간의 message 전달 및 동기화 등의 목적으로 Queue(List) 개념을 사용한다. </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">Queue API에는 block time을 지정할 수 있는 parameter가 있는데, task가 비어 있는 queue에서 message를 읽으려 할 때, task는 읽을 수 있는 message가 새로 추가되거나, block time이 경과하게 될 때까지 Blocked state로 들어가게 된다. 이와 유사하게 queue가 꽉 차 있는 상태에서 task가 queue에 message가 쓰려고 할 경우에도 queue에 쓸 공간이 생기거나, block time이 경과할 때까지 해당 task는 Blocked state로 들어가게 된다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnNRt9YtZr_64jbyAT0vgcMyI3P54NVsQnQYhZHFb-7TzU23y9IYWjqJOXdwWFjPfvPYUOJnETxBAZpsucv7GtQww-TzzgfbS-M7WjGARCAZlvY4jynceIx8iiCIuvA0V73h1St4rjnhui/s1012/freertos_queue.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="144" data-original-width="1012" height="58" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnNRt9YtZr_64jbyAT0vgcMyI3P54NVsQnQYhZHFb-7TzU23y9IYWjqJOXdwWFjPfvPYUOJnETxBAZpsucv7GtQww-TzzgfbS-M7WjGARCAZlvY4jynceIx8iiCIuvA0V73h1St4rjnhui/w400-h58/freertos_queue.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.7] freertos queue management <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">아래 그림은 Queue 1개를 만든 상태에서 이를 사용하는 sender task가 여러 개(예: 3개)이고, receiver task가 1개인 예를 보여준다. 또한 Queue를 통해 전달하는 내용이 구조체 형태임도 알 수 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6MQ5fjWtoln85rv8c3_TxI1Zdd2JTx-FUg0l4BIfYXnvL2rfK8wtbjvmI6jqsr6nDWPuZlNCc4XchjIwUrQ73qR8s7CqVyUGjmoETGSeDzFrSw1NjS-hK-CjQ2FnusWqRP9Y5eiwujb3H/s890/freertos_queue_mgmt.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="424" data-original-width="890" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6MQ5fjWtoln85rv8c3_TxI1Zdd2JTx-FUg0l4BIfYXnvL2rfK8wtbjvmI6jqsr6nDWPuZlNCc4XchjIwUrQ73qR8s7CqVyUGjmoETGSeDzFrSw1NjS-hK-CjQ2FnusWqRP9Y5eiwujb3H/w400-h190/freertos_queue_mgmt.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.8] freertos queue management - multiple sender, 1 receiver <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><b style="color: #ff00fe;"><Timer></b></span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;">Timer는 정해진 시간(period)이 경과하면 원하는 action(function - callback function)을 수행하도록 하는 s/w 기능이다. FreeRTOS는 한차례 정해진 action만 실행하는 one-shot timer와 일정한 주기마다 자동으로 action을 반복 수행하는 auto-reload timer 두가지를 제공한다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3DXCSSozdbRf8ySVzLOtSfQ8ZB0rzGgyDkqFraYh4K6Oj9L7BqUVQ10N7-TMJwW4pr58ai11bRK8ApaET9Sz4AWLoLvP-7meDTDEEjeuz1EAXxYfy8SLRnvcUKwfGoa6UXAbYvrpgtCke/s838/freertos_sw_timer1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="339" data-original-width="838" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3DXCSSozdbRf8ySVzLOtSfQ8ZB0rzGgyDkqFraYh4K6Oj9L7BqUVQ10N7-TMJwW4pr58ai11bRK8ApaET9Sz4AWLoLvP-7meDTDEEjeuz1EAXxYfy8SLRnvcUKwfGoa6UXAbYvrpgtCke/w400-h161/freertos_sw_timer1.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.9] freertos s/w timer management 1 - one-shot, auto-reload timer <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg5xrAvod_lKWmiul2KYbpZ20O2_D0CRY3UxTEdBXa21e8Pb6FPA6CcxuczgMRpG0-YinOm3CIYta5wGqVzAWj1vNVOPo57yD4ka-Jg86zNyWajd2M5z3S2o7TUSUo841BYprlNsRu2np1/s739/freertos_auto_reload_timer.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="332" data-original-width="739" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhg5xrAvod_lKWmiul2KYbpZ20O2_D0CRY3UxTEdBXa21e8Pb6FPA6CcxuczgMRpG0-YinOm3CIYta5wGqVzAWj1vNVOPo57yD4ka-Jg86zNyWajd2M5z3S2o7TUSUo841BYprlNsRu2np1/s320/freertos_auto_reload_timer.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.10] freertos s/w timer management 2 - auto-reload timer의 상태도 <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">그렇다면 Timer의 action(function)은 누가 실행해 주는 것일까 ? 아래 그림에서 보는 것 처럼 RTOS <b>Daemon task</b>(scheduler 시작 시 자동으로 생성되는 task)라는 녀석이 있어서 timer function을 실행해 주게 된다. 아래 그림과 같이 Daemon task는 timer function을 실행하거나 timer를 중지하거나 등의 요청을 Timer Command Queue를 통해 다른 task(예: main routine)로 부터 전달받는 형태를 취한다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_BUJ8BqSIQ_ySVfS0sGr0yDmvrL9jzRHRLRw8Z94ONcE5MD5HlZN5YqR67aYyN4rajBfA9w-OHbVBxpzQnZRxRmq2P_ZOSnlZxd7RFMVg-wm01MAT1cmGGgWyHnPuHrtEiagLyaOYnenN/s950/freertos_sw_timer2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="539" data-original-width="950" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_BUJ8BqSIQ_ySVfS0sGr0yDmvrL9jzRHRLRw8Z94ONcE5MD5HlZN5YqR67aYyN4rajBfA9w-OHbVBxpzQnZRxRmq2P_ZOSnlZxd7RFMVg-wm01MAT1cmGGgWyHnPuHrtEiagLyaOYnenN/w400-h226/freertos_sw_timer2.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.11] freertos s/w timer management 3 - daemon task의 역할 <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 timer도 역시 linux의 그것과 별반 다르지 않다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;"><b style="color: #ff00fe;"><Interrupt and synchronization></b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">마지막으로 아래 그림은 <b>ISR</b>(Interrupt Service Routine)과 <b>지연처리 task</b>(deferring interrupt processing task)의 개념을 보여준다. ISR 내에서는 수행시간이 오래 걸리거나 Blocked state로 전환되는 API(함수)를 호출해서는 안된다. 따라서 이 때에는 시간이 많이 걸리는 부분을 별도의 task로 분리하여 실행(deferring task)해 줌으로써 ISR을 간소화시켜 주게 된다. 또한 별도로 분리된 task의 우선 순위를 여타 task에 비해 높게 설정해 줌으로써, interrupt service routine이 연속적으로 실행되는 효과를 가져오게 만들어 줄 수 있다. </span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4ud-UftiVBaR3Hr9gz58zswDBMZK-1mY41qibrt5yX7yWdY6CKGDLQ-2zhlLAKpE0nhUB3Rhb-7tzCTgWwRVadHJH0Cx8y-Pru0iEgZmBS4GklzXisBrEEg4wZNuMdLxaUcag1G3rKbm9/s727/freertos_ISR_binary_semaphore.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="473" data-original-width="727" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4ud-UftiVBaR3Hr9gz58zswDBMZK-1mY41qibrt5yX7yWdY6CKGDLQ-2zhlLAKpE0nhUB3Rhb-7tzCTgWwRVadHJH0Cx8y-Pru0iEgZmBS4GklzXisBrEEg4wZNuMdLxaUcag1G3rKbm9/w400-h260/freertos_ISR_binary_semaphore.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.12] freertos s/w interrupt service routine & deferring interrupt processing <b>[출처 - 참고문헌2]</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 위의 개념은 Linux의 interrupt(top half)와 bottom half(tasklet, workqueue, thread) 개념과 동일한 내용이라고 볼 수 있다.</span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 ISR내에서는 기존의 API 대신 "FromISR"로 끝나는 API만을 사용할 수 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">FreeRTOS는 mutual exclusion(상호배제) 및 synchronization(동기화)을 위해 binary semaphore, couting semaphore 및 mutex 기능을 제공한다. Binary semaphore는 2가지 값만을 가지고 있어서 task와 task 간 or task와 interrupt 간의 동기화를 맞추고자 할 때 쓰면 편리하다. Counting semaphore는 2개 이상의 값을 가지게 되므로, 2개 이상의 task간의 동기화를 맞추고자 할 때 사용할 수 있다. 마지막으로 mutex는 우선 순위 상속 메카니즘이 있는 일종의 binary semaphore라고 말할 수 있다. </span><span style="font-family: Nunito;">참고로 위의 그림(3.12)에는 Semaphore를 사용하여 ISR(semaphore give)과 지연처리 task인 Task2(semaphore take)를 동기화 시켜 주는 내용이 포함되어 있다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">이상으로 FreeRTOS의 개념과 관련하여 아주 기본적은 사항만을 요약해 보았다. 거의 370여 page에 달하는 FreeRTOS 관련 내용을 11개의 그림으로 응축해 놓았기 때문에, 당연히 추가로 확인해 보아야 할 내용(Heap management, Event group, Task notification 등)이 많이 있을 것으로 보인다. 부족한 설명은 독자 여러분의 몫으로 남겨두도록 한다. 😋</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #38761d; font-family: Nunito; font-size: medium;">b) FreeRTOS 예제 소개</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">앞서 FreeRTOS의 기본 동작 원리를 살펴 보았으니, 이제 부터는 간단한 예제를 하나 분석해 보도록 하자.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #a64d79; font-family: Nunito;">esp-idf/examples/system/freertos/real_time_stats</span></b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br />$ <b>cd esp-idf/examples/system/freertos/real_time_stats</b></span></div><div><span style="font-family: Nunito;">$ <b>idf.py menuconfig</b></span></div><div><span style="font-family: Nunito;">$ <b>idf.py build</b></span></div><div><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB1 flash</b></span></div><div><span style="font-family: Nunito;">$ <b>idf.py -p /dev/ttyUSB1 monitor</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_q6OzfmTR0Eivbw13rhhfa6NonZn-v4na3vCyPb21Bw7n1w59ohEGYwiZrycqLbPpDXfk5Skx9T7QSqxFFhdXNtWChPUN8QM8588l8xG2laBOM4XQZ8o6cy2n1wcU71p-X7a06TSFrggB/s956/esp32_exam_run.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="649" data-original-width="956" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_q6OzfmTR0Eivbw13rhhfa6NonZn-v4na3vCyPb21Bw7n1w59ohEGYwiZrycqLbPpDXfk5Skx9T7QSqxFFhdXNtWChPUN8QM8588l8xG2laBOM4XQZ8o6cy2n1wcU71p-X7a06TSFrggB/w400-h271/esp32_exam_run.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.13] <span style="text-align: left;">real_time_stats application 실행 모습</span></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">--------------------------------------------------- .<span style="color: #990000;">........................... <b>(A)</b></span></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito;">Getting real time stats over 100 ticks</span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito;">| Task | Run Time | Percentage</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| stats | 945 | 0% </span><span style="color: #f1c232;"># stats task</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin1 | 225416 | 11% </span> # spin task 1</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| IDLE1 | 390994 | 19% </span><span style="color: #38761d;"> # idle task 1(for cpu1)</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| IDLE0 | 288281 | 14% </span><span style="color: #38761d;"># idle task 1(for cpu0)</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin3 | 225379 | 11% </span># spin task 3</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin0 | 225412 | 11% </span># spin task 0</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin2 | 217254 | 10% </span># spin task 2</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin5 | 200956 | 10% </span># spin task 5</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| spin4 | 225362 | 11% </span><span style="color: #b45f06;"> </span># spin task 4</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| Tmr Svc | 0 | 0% </span><span style="color: #674ea7;"># daemon task(for timer)</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| ipc1 | 0 | 0% </span><span style="color: #666666;"># queue(for cpu1) ???</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| ipc0 | 0 | 0% </span><span style="color: #666666;"># queue(for cpu0) ???</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><span style="color: #b45f06;">| esp_timer | 0 | 0% </span><span style="color: #6fa8dc;"> # esp timer</span></span></div><div class="separator" style="clear: both;"><span style="color: #b45f06; font-family: Nunito;">Real time stats obtained</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">---------------------------------------------------</span></div></div></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">예상했겠지만, 코드 자체의 분량은 많지가 않다.</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">chyi@mars:~/workspace/Boards/ESP/esp32/esp-idf/examples/system/freertos/real_time_stats/main$ ls -la</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">합계 24</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">drwxr-xr-x 2 chyi chyi 4096 12월 1 20:57 .</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">drwxr-xr-x 4 chyi chyi 4096 11월 25 11:44 ..</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 98 11월 20 11:05 CMakeLists.txt</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 146 11월 20 11:05 component.mk</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 chyi chyi 6514 11월 20 11:05 <span style="color: #990000;">real_time_stats_example_main.c</span></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">real_time_stats_example_main.c 파일은 아래와 같이 4개의 함수로 이루어진 간단한 program에 불과하다. 이 program이 하는 일은 주기적으로 위의 결과 <b><span style="color: #990000;">(A)</span></b>를<b> </b>console에 출력(마치 Linux의 ps 명령 처럼)하는 것이 전부이다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">___________________________________________________________________________________</span></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFoN51NXwcE3hwTgHQWCf3SCRwaGCPDfQI6fVO18N5SH_R9RLA6nvTGh9TW0WlRFrunHPBTUFnTH4MAMD4DxyYbptRBvPFfPnaQJMXqoOi4lE90fprSU6opiAp5byKHsL9xsgKve_etrz9/s805/esp32_exam4.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="302" data-original-width="805" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFoN51NXwcE3hwTgHQWCf3SCRwaGCPDfQI6fVO18N5SH_R9RLA6nvTGh9TW0WlRFrunHPBTUFnTH4MAMD4DxyYbptRBvPFfPnaQJMXqoOi4lE90fprSU6opiAp5byKHsL9xsgKve_etrz9/s16000/esp32_exam4.png" /></span></a></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;">아래 함수는 stats_task( ) 함수에서 pdMS_TO_TICKS(1000)(= 1 초) 시간마다 한번씩 호출되는 함수로, 이곳에서 위의 결과 (A)를 출력한다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF3X4hixZdmRl_5KT0fO2HcylKXKOuq6zsGVlGa_griAU0DTg8kagSYXtKL5w3ntivOWN7b_oTwQ64oN7GDSDqy3KV1atFbLCftnLvxed0XZsKxDWpxPodNrKFoBlXY8tsioOV1orKUhbT/s880/esp32_exam3_3.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="738" data-original-width="880" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgF3X4hixZdmRl_5KT0fO2HcylKXKOuq6zsGVlGa_griAU0DTg8kagSYXtKL5w3ntivOWN7b_oTwQ64oN7GDSDqy3KV1atFbLCftnLvxed0XZsKxDWpxPodNrKFoBlXY8tsioOV1orKUhbT/s16000/esp32_exam3_3.png" /></span></a></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf3R9jzhYKsgk6uEwC-tVTBBUY-LLMcjWsQHz46raf_S9Y-3D0ICnnVWuT6Vzn3dfxHUWm-e2cKQ4ji-dMGCWbKT_e4JnO8WehGtkE-naUsn9xXPZSpNGGYl2P9mThSLDz_FalCdqToH3Q/s877/esp32_exam3_2.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><span style="font-family: Nunito;"><img border="0" data-original-height="678" data-original-width="877" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf3R9jzhYKsgk6uEwC-tVTBBUY-LLMcjWsQHz46raf_S9Y-3D0ICnnVWuT6Vzn3dfxHUWm-e2cKQ4ji-dMGCWbKT_e4JnO8WehGtkE-naUsn9xXPZSpNGGYl2P9mThSLDz_FalCdqToH3Q/s16000/esp32_exam3_2.png" /></span></a></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;">아래 두개의 함수는 app_main( )에서 생성한 두개의 task 함수이다.</span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;">먼저<b> spin_task</b>는 sync_spin_task semaphore가 해제되기를 기다린 후, 해제될 경우 while loop을 돌며 pdMS_TO_TICKS(100) 간격으로 CPU를 점유(점유 후, 단순히 No operation 수행)하도록 하는 단순한 코드이다.</span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;">반면에 <b>stats_task</b>는 역시 sync_stats_task semphore가 해제되기를 기다린 후, 해제 시 앞서 spin_tasks가 기다리는 sync_spin_task semaphore를 해제시켜 준다. 이후, while loop을 돌면서 pdMS_TO_TICKS(1000) 간격으로 print_real_time_stats( ) 함수를 호출해 준다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ibqgR4_Lkq5A3dRHpLeF9hwekvtDZd2NPcdZi7MOvkQ4YU2cTmAHMpcz-cZa2KqRZEf4u7kGMEaHxKm1TfMqJTVIXJk3YkDlmQBgmvm9XhhHe1jiJ25QxVLPS5LSLFTClX6AfbQ87cnN/s593/esp32_exam2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="559" data-original-width="593" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0ibqgR4_Lkq5A3dRHpLeF9hwekvtDZd2NPcdZi7MOvkQ4YU2cTmAHMpcz-cZa2KqRZEf4u7kGMEaHxKm1TfMqJTVIXJk3YkDlmQBgmvm9XhhHe1jiJ25QxVLPS5LSLFTClX6AfbQ87cnN/s16000/esp32_exam2.png" /></span></a></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><span style="color: #990000; font-family: Nunito;">아래 코드가 main routine이다. main routine이 하는 일은 간단 명료하다.</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><i><span style="color: #0b5394; font-family: Nunito;">1) 1개의 count semaphore sync_spin_task를 생성한다. 얘는 6개의 spin_task에서 사용하게 된다.</span></i></div><div class="separator" style="clear: both;"><i><span style="color: #0b5394; font-family: Nunito;">2) 1개의 binary semaphore sync_stats_task를 생성한다.</span></i></div><div class="separator" style="clear: both;"><i><span style="color: #0b5394; font-family: Nunito;">3) 6개의 spin_task를 생성한다. 여기에서는 xTaskCreate( ) 함수 대신 espressif에서 만든 xTaskCreatePinnedToCore( ) 함수를 사용한다.</span></i></div><div class="separator" style="clear: both;"><i><span style="color: #0b5394; font-family: Nunito;">4) 1개의 stats_task를 생성한다. 이때도 역시 xTaskCreate( ) 함수 대신 espressif에서 만든 xTaskCreatePinnedToCore( ) 함수를 사용한다.</span></i></div><div class="separator" style="clear: both;"><i><span style="color: #0b5394; font-family: Nunito;">5) 마지막으로, xSemaphoreGive(sync_stats_task)를 호출하여 sync_stats_task semaphore를 해제(give)한다.</span></i></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOpdtmsz8kzPVn9CjYlZOg-cZlYAE030HxwHwOZFrfjrGIZffqc_sEmdiQcUsUHUxmft6qI8ftAVDqphjaSknXROodD9MhMfW7JoV3ThLJIfWarLseJ4XYOBuYAQLVs6p5sRzdw9wrJX5/s862/esp32_exam1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="338" data-original-width="862" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMOpdtmsz8kzPVn9CjYlZOg-cZlYAE030HxwHwOZFrfjrGIZffqc_sEmdiQcUsUHUxmft6qI8ftAVDqphjaSknXROodD9MhMfW7JoV3ThLJIfWarLseJ4XYOBuYAQLVs6p5sRzdw9wrJX5/s16000/esp32_exam1.png" /></span></a></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito;">📌 </span><span style="color: #b45f06; font-family: Nunito;">xTaskCreatePinnedToCore( ) 함수와 관련해서는 아래 page의 내용을 살펴 보기 바란다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/freertos-smp.html#tasks-and-task-creation">https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/freertos-smp.html#tasks-and-task-creation</a></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">___________________________________________________________________________________</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;">지금까지 FreeRTOS의 동작 원리를 살펴 보고, FreeRTOS 예제를 하나 선택하여 그 코드를 분석해 보았다(Queue API 사용 부분이 빠져 있어서 좀 아쉽다).</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">4. 아직 못다한 이야기</span></b></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">ESP32는 Wi-Fi와 BLE를 위한 SoC이다. 따라서 ESP-IDF에는 이와 관련한 많은 예제가 포함되어 있다. 앞으로 시간을 두고 좀 더 살펴 보아야 하겠다. 😜</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>a) Wi-Fi programming</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/wifi.html">https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/wifi.html</a></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>b) BLE programming</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/bluetooth/index.html">https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/bluetooth/index.html</a></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>c) 주변 장치 device driver</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/peripherals/index.html">https://docs.espressif.com/projects/esp-idf/en/stable/api-reference/peripherals/index.html</a></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>d) FreeRTOS SMP changes</b></span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/freertos-smp.html">https://docs.espressif.com/projects/esp-idf/en/stable/api-guides/freertos-smp.html</a></span></div><div><span style="font-family: Nunito;"><br /></span></div></div></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>e) Secure Boot</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/security/secure-boot-v1.html">https://docs.espressif.com/projects/esp-idf/en/stable/security/secure-boot-v1.html</a></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>f) Flash encryption</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><a href="https://docs.espressif.com/projects/esp-idf/en/stable/security/flash-encryption.html">https://docs.espressif.com/projects/esp-idf/en/stable/security/flash-encryption.html</a></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #b45f06; font-family: Nunito; font-size: large;"><b>To be continued...</b></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><br /></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><b><span style="color: #3d85c6; font-family: Nunito; font-size: x-large;">5. References</span></b></div></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">[1] https://docs.espressif.com/projects/esp-idf/en/stable/get-started/index.html</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">[2] Mastering the FreeRTOS Real Time Kernel - A Hands On Tutorial Guide, Richard Barry</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">[3] The FreeRTOS Reference Manual, Richard Barry</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">[4] 2019 Embedded Markets Study - Integrating IoT and Advanced Technology Designs,</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">Application Development & Processing Environments, March 2019, AspenCore</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[5] https://aws.amazon.com/ko/blogs/korea/announcing-amazon-freertos/</span></div><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[6] 사물인터넷을 품은 라즈베리파이 개정판, 김성우, Jpub</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[7] https://www.cnx-software.com/2016/03/25/esp8266-and-esp32-differences-in-one-single-table/</span></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[8] And, Google~</span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: right;"><b><span style="color: #38761d; font-family: Nunito;">Slowboot</span></b></div><div class="separator" style="clear: both; text-align: left;"><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com10tag:blogger.com,1999:blog-6346200245600677355.post-80948218679026347842020-11-06T15:54:00.000+09:002020-11-06T15:54:07.283+09:00Zephyr RTOS Project<h4 style="text-align: left;"><span style="font-weight: normal;"><span style="font-family: Nunito;">이번 시간에는 3년 전에 한차례 소개한 바 있는 <a href="https://www.zephyrproject.org/">Zephyr RTOS Project</a>를 다시 조명해 보고자 한다. 그 동안 많은 변화(v1.7 -> v2.4.99)가 있었는데, 왜 Zephyr가 앞으로 성공할 수 밖에 없는지 하나 하나 파헤쳐 보도록 하자. 😎</span></span></h4><div><span style="font-weight: normal;"><span style="font-family: Nunito;"><br /></span></span></div><div><span style="font-weight: normal;"><span style="font-family: Nunito;"><br /></span></span></div><div><div class="separator" style="clear: both; font-weight: normal; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_NEM7ocZrcDOU6YGY-l7SNTbhup-hCVYVw504rExiX7iH8esnA9qVMHQrMJpW48wE9-sU_4ScW_bewX8kTSpEZsH8bWb1wYTV11qP4Obd2aVW5-qXPk0AQIS7Ukov6QnOJFWamULpeZcL/s198/zephyr_logo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="117" data-original-width="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_NEM7ocZrcDOU6YGY-l7SNTbhup-hCVYVw504rExiX7iH8esnA9qVMHQrMJpW48wE9-sU_4ScW_bewX8kTSpEZsH8bWb1wYTV11qP4Obd2aVW5-qXPk0AQIS7Ukov6QnOJFWamULpeZcL/s0/zephyr_logo.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><b>RTOS/IoT OS 계의 새로운 바람~</b></span></div></div><h4 style="text-align: left;"><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;">목차</span><br /><div style="text-align: left;"><span style="font-family: Nunito;"><i style="font-weight: normal;">1. Zephyr reloaded</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i style="font-weight: normal;">2. Zephyr 개발 환경 설정<br /></i></span><span style="font-family: Nunito;"><i style="font-weight: normal;">3. Build system 소개<br /></i></span><span style="font-family: Nunito;"><i style="font-weight: normal;">4. Device tree 기반의 device driver model <br /></i></span><span style="font-family: Nunito;"><i style="font-weight: normal;">5. 아직 못다한 이야기</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i style="font-weight: normal;">6. References</i></span></div></h4><p style="text-align: left;"><span style="color: #3d85c6; font-family: Nunito;"><br /></span></p><div style="text-align: left;"><span style="font-family: Nunito;"><span style="color: #674ea7;">아래 내용을 소개하기에 앞서 3년 전에 작성해 둔 아래 posting을 먼저 확인해 보기 바란다.</span></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2017/03/zephyr-project.html">https://slowbootkernelhacks.blogspot.com/2017/03/zephyr-project.html</a></span></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div><div style="text-align: left;"><div><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">1. Zephyr reloaded</span></b></div><div><div><span style="font-family: Nunito;">3년 전 v1.7에 비해 이 글을 쓰고 있는 현재(2020. 11) v2.4.99 버젼이 나오기까지 눈에 띄는 변화는 <b>CMake, Ninja/Make & Python3를 중심으로 하는 build system</b>과 swiss army knife에 해당하는 <b><span style="color: #b45f06;">west</span></b>(python으로 작성)라는 tool이 추가된 점을 들 수 있다. 또한 200여개 이상의 board를 지원하면서 다양한 soc 및 board 관련 코드가 추가되었고, 많은 보드의 다양한 device를 효과적으로 처리하기 위해 (linux 처럼) <b>device tree를 기반으로 하는 device driver model</b>이 제대로 정착되었다는 점 등을 꼽을 수 있을 것 같다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><span style="color: #674ea7; font-family: Nunito;"><b>주요 구성 요소:</b></span></div><div><span style="font-family: Nunito;"><div><span style="white-space: pre;"> </span>− <b>Python 3</b>: Script interpreter and packages</div><div><span style="white-space: pre;"> </span>− <b>CMake/Ninja/Make</b>: Build system</div><div><span style="white-space: pre;"> </span>− <b>Device Tree </b>Compiler: Compiles device tree hardware descriptions</div><div><span style="white-space: pre;"> </span>− <b>Toolchain</b>: gcc for Arm, RISC-V, x86, etc.</div><div><span style="white-space: pre;"> </span>− <b>Debug/Flash Tools</b>: J-Link, pyOCD, OpenOCD, etc.</div><div><span style="white-space: pre;"> </span>− <b>West</b>: Custom tool for repository management, build/flash/debug assistance, and image signing</div><div><span style="white-space: pre;"> </span>− <b>Zephyr Git repositories</b>: The source code!</div></span></div></div></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #674ea7;">주요 특징:</span></b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">1) Zephyr는 Linux를 사용하기에는 부담이 되는 작은 시스템(resource constrained system)을 target으로 하고 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><b>Linux Foundation's Strategy</b></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><b><span style="color: #b45f06;">Zephyr</span></b>(resource constrained system) +<b><span style="color: #38761d;"> Linux</span></b>(resource not constrained system)</span></div><div style="text-align: center;"><span style="font-family: Nunito;">=</span></div><div style="text-align: center;"><span style="font-family: Nunito;">IoT Devices based on Zephyr + IoT Gateway based on Linux</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGWPErDTrU8rIRRacMhU_MBd7gaH_0-BCSlp7KTcAyjO8df9ochAG82qkPkEVqNyNXQViNyYh9wmK7E2eOey3nkwRJGn1zggc8rpU-JV-Za03u5ALpMeFe5-kc_Sund88pfw6uEiOjofFX/s603/zepyhr_overview.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="603" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGWPErDTrU8rIRRacMhU_MBd7gaH_0-BCSlp7KTcAyjO8df9ochAG82qkPkEVqNyNXQViNyYh9wmK7E2eOey3nkwRJGn1zggc8rpU-JV-Za03u5ALpMeFe5-kc_Sund88pfw6uEiOjofFX/s320/zepyhr_overview.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.1] Zephyr RTOS Overview </span><b style="font-family: Nunito;">[출처 - 참고 문헌 2]</b></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">2) Zephyr는 여타 RTOS(예: FreeRTOS, ARM mbedOS, NuttX 등)와 마찬가지로 RTOS 및 IoT OS를 위해 필요한 왠만한 기능은 이미 다 갖추고 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM-LW44XkYMFAKl0UBCiBrX0x4hhpcKB1lPYKkUJEAcidCN3iidsv4B0jjRqTgNBzdjmIPYwZzaoRDsgZWFNDN-dV3CztivGnflbPKXCNWGu_0SBHYDgV4b8xsZyYx4DzYteUrC5l2mx_h/s660/zephyr_architecture.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="555" data-original-width="660" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM-LW44XkYMFAKl0UBCiBrX0x4hhpcKB1lPYKkUJEAcidCN3iidsv4B0jjRqTgNBzdjmIPYwZzaoRDsgZWFNDN-dV3CztivGnflbPKXCNWGu_0SBHYDgV4b8xsZyYx4DzYteUrC5l2mx_h/s320/zephyr_architecture.png" width="320" /></a> </div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.2] Zephyr RTOS Architecture </span><b style="font-family: Nunito;">[출처 - 참고 문헌 2]</b></div><span style="font-family: Nunito;"><div style="text-align: left;"><br /></div><div style="text-align: left;">3) Zephyr는 이제 200개 이상의 board(ARM Cortex-M 계열, x86, ARC, XTENSA 등)를 지원하며, 다양한 상용 제품에 널리 활용되고 있다.</div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhctp9MP6BYaea88MnlKYe3n8amxV1KmdtZlaif2WDuW4Afr82doMgKNufTBcMKuboCuMPbyYRDYMnJ47Z1ogtrwdpEMyWMsp5zzDmBtYmsPhh9qZGEQJCWHUmXd8SlnuBs0L_8kSEGJnVq/s1244/zephyr_boards.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="534" data-original-width="1244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhctp9MP6BYaea88MnlKYe3n8amxV1KmdtZlaif2WDuW4Afr82doMgKNufTBcMKuboCuMPbyYRDYMnJ47Z1ogtrwdpEMyWMsp5zzDmBtYmsPhh9qZGEQJCWHUmXd8SlnuBs0L_8kSEGJnVq/s320/zephyr_boards.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.3] Zephyr 지원 보드 - 200개 이상(2020년 현재) <b>[출처 - 참고 문헌 2]</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju1PL4Bob73PMuvkkzO-XPoDW6YOBAuiSuxQtk6ougle63ll77qyunmyAdRw1iQZSDI3KMWnX03p_U1eo-FAlx-CjdpoONMZIFqDEs8v6fEC-DzCrQuWsjQ7QN1Oln5LzzQ0O1T1G8n7oD/s1260/zephyr_products.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="596" data-original-width="1260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEju1PL4Bob73PMuvkkzO-XPoDW6YOBAuiSuxQtk6ougle63ll77qyunmyAdRw1iQZSDI3KMWnX03p_U1eo-FAlx-CjdpoONMZIFqDEs8v6fEC-DzCrQuWsjQ7QN1Oln5LzzQ0O1T1G8n7oD/s320/zephyr_products.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.4] Zephyr를 활용한 상용 제품 <b>[출처 - 참고 문헌 2]</b></div></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">4) 문서 정리가 아주 잘 되어 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6a9Z1k5Jp3PstM5Yo2Q7NA4qBzPKWQBginMmaBS909pCR14trCgSpMy_biBsrvokdhgxt8dKhdWi1pgI2llnqmHyoBSwo0gNru8gCFszp-7hqBymrVUK4uxdA2dM_rdWsep4C9BEiWo1C/s1210/zephyr_docs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="725" data-original-width="1210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6a9Z1k5Jp3PstM5Yo2Q7NA4qBzPKWQBginMmaBS909pCR14trCgSpMy_biBsrvokdhgxt8dKhdWi1pgI2llnqmHyoBSwo0gNru8gCFszp-7hqBymrVUK4uxdA2dM_rdWsep4C9BEiWo1C/s320/zephyr_docs.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.5] Zephyr Documentation</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/">https://docs.zephyrproject.org/latest/</a></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">5) 특정 회사, 개인이 중심이 되어 개발된 project가 아니라 community가 그 중심인 project라는 면에서 </span><span style="font-family: Nunito;">Zephyr만이 진정한 의미에서의 open source RTOS 이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">____________________</span></div><div style="text-align: left;"><span style="font-family: Nunito;">아래 내용은 Zephyr 진영에서 작성한 것이긴 하지만, zephyr가 여타 RTOS에 비해 지난 1년간 가장 활발히 개발되고 있는 open source RTOS project임을 보여준다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQSbf18e6fOomReXvrchxtcteI0scI70vg6MCvRjPJjcoSfbz0Gd5rSm3ah7sBkgWGYr2eyy1hcmzoXymVGpBFWw55Gwij4x6phI57HrorCjLKU_j6_bR_5HSefArb9RB04xbB1qZGUuLC/s1252/zephyr_upstream_commits.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="593" data-original-width="1252" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQSbf18e6fOomReXvrchxtcteI0scI70vg6MCvRjPJjcoSfbz0Gd5rSm3ah7sBkgWGYr2eyy1hcmzoXymVGpBFWw55Gwij4x6phI57HrorCjLKU_j6_bR_5HSefArb9RB04xbB1qZGUuLC/s320/zephyr_upstream_commits.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 1.6] 지난 해 RTOS 간 commit 횟수 비교 </span><b style="font-family: Nunito;">[출처 - 참고 문헌 2]</b></div><div class="separator" style="clear: both; text-align: center;"><b style="font-family: Nunito;"><br /></b></div></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Code commit이 활발하다는 것은 말 그대로 가장 관심이 높다는 의미이기도 하겠지만, 아직 개발할 게 많이 남아있다는 의미일 수도 있겠다. 참고로 우측의 FreeRTOS는 sourceforge => Github으로 전환한 것이 얼마되지 않아 활동량이 많지 않다는 얘기도 있다.</span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><span style="font-size: 14.85px;">📌 현재까지 RTOS 1위는 FreeRTOS(얼마 전에 AWS에서 인수하여 AWS FreeRTOS로 판매 중)이지만, 그 뒤를 ARM mbedOS가 바짝 뒤 쫒고 있는 듯하다. 하지만 머지 않아 Zephyr가 이들을 제치고 그 위용을 들어낼 날이 곧 올 것으로 믿어 의심치 않는다.</span></span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><span style="font-size: 14.85px;">📌 참고로 위 그림에는 없지만 최근 (개인적으로 별로 좋아하지 않는)M$에서도 Azure Sphere라는 RTOS를 밀고 있는 듯하다.</span></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;">그야말로 RTOS 춘추 전국 시대 ~ 특정 RTOS가 천하를 통일할 것으로는 보지 않는다. 하지만 여러가지 면에서 볼 때 Zephyr는 장래가 매우 촉망되는 RTOS임에 틀림없어 보인다. 😍</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">2. Zephyr 개발 환경 설정</span></b></div></div><div style="text-align: left;"><span style="font-family: Nunito;">Zephyr 개발 환경 구축과 관련해서는 아래 site에 아주 정리가 잘 되어 있다(그대로 따라하기만 하면 된다 😋). 기존(make 중심)에 비해 설치 과정이 다소 복잡해 진 느낌이나, west라는 tool이 추가되어 있어 전체적으로 편리해 진 것도 사실이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/getting_started/index.html">https://docs.zephyrproject.org/latest/getting_started/index.html</a></span></div><div style="text-align: left;"><span style="font-weight: normal;"><span style="font-family: Nunito;"><br /></span></span></div><div style="text-align: left;"><span style="font-family: Nunito;">이 절에서는 Ubuntu 18.04를 기준으로 환경 설정을 해 보도록 하겠다. 상세한 내용은 위의 page를 참조하기 바란다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 당연히 Windows, macOS 등에서도 개발 가능하다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div style="text-align: left;"><span style="color: #ff00fe; font-family: Nunito;"><b><package 설치></b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div>$<b> sudo apt update</b></div><div>$ <b>sudo apt upgrade</b></div><div><br /></div><div><div>$<b> sudo apt install --no-install-recommends git cmake ninja-build gperf \</b></div><div><b> ccache dfu-util device-tree-compiler wget \</b></div><div><b> python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \</b></div><div><b> make gcc gcc-multilib g++-multilib libsdl2-dev</b></div><div><br /></div><div><b><span style="color: #ff00fe;"><cmake upgrade></span></b></div><div>$ <b>cmake --version</b></div><div>cmake version 3.10.2</div></div><div><br /></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 cmake version 3.13.1 이상이어야 한다. 따라서 아래 내용을 수행해 준다.</span></div><div><div>$ <b>wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -</b></div><div>$ <b>sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main'</b></div><div>$ <b>sudo apt update</b></div><div>$ <b>sudo apt install cmake</b></div><div><br /></div><div>$<b> cmake --version</b></div><div>cmake version 3.18.4</div></div><div><br /></div><div><b><span style="color: #ff00fe;"><zephyr 설치 및 python 관련 package 설치></span></b></div><div>$ <b>pip3 install --user -U west</b></div><div><div>$ <b>echo 'export PATH=~/.local/bin:"$PATH"' >> ~/.bashrc</b></div><div>$ <b>source ~/.bashrc</b></div></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 python으로 작성된 west는 source code download(마치 repo와 같은 역할)는 물론이고 build 시에도 사용된다.</span></div><div><br /></div><div>$ <b>west init ~/zephyrproject</b></div><div>$ <b>cd ~/zephyrproject</b></div><div>chyi@mars:~/zephyrproject$ <b>west update</b></div><div><br /></div><div><div>chyi@mars:~/zephyrproject$<b> ls -la</b></div><div><span style="font-size: x-small;">합계 28</span></div><div><span style="font-size: x-small;">drwxr-xr-x 7 chyi chyi 4096 10월 30 10:38 .</span></div><div><span style="font-size: x-small;">drwxr-xr-x 21 chyi chyi 4096 10월 30 10:40 ..</span></div><div><span style="font-size: x-small;">drwxr-xr-x 2 chyi chyi 4096 10월 30 10:35 .west</span></div><div><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 10월 30 10:38 bootloader</span></div><div><span style="font-size: x-small;">drwxr-xr-x 9 chyi chyi 4096 10월 30 10:39 modules</span></div><div><span style="font-size: x-small;">drwxr-xr-x 5 chyi chyi 4096 10월 30 10:39 tools</span></div><div><span style="font-size: x-small;">drwxr-xr-x 23 chyi chyi 4096 10월 30 10:35 zephyr</span></div></div><div><br /></div><div><div>chyi@mars:~/zephyrproject$ <b>west zephyr-export</b></div><div><span style="font-size: x-small;">Zephyr (/home/chyi/zephyrproject/zephyr/share/zephyr-package/cmake)</span></div><div><span style="font-size: x-small;">has been added to the user package registry in:</span></div><div><span style="font-size: x-small;">~/.cmake/packages/Zephyr</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;">ZephyrUnittest (/home/chyi/zephyrproject/zephyr/share/zephyrunittest-package/cmake)</span></div><div><span style="font-size: x-small;">has been added to the user package registry in:</span></div><div><span style="font-size: x-small;">~/.cmake/packages/ZephyrUnittest</span></div><div><br /></div><div><br /></div><div>chyi@mars:~/zephyrproject/zephyr$<b> pip3 install --user -r ~/zephyrproject/zephyr/scripts/requirements.txt</b></div></div><div><br /></div><div><b><span style="color: #ff00fe;"><toolchain 설치></span></b></div><div>chyi@mars:~/workspace/Zephyr$ <b>wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.11.4/zephyr-sdk-0.11.4-setup.run</b></div><div>chyi@mars:~/workspace/Zephyr$ <b>chmod 755 ./zephyr-sdk-0.11.4-setup.run</b></div></span><span style="font-family: Nunito;"><div>chyi@mars:~/workspace/Zephyr$ <b>./zephyr-sdk-0.11.4-setup.run -- -d ~/zephyr-sdk-0.11.4</b></div><div><div>chyi@mars:~/zephyr-sdk-0.11.4$ ls -la</div><div><span style="font-size: x-small;">합계 56</span></div><div><span style="font-size: x-small;">drwxr-xr-x 13 chyi chyi 4096 10월 30 11:05 .</span></div><div><span style="font-size: x-small;">drwxr-xr-x 23 chyi chyi 4096 10월 30 11:04 ..</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 20:49 aarch64-zephyr-elf</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 21:50 arc-zephyr-elf</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 21:56 arm-zephyr-eabi</span></div><div><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 6월 25 20:42 cmake</span></div><div><span style="font-size: x-small;">drwxr-xr-x 2 chyi chyi 4096 10월 30 11:05 info-zephyr-sdk-0.11.4</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 21:00 nios2-zephyr-elf</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 21:05 riscv64-zephyr-elf</span></div><div><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 7 10월 30 11:05 sdk_version</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 21:01 sparc-zephyr-elf</span></div><div><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 6월 25 21:15 sysroots</span></div><div><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 6월 25 20:50 x86_64-zephyr-elf</span></div><div><span style="font-size: x-small;">drwxrwxr-x 9 chyi chyi 4096 10월 30 11:05 xtensa</span></div></div><div><br /></div><div><div>chyi@mars:~/workspace/Zephyr$ <b>sudo cp ~/zephyr-sdk-0.11.4/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d</b></div><div><br /></div><div>$ <b>sudo udevadm control --reload</b></div></div><div><br /></div><div><span style="background-color: white; font-size: 14.85px;">필자는 Linux 환경에 익숙해서인지 terminal 환경에서 개발하는 것을 좋아한다. 하지만 IDE 개발 환경을 선호하는 개발자들도 많은데, 이를 위해 zephyr는 아래의 두가지 방식을 지원한다.</span></div><div><span style="background-color: white; font-size: 14.85px;"><br /></span></div><div><span style="background-color: white; font-size: 14.85px;"><i>1) Eclipse 환경</i></span></div><div><span style="background-color: white; font-size: 14.85px;"><i><br /></i></span></div><div style="text-align: center;"><span style="background-color: white; font-size: 14.85px;"><a href="https://docs.zephyrproject.org/latest/application/index.html#important-build-system-variables">https://docs.zephyrproject.org/latest/application/index.html#important-build-system-variables</a></span></div><div><span style="background-color: white; font-size: 14.85px;"><i><br /></i></span></div><div><span style="background-color: white; font-size: 14.85px;"><i>2) (Third party에서 개발한) Platform IO(Visual Studio plugin) 환경</i></span></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE7or-0O2EodLWl1eA6BuyDFJ8NhWDgRceaMm9UuFEgh1fNMUN4H6G1xCJ5H-tFEqwwM_qozrO0rkSXWVccxYkY0m0EuHWsE8MLUYs7dZ6NhD7T3PMhGbSlU0ue0iA2qz6j8ODlaQpSbBV/s556/zephyr_platformio.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="132" data-original-width="556" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE7or-0O2EodLWl1eA6BuyDFJ8NhWDgRceaMm9UuFEgh1fNMUN4H6G1xCJ5H-tFEqwwM_qozrO0rkSXWVccxYkY0m0EuHWsE8MLUYs7dZ6NhD7T3PMhGbSlU0ue0iA2qz6j8ODlaQpSbBV/s320/zephyr_platformio.png" width="320" /></a></div><div style="text-align: center;"><a href="https://docs.zephyrproject.org/latest/guides/platformio/index.html">https://docs.zephyrproject.org/latest/guides/platformio/index.html</a></div></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></div><div><br /></div><div>자, zephyr 개발 환경이 모두 준비되었으니, 이제부터는 실제 예제를 하나 돌려 보면서 zephyr build system이 어떻게 동작하는지를 살펴 보도록 하자.</div><div><br /></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">3. Build system 소개</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">이 장에서는 zephyr sample code를 하나 돌려본 후, 실제 build 시스템이 어떻게 구성되어 있는지를 그림을 통해 상세히 파악해 볼 것이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both; text-align: justify;"><b style="color: #38761d; font-family: Nunito; font-size: large; text-align: left;">a) Target board</b></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">예제 코드를 돌려 보기 위해서는 target board가 하나 필요한데, 지금부터는 아래 보드를 사용하기로 한다.</span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8oHigoVyrTfZjw1gHEPWrpqoo_1U3ZP-6UPy_Q6iHUfY_KFFvmsRtQDtFA3rNaQ-m4vjfuJFKBmBAortfH_h41_-X4nPRGLhvZV5MbbEOWboGPQh-T7QGZx0JqRoGLzM1f4mFDg9YvQtn/s259/nucleo_f103rb.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="194" data-original-width="259" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8oHigoVyrTfZjw1gHEPWrpqoo_1U3ZP-6UPy_Q6iHUfY_KFFvmsRtQDtFA3rNaQ-m4vjfuJFKBmBAortfH_h41_-X4nPRGLhvZV5MbbEOWboGPQh-T7QGZx0JqRoGLzM1f4mFDg9YvQtn/s0/nucleo_f103rb.jpeg" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><b><span style="color: #ff00fe;">ARM Cortex-M3, 72Mhz, 128KB Flash, 20KB SRAM, ST-Link/V2 debugger 장착</span></b></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.1] <span style="font-size: 16px; text-align: left;"> Target Board - </span><span style="font-size: 16px; text-align: left;">STM32 Nucleo</span><span style="font-size: 16px; text-align: left;"> F103RB<b> [출처 - 참고문헌 3]</b></span></span></div></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 Nucleo F103RB 보드는 $10 ~ 15(한화로 13,000 ~ 14,000원 정도) 정도로 가격이 아주 저렴하다. </span><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">또한 ST-Link/V2 debugger(선이 그어져 있는 그림 우측 부분)가 장착되어 있어, 곧 바로 flash writing이 가능하다. </span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">b) 예제 build해 보기 - synchronization</b></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><div class="separator" style="clear: both;">chyi@mars:~$<b> cd ~/zephyrproject/</b></div><div class="separator" style="clear: both;">chyi@mars:~/zephyrproject$ <b>cd zephyr/</b></div></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">chyi@mars:~/zephyrproject/zephyr$ <b>west build -b <span style="color: #990000;">nucleo_f103rb</span> -s samples/synchronization</b></span></div></div></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaie5DFlf_7YAXKy4VCkeqmxbR6mry6RAnBo0S0BtoLhdrXLUYpNQsOmT8MyjkU7gkfwQYSdnC4azzaGT_FJg0zEjMyWO3mLJz4EBl_mGJdS-zdYgXf_fd-segRzgOwGXjInQwLSxQZE3R/s1321/zephyr_build_ex.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="665" data-original-width="1321" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaie5DFlf_7YAXKy4VCkeqmxbR6mry6RAnBo0S0BtoLhdrXLUYpNQsOmT8MyjkU7gkfwQYSdnC4azzaGT_FJg0zEjMyWO3mLJz4EBl_mGJdS-zdYgXf_fd-segRzgOwGXjInQwLSxQZE3R/w400-h201/zephyr_build_ex.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.2] Zephyr 예제 코드 build 모습(1)</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMVaKJCV5U5WJpxUiZ_V20i7m-okPQX5bPhiDYVZYx1uAmoWmDtDB7i3smpz-qZ7LIVAet2WH4wQ2fUxJyiQkGcanQ6o6cxuMiXXlmqfOe5CVe5pK1hi7G6m4fR-B_cIokXCnUNwHWrWbI/s757/zephyr_build_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="757" data-original-width="656" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMVaKJCV5U5WJpxUiZ_V20i7m-okPQX5bPhiDYVZYx1uAmoWmDtDB7i3smpz-qZ7LIVAet2WH4wQ2fUxJyiQkGcanQ6o6cxuMiXXlmqfOe5CVe5pK1hi7G6m4fR-B_cIokXCnUNwHWrWbI/w346-h400/zephyr_build_output.png" width="346" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.3] Zephyr 예제 코드 build 모습(2) - output directory</span></div></div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">zephyr.elf 파일이 생성되었으니, west flash 명령을 이용하여 target board에 writing해 보도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">chyi@mars:~/zephyrproject/zephyr$<b> west flash</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOeI_qZd5bzbyFsVpha_cW9ZEUKK9s-6Nufgokxp2vLRJdvLyJXKaiYjQ1JAkGHDU4k1mwO-Rcapvl7HPJXC-r9p2WtcgGY_75VU8B3JQJBWvyomELmFSXfL_gBroHlcwn2dW0yO5aZFh-/s1066/zephyr_west_flash.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="594" data-original-width="1066" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOeI_qZd5bzbyFsVpha_cW9ZEUKK9s-6Nufgokxp2vLRJdvLyJXKaiYjQ1JAkGHDU4k1mwO-Rcapvl7HPJXC-r9p2WtcgGY_75VU8B3JQJBWvyomELmFSXfL_gBroHlcwn2dW0yO5aZFh-/w400-h223/zephyr_west_flash.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] west를 이용한 flash writing 모습(1)</span></div></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIZGkwskGfGhhaP9IFP598GWXSAlN80nlkvgNXH6gPoRVKKEV_1vTIAhH12unOuVZS9278eyt5ZCL-n7ZvudfejnpnUZ_P2Ke-eb4s7T6awkJbGkcrmcy-2-Ma6vB4VH_4PFX1c7BI3pgU/s869/zephyr_minicom.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="692" data-original-width="869" height="319" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIZGkwskGfGhhaP9IFP598GWXSAlN80nlkvgNXH6gPoRVKKEV_1vTIAhH12unOuVZS9278eyt5ZCL-n7ZvudfejnpnUZ_P2Ke-eb4s7T6awkJbGkcrmcy-2-Ma6vB4VH_4PFX1c7BI3pgU/w400-h319/zephyr_minicom.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] west를 이용한 flash writing 모습(2) - minicom console(/dev/ttyACM0, 115200, 8N1)</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 west를 이용해 clean을 하려면 ...</span></span></div><div><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white; font-size: 14.85px;">$ west build -t clean # built 파일을 모두 삭제</span></span></div><div><span style="color: #b45f06; font-family: Nunito;"><span style="background-color: white; font-size: 14.85px;">$ west build -t pristine # build 디렉토리를 통째로 날림.</span></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;">_________________________________________________</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">앞서 build해 본 바와 같이 zephyr build 과정은 크게 2단계로 나뉜다.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><i> 1) <b>CMake에 의한 configuration 단계 </b></i></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><i> => dts/binding/Kconfig 등을 이용하여 주요 header 파일 및 Makefile(or Ninja 파일) 생성<br /></i></span><span style="font-family: Nunito;"><span class="go" style="box-sizing: border-box;"><span style="color: #404040;"> </span><span style="color: #3d85c6;"> ex) cmake -B build -GNinja -DBOARD=nucleo_f103rb samples/hello_world</span><br /></span></span><i style="font-family: Nunito;"> 2) <b>Make or Ninja를 이용한 실제 build 단계</b></i></div><div style="font-family: "Noto Sans CJK KR";"><i style="font-family: Nunito;"><b> </b> => 실제 build 절차를 진행하여 elf 파일 등 생성<br /></i><span style="font-family: Nunito;"><span class="go" style="box-sizing: border-box;"> <span style="color: #3d85c6;"> ex) ninja -C build or make -C build</span></span></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><span class="go" style="box-sizing: border-box;"><span style="color: #3d85c6;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></span></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><span class="go" style="box-sizing: border-box;"><span style="color: #3d85c6;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Zephyr build system은 CMake, Ninja/Make를 주축으로 하며, 중간 중간에 python script가 적절히 활용되고 있다.</span></span></span></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><span class="go" style="box-sizing: border-box;"><span style="color: #3d85c6;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></span></span></div></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>c) CMake에 의한 configuration 단계</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">이 단계에서는 dts 파일, binding 정보, prj.conf 및 Kconfig 파일 정보 등을 토대로 아래와 같이 autoconf.h, .config, devicetree.h, Makefile or Ninja file 등을 생성한다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWYAdjRWh4GxChKyYAwFtyya1KaZsZXMHXGBbffKnZv7M1JeLPJaavGJ2VG9edfMaMYhCK_0bmPpIepaXNamqduP1CVBf7drnLJbqvI_sx-IQwIN019IJ4M0m_l8rWQfbJEf20L4R-w7aY/s758/zephyr_dts_generation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="757" data-original-width="758" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWYAdjRWh4GxChKyYAwFtyya1KaZsZXMHXGBbffKnZv7M1JeLPJaavGJ2VG9edfMaMYhCK_0bmPpIepaXNamqduP1CVBf7drnLJbqvI_sx-IQwIN019IJ4M0m_l8rWQfbJEf20L4R-w7aY/w400-h400/zephyr_dts_generation.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] CMake에의 configuration 단계(<b><span style="color: #b45f06;">header 파일 생성</span></b>) <b>[출처 - 참고문헌 1]</b></span></div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>d) Make or Ninja를 이용한 실제 build 단계</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;">실제 build 단계는 다시 4개의 과정 즉, <b>pre-build, first-pass binary, final binary, post-processing</b> 으로 세분화 될 수 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrcya0_-tM5BwBFeFSHzQOQkp0r5xD34FDGejtvgp3ulx4hech3Tbz32Lmdv7b_pBGzjrgNSg31qdXb__FbrQBl8FNdKP2TKIZpJC-bb6JvmjpzLjF62bTS6GW_qHaGAnCTIB66g0p0VAF/s751/zephyr_build_step1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="547" data-original-width="751" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrcya0_-tM5BwBFeFSHzQOQkp0r5xD34FDGejtvgp3ulx4hech3Tbz32Lmdv7b_pBGzjrgNSg31qdXb__FbrQBl8FNdKP2TKIZpJC-bb6JvmjpzLjF62bTS6GW_qHaGAnCTIB66g0p0VAF/w400-h291/zephyr_build_step1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.7] Ninja or Make를 이용한 build 단계 1(<b><span style="color: #b45f06;">pre-build</span></b>) </span><span style="font-family: Nunito;"><b>[출처 - 참고문헌 1]</b></span></div></div><div style="text-align: left;"><span style="font-family: Nunito; text-align: center;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd6FOpbb8NewVp8BbktFAD4G15RHy83-bmoYeE2GT0OsQstceIZfdMCMvErZFGDSFjPmiXz06Zm25r4bBhNfXkGN0X3mOkzaGej5t0E4g_RulMFydb3E7MJWe99pquk5Wjb_tkikfHkqQX/s749/zephyr_build_step2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="749" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd6FOpbb8NewVp8BbktFAD4G15RHy83-bmoYeE2GT0OsQstceIZfdMCMvErZFGDSFjPmiXz06Zm25r4bBhNfXkGN0X3mOkzaGej5t0E4g_RulMFydb3E7MJWe99pquk5Wjb_tkikfHkqQX/w400-h271/zephyr_build_step2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.8] Ninja or Make를 이용한 build 단계 2(<b><span style="color: #b45f06;">first-pass binary</span></b>) </span><b style="font-family: Nunito;">[출처 - 참고문헌 1]</b></div></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEWRkueEd23Q84cuDz4BvgdZY5xtxewY0-M-MTsSF1BVeDq6iLiV5H8P48iufsgIUemjK_SEReNMsgt5Zncnid3DJOH6qUNJHZdAircSEgNm2vck-EObLgkzLl5wpClhrHYMAYb0w_0WGV/s748/zephyr_build_step3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="545" data-original-width="748" height="291" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEWRkueEd23Q84cuDz4BvgdZY5xtxewY0-M-MTsSF1BVeDq6iLiV5H8P48iufsgIUemjK_SEReNMsgt5Zncnid3DJOH6qUNJHZdAircSEgNm2vck-EObLgkzLl5wpClhrHYMAYb0w_0WGV/w400-h291/zephyr_build_step3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.9] </span><span style="font-family: Nunito;">Ninja or Make를 이용한 build 단계 3(<b><span style="color: #b45f06;">final binary</span></b>) </span><b style="font-family: Nunito;">[출처 - 참고문헌 1]</b></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtWch4IVxkVTsSWXxRnR_WIIhNkVQ9y87Cf_aV9-rgitKieEAwEeoTLVt2MLSKsdcJhPIMZofxeVKNszaYZnexsEfHq0qRWUEHQknFdP1-JJPbWmvIZ0Vijsc8P39rK12y5DYShORraG6q/s745/zephyr_build_step4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="314" data-original-width="745" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtWch4IVxkVTsSWXxRnR_WIIhNkVQ9y87Cf_aV9-rgitKieEAwEeoTLVt2MLSKsdcJhPIMZofxeVKNszaYZnexsEfHq0qRWUEHQknFdP1-JJPbWmvIZ0Vijsc8P39rK12y5DYShORraG6q/w400-h169/zephyr_build_step4.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><div class="separator" style="clear: both;"><span style="font-family: Nunito;">[그림 3.10] </span><span style="font-family: Nunito;">Ninja or Make를 이용한 build 단계 4(<b><span style="color: #b45f06;">post-processing</span></b>) </span><b style="font-family: Nunito;">[출처 - 참고문헌 1]</b></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito;">각각의 단계를 상세히 소개하는 것은 간단한 일이 아니다. 따라서 보다 자세한 사항은 아래 site 내용을 살펴 보기 바란다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/guides/build/index.html#build-overview">https://docs.zephyrproject.org/latest/guides/build/index.html#build-overview</a></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="font-family: Nunito;"><br /></span></div></div></div></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">4. Device tree 기반의 device driver model</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">이번 장에서는 device tree를 기반으로 하는 zephyr RTOS의 device driver model을 분석해 볼 것이다. <span style="color: #990000;">사실 이 부분은 조금 난해할 수 있다. 하지만 반드시 이해해야 하는 부분이기도 하다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div><b style="color: #38761d; font-size: large;">a) blinky 예제 분석하기</b></div><div><span style="font-family: Nunito;"><div>Zephyr의 device driver 동작 원리를 파악하기 전에, 관련 예제 코드( blinky)를 먼저 살펴 보도록 하자.</div><div><br /></div><div>chyi@mars:~/zephyrproject/zephyr/<span style="color: #b45f06;">samples/basic/blinky</span>$ ls -la</div><div>합계 28</div><div>drwxr-xr-x 3 chyi chyi 4096 11월 2 10:39 .</div><div>drwxr-xr-x 10 chyi chyi 4096 10월 30 11:14 ..</div><div>-rw-r--r-- 1 chyi chyi 188 10월 30 10:35 <b>CMakeLists.txt </b># CMake 파일용</div><div>-rw-r--r-- 1 chyi chyi 1196 10월 30 10:35 README.rst</div><div>-rw-r--r-- 1 chyi chyi 14 10월 30 10:35 <b>prj.conf </b># kernel config 기술</div><div>-rw-r--r-- 1 chyi chyi 224 10월 30 10:35 <b>sample.yaml </b># binding 파일</div><div>drwxr-xr-x 2 chyi chyi 4096 11월 4 11:09 <b>src</b></div><div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYiiT14rijWBdE-M2Bn7SR49B6dQSW8XZqfjm0CzzNI1EPoUFCKPSxixb2qhYvJPuoKt4KkNYiI6GFMqpj7hPnD3SBi2X9NCycEGi_aLbGvQ2a8245TrMg8lWHKWi93VkM6kcSCh6p1meY/s494/zephyr_cmake_txt.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="145" data-original-width="494" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYiiT14rijWBdE-M2Bn7SR49B6dQSW8XZqfjm0CzzNI1EPoUFCKPSxixb2qhYvJPuoKt4KkNYiI6GFMqpj7hPnD3SBi2X9NCycEGi_aLbGvQ2a8245TrMg8lWHKWi93VkM6kcSCh6p1meY/s320/zephyr_cmake_txt.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.1] CMakeLists.txt 파일</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9v4aWEHZfjx45w-woY5eDdl-US5QtWBNsWFQKxOvfseUGbN6LmJjOqqNE8V49WIxTmbnhuDbINsps-MjkKP2Keio8bZ3HHpJdYhiMfXb_jGmFtrAz4TXZ52zXQfux1rVPvaGZFqxO6VQj/s162/zephyr_prj_conf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="50" data-original-width="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9v4aWEHZfjx45w-woY5eDdl-US5QtWBNsWFQKxOvfseUGbN6LmJjOqqNE8V49WIxTmbnhuDbINsps-MjkKP2Keio8bZ3HHpJdYhiMfXb_jGmFtrAz4TXZ52zXQfux1rVPvaGZFqxO6VQj/s0/zephyr_prj_conf.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.2] prj.conf 파일</div><div><br /></div><div>chyi@mars:~/zephyrproject/zephyr/samples/basic/blinky/src$ ls -la</div><div>합계 16</div><div>drwxr-xr-x 2 chyi chyi 4096 11월 4 11:09 .</div><div>drwxr-xr-x 3 chyi chyi 4096 11월 2 10:39 ..</div><div>-rw-r--r-- 1 chyi chyi 1084 10월 30 11:31 <b>main.c</b></div></div><div><br /></div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Zephyr application(or device driver)은 모두 위와 같이 구성되어 있다. src 디렉토리 아래에 C & header 파일을 추가해 주면 된다.</span></div></span></div><div><br /></div><div>main.c 파일을 열어 보니, 예상대로 몇줄 되지 않는다. 하지만 몇 줄 안되는 아래 코드를 제대로 이해하기 위해서는 파악할 내용이 만만치 않다.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjREdfuIrGhd0FAoiRJm_-vkgEK_k3EBEBGXMx0hGUGZjN9W8Jqp4yIV7F_xhaaleiKPer-pB0jfa9IAP9rttD5MHe0UaKYiYmv7okyXKAAMkpv5K40SN8z3yJTJYwneJqzsJomH7lVenoa/s896/zephyr_blinky_main.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="896" data-original-width="603" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjREdfuIrGhd0FAoiRJm_-vkgEK_k3EBEBGXMx0hGUGZjN9W8Jqp4yIV7F_xhaaleiKPer-pB0jfa9IAP9rttD5MHe0UaKYiYmv7okyXKAAMkpv5K40SN8z3yJTJYwneJqzsJomH7lVenoa/s16000/zephyr_blinky_main.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.3] blinky 예제 코드</span></div><br /><span style="font-family: Nunito;">우선 제일 먼저 눈에 들어오는 코드 부분은 아래 한 줄이다. 다른 device driver 예제를 살펴 보아도 모두 제일 먼저 이 함수를 호출한다.</span></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><span style="font-family: Nunito;"><b>dev = device_get_binding(<span style="color: #b45f06;">LED0</span>)</b></span></div><div><br /></div><div>____________________________ 위의 코드 분석 시도 ____________________________</div><div><span style="font-family: Nunito;">위 코드에서 LED0는 아래와 같이 define되어 있다. </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">#define LED0 <b>DT_GPIO_LABEL</b>(<span style="color: #3d85c6;">LED0_NODE</span>, gpios)</span></div><div><span style="font-family: Nunito;">#define <span style="color: #3d85c6;">LED0_NODE</span> DT_ALIAS(<b>led0</b>)</span></div><div><span style="font-family: Nunito;">-> 줄여서 이렇게도 볼 수 있다.</span></div><div><span style="font-family: Nunito;">#define LED0 <b>DT_GPIO_LABEL</b>(DT_ALIAS(<b><span style="color: #b45f06;">led0</span></b>), <b><span style="color: #b45f06;">gpios</span></b>)</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌그렇다면 led0, gpios는 어디에 있는 정보일까 ?</span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;"><br /></span></span></div><div><span style="font-family: Nunito;">좀더 따라 들어가 보도록 하자. DT_GPIO_LABEL은 include/devicetree/gpio.h 파일에 아래와 같이 정의되어 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>#define <b>DT_GPIO_LABEL</b>(node_id, gpio_pha) \</div><div> <b> DT_GPIO_LABEL_BY_IDX</b>(node_id, gpio_pha, 0)</div><div>=></div></span></div><div><div><span style="font-family: Nunito;">#define DT_GPIO_LABEL_BY_IDX(node_id, gpio_pha, idx) \</span></div><div><span style="font-family: Nunito;"> DT_PROP_BY_PHANDLE_IDX(node_id, gpio_pha, idx, label)</span></div><div><span style="font-family: Nunito;">=></span></div><div><span style="font-family: Nunito;"><div>#define DT_PROP_BY_PHANDLE_IDX(node_id, phs, idx, prop) \</div><div> DT_PROP(DT_PHANDLE_BY_IDX(node_id, phs, idx), prop)</div><div>=></div><div>#define DT_PROP(node_id, prop) DT_CAT(node_id, _P_##prop) ... include/devicetree.h</div><div>=></div><div>#define DT_CAT(node_id, prop_suffix) <span style="color: #b45f06;"><b>node_id##prop_suffix</b></span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">node_id##prop_suffix 가 의미하는 것은 또 무엇일까 ?</span></div><div><span style="font-family: Nunito;">________________________________________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div>눈치 빠른 분은 예상했겠지만, 위 내용은 device tree와 연관이 있다. 따라서 이 대목에서 우리는 Nucleo f103rb의 device tree 파일 및 binding file(yaml)을 확인해 <span>볼 필요가 있다.</span></div><div><br /></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTN2nAw4z7WoVq7vRqpFK6FiJQsHn8dZuXF3GfVUZRcIRkoODIk4snh1phP-y-54KOSztYLJeHESAfftOzU5blpcN7qa3khKkCBBUDjOnzRoYE47nxVnWN-lfEYOx4ixHvLfxjPGdpp9HI/s820/zephyr_f103rb_dts.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="820" data-original-width="567" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTN2nAw4z7WoVq7vRqpFK6FiJQsHn8dZuXF3GfVUZRcIRkoODIk4snh1phP-y-54KOSztYLJeHESAfftOzU5blpcN7qa3khKkCBBUDjOnzRoYE47nxVnWN-lfEYOx4ixHvLfxjPGdpp9HI/w443-h640/zephyr_f103rb_dts.png" width="443" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.4] zephyr/boards/arm/nucleo_f103rb/nucleo_f103rb.dts 파일</span></div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLqpy0hdTVOAc6oZFR6RWPXXgop15zNKkR0O_LPpG6pqAo1XTqZ20At8mN753cgDjAv25i4gN01_D3-ytzRek-Ew0Cu6pG8YN6Hiq6CgvCCwO_1hDh8m7InYM3-n5xfk3LyFvQQaErJtrw/s566/zephyr_blinky_sample_yaml.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="195" data-original-width="566" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLqpy0hdTVOAc6oZFR6RWPXXgop15zNKkR0O_LPpG6pqAo1XTqZ20At8mN753cgDjAv25i4gN01_D3-ytzRek-Ew0Cu6pG8YN6Hiq6CgvCCwO_1hDh8m7InYM3-n5xfk3LyFvQQaErJtrw/w400-h138/zephyr_blinky_sample_yaml.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito; text-align: left;"><span style="text-align: center;">[그림 4.5] </span></span><span style="text-align: left;">zephyr/samples/basic/blinky/sample.yaml</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div>(설명이 길어지는 관계로) 답을 미리 말하자면, 앞에서 분석한 내용 중 <b><span style="color: #b45f06;">led0</span></b>와 <span style="color: #b45f06;"><b>gpios</b></span>는 각각 위의 device tree 내용 중 아래 부분에 해당한다. </div><div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: left;">______________________________________________</div><div style="text-align: left;"><span style="font-family: Nunito;"><b><span style="color: #b45f06;">led0</span> = &green_led_2;</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><br /></b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-weight: bold;">leds {</div><div><b> compatible = "</b><span style="color: #3d85c6; font-weight: bold;">gpio-leds</span><b>"; </b># samples/basic/blinky/sample.yaml 내용과 연관</div></span></div><div><span style="font-family: Nunito;"><div style="font-weight: bold; text-align: left;"> green_led_2: led_2 {</div><div style="font-weight: bold; text-align: left;"> <span style="color: #b45f06;">gpios</span> = <span style="color: #38761d;"><&gpioa 5 GPIO_ACTIVE_HIGH></span>;</div><div style="font-weight: bold; text-align: left;"> label = "User LD2";</div><div style="font-weight: bold; text-align: left;"> };</div><div style="text-align: left;"><b> };</b></div></span></div></div></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;">______________________________________________</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 Linux에서 device driver와 device tree를 연결하는 것이 compatible 속성이었던 것을 기억하는가 ? Zephyr에서는 이 연결 작업을 device driver에서 run time에 하는 것이 아니라 compile time에 device tree와 위의 binding file을 이용하여 진행한다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">위 내용 중에서 device driver에서 실제로 필요로 하는 것은 녹색으로 표시한 GPIO 관련 정보일 것이다. 따라서 (다시 처음 코드로 돌아와) 우리는 아래 코드가 led0(alias 명) -> gpios(속성 명) 를 이용해서<b> leds 노드 </b></span><span style="font-family: Nunito;">정보를 찾는 과정임을 유추해 볼 수가 있다.</span></div><div style="text-align: left;"><div style="font-family: Nunito; text-align: center;"><br /></div><div style="font-family: Nunito; text-align: center;"><span style="font-family: Nunito;"><b>dev = device_get_binding(<span style="color: #b45f06;">LED0</span>)</b></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌그런데 kernel source code 어디에도 device_get_binding( ) 함수가 보이질 않는다 ? 어디에 있을까 ?</span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">아직 필자는 앞에서 살펴본 매우 복잡한 #define 문의 내용이 무엇을 의미하는지를 제대로 설명하지 못했다. 이 내용을 파악하기 위해서는 (아래 page를 참조하여) 좀 더 깊게 들어가 볼 필요가 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/guides/dts/api-usage.html">https://docs.zephyrproject.org/latest/guides/dts/api-usage.html</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">b) Zephyr의 device tree</b></div><div style="text-align: left;"><span style="font-family: Nunito;">Zephyr는 Linux의 brother OS이다. 따라서 Linux의 많은 장점을 그대로 채용하여 사용하고 있는데, 그 중 하나가 바로 device tree이다. Device tree에 대해서는 본 blog를 통해 여러 차례 소개한 바 있다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html">https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html</a></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;">하지만 zephyr는 resource constrained 장치용 OS이다 보니, device tree를 binary 형태(dtb 파일)로 유지(flash memory에 탑재)하는 것도 부담이 된다. 따라서 Linux와는 달리 dtb 파일 형태를 유지하지 않고, <span style="color: #b45f06;">pre-compile 단계에서 device tree를 적절히 파싱하여 header 파일로 만든 후, binding 과정(yaml 파일 내용)을 거쳐 elf에 적절히 녹이는 방식을 사용한다(?)</span>.</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><Linux의 device tree 처리 방식></b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>dtb 파일 생성 -> memory에 load -> kernel 에서 runtime에 dtb 내용을 읽어 들여 필요한 device 속성 정보 추출 -> device driver에서 이를 사용</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigsRjCAEuEQA-ZlgwL2Mp1GlsB-tN2gZ95KL5fLH8Z8V26E5INMK6F2HHGKLbVyCBJNh34rJ_MJTQD1GQiGH7QXuN0Kl0HEdxU0bjb2kg9t2GME9oCq_d6CrAxRexJ3hWbCPGPzEPAAyPo/s377/linux_dtb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="377" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigsRjCAEuEQA-ZlgwL2Mp1GlsB-tN2gZ95KL5fLH8Z8V26E5INMK6F2HHGKLbVyCBJNh34rJ_MJTQD1GQiGH7QXuN0Kl0HEdxU0bjb2kg9t2GME9oCq_d6CrAxRexJ3hWbCPGPzEPAAyPo/s320/linux_dtb.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.6] Linux에서 device tree를 처리하는 방식 <b>[출처 - 참고문헌 4]</b></span></div></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><b><Zephyr의 device tree 처리 방식></b></span></div><div style="text-align: left;"><i><span style="font-family: Nunito;">pre-compile 단계에서 device tree 파일로 부터 header 파일 생성 -> build 단계에서 device tree 정보를 이용하여 elf 파일에 포함 -> device driver에서 </span><span style="font-family: Nunito;">device_get_binding( ) 함수를 호출하여 사용</span></i></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">아래 그림은 dts 파일로 부터 header 파일이 생성되는 과정을 보여준다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQQ7oymUZQy2Z2Bvs6cMT8qA5cETNuyYnzqka7HBLB5hJazV-JLploIhUm7VoUU2JNd3oIWG660h-96T6tcnuSu5MLko1nIP6-TUqqI3sdzI55eqOeJgGi9xO5m3rt2ty5zlA9kkLk3thK/s789/zephyr_device_tree_generation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="638" data-original-width="789" height="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQQ7oymUZQy2Z2Bvs6cMT8qA5cETNuyYnzqka7HBLB5hJazV-JLploIhUm7VoUU2JNd3oIWG660h-96T6tcnuSu5MLko1nIP6-TUqqI3sdzI55eqOeJgGi9xO5m3rt2ty5zlA9kkLk3thK/w400-h324/zephyr_device_tree_generation.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.7] Zephyr</span><span style="font-family: Nunito;">에서 device tree를 처리하는 방식 </span><span style="font-family: Nunito;">- device tree로 부터 header 전환 과정 </span><b style="font-family: Nunito;">[출처 - 참고문헌 1]</b></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px;">📌 중간 결과물인 </span><span style="color: #b45f06; font-family: Nunito;"><span style="font-size: 14.85px;">zephyr.dts는 debugging 용일 뿐 실제로 사용되지는 않는다. 즉 dtb로 변환되어 memory에 load되지 않는다.</span></span></div><div style="text-align: left;"><span style="color: #b45f06; font-family: Nunito;"><span style="font-size: 14.85px;"><br /></span></span></div><span style="font-family: Nunito;">이렇게 해서 생성한 header 파일 중 하나가 바로 devicetree_unfixed.h 파일(전부 #define 문으로 구성됨)이다.</span><br /><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPCl3wKNYmRk74TvVfD13sHzcFpcFc-l9sioQNwAz0wpA_CCxFZBUp2RJLIw5RAVRlpkHYPLks6xgbMHVfzY1PLOHeB7IET5_WuK6TQVa1GsZ1FwY6bqk4tVSRdo3fBvtq6qHN3NZ5g0cy/s924/zephyr_devicetree_unfixed_h.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="700" data-original-width="924" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPCl3wKNYmRk74TvVfD13sHzcFpcFc-l9sioQNwAz0wpA_CCxFZBUp2RJLIw5RAVRlpkHYPLks6xgbMHVfzY1PLOHeB7IET5_WuK6TQVa1GsZ1FwY6bqk4tVSRdo3fBvtq6qHN3NZ5g0cy/s320/zephyr_devicetree_unfixed_h.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.8] </span><span style="text-align: left;"><span style="font-family: Nunito;">build/zephyr/include/generated/devicetree_unfixed.h</span></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">이후, (너무 모호하게 설명하는 듯 하지만) build 과정에서 device tree 정보가 elf 파일에 적절히 녹아 들어가게 된다(linker.cmd 이용).</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">c) Device driver model</b></div></div><div style="text-align: left;"><div><div class="separator" style="clear: both;"><span style="font-family: Nunito;">다음으로 알아볼 내용은 zephyr의 device driver model에 관한 것이다. Zephyr는 device를 위해 아래와 같이 <b>struct device</b>와 <b>device_get_binding( ) </b>함수를 정의해 두고 있다(Linux kernel 처럼 복잡한 방식이 아니다). Application code(device driver)에서는 device_get_binding( ) 함수를 이용하여 device(struct device)를 정보를 획득한 후, 이를 이용해 실제 device driver 관련 나머지 작업을 진행한다.</span></div></div><div class="separator" style="clear: both;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both;"><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-q5LrWEnpN7U63ew6sjjsZJQCMh9zdQCU-YWLSH_M-u5Ezvb_dhoc5s_qb-wL1IAX11rx9lahVeiNCxQy3QhynPQfVuehcteYJarMypgogbPdcbaN5eWXx0-accbsNd0kp_JyR_3GCWeb/s666/zephyr_struct_device.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="372" data-original-width="666" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-q5LrWEnpN7U63ew6sjjsZJQCMh9zdQCU-YWLSH_M-u5Ezvb_dhoc5s_qb-wL1IAX11rx9lahVeiNCxQy3QhynPQfVuehcteYJarMypgogbPdcbaN5eWXx0-accbsNd0kp_JyR_3GCWeb/w400-h224/zephyr_struct_device.png" width="400" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.9] struct device - zephyr/include/device.h</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">앞서 찾을 수 없었던, device_get_binding( ) 함수의 실체는 다음과 같다.</span></div><div><div><span style="font-family: Nunito;"><div>______________________________________________________________________</div><div>extern const struct device * z_impl_device_get_binding(const char * name);</div><div>static inline const struct device * <b><span style="color: #b45f06;">device_get_binding</span></b>(const char * name)</div><div>{</div><div>#ifdef CONFIG_USERSPACE</div><div> if (z_syscall_trap()) {</div><div> return (const struct device *) arch_syscall_invoke1(*(uintptr_t *)&name, K_SYSCALL_DEVICE_GET_BINDING);</div><div> }</div><div>#endif</div><div> compiler_barrier();</div><div> return <b><span style="color: #38761d;">z_impl_device_get_binding</span></b>(name);</div><div>}</div></span></div><div><span style="font-family: Nunito;">______________________________________________________________________<br /> [코드 4.1] device_get_binding( ) 함수 - </span><span style="font-family: Nunito;">zephyr/build/zephyr/include/generated/syscalls/device.h</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b>z_impl_device_get_binding( ) </b>함수에서 device 정보를 찾는 과정을 좀 더 깊게 따라가 보면 다음과 같다.</span></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgKujdkbKwHOsd-JpZ6uUIqt-1tgzV7-ID008PyjdH-h8tVePvWsgIUv1ZbaYhClGUQleprZb59_EnXODDrsMZAhonjBngB69za5PpWZelyuN27xKDo1YjF7t-UHfxmljYobbBsuePMbQQ/s634/zephyr_z_impl_device_get_binding.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="421" data-original-width="634" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgKujdkbKwHOsd-JpZ6uUIqt-1tgzV7-ID008PyjdH-h8tVePvWsgIUv1ZbaYhClGUQleprZb59_EnXODDrsMZAhonjBngB69za5PpWZelyuN27xKDo1YjF7t-UHfxmljYobbBsuePMbQQ/w400-h265/zephyr_z_impl_device_get_binding.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.10] z_impl_device_get_binding( ) 함수 - kernel/device.c</span></div></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">위 함수는 __device_start 부터 __device_end까지의 device를 대상으로 dev->name이 일치하는 무언가(= struct device)를 찾아내는 일을 하고 있는 듯 보인다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">그렇다면, (kernel/device.c에 아래와 같이 선언되어 있는) <b>__device_start ~ __device_end</b>의 실제 내용은 어디에 있을까 ?</span></div><div><span style="font-family: Nunito;"><div><b><span style="color: #38761d;">extern const struct device __device_start[];</span></b></div><div><b><span style="color: #38761d;">extern const struct device __device_end[];</span></b></div><div><br /></div><div>이를 source code에서는 찾을 수 없어, build 결과물 중에서 뒤져 보기로 한다.</div><div><div><br /></div><div>chyi@mars:~/zephyrproject/zephyr/build/zephyr$ <b>grep -rl __device_start *</b></div><div>kernel/libkernel.a</div><div>kernel/CMakeFiles/kernel.dir/device.c.obj</div><div><b>linker.cmd</b></div><div>linker_pass_final.cmd</div><div><b>zephyr.elf</b></div><div>zephyr.lst</div><div>zephyr.map</div><div>zephyr_prebuilt.elf</div><div>zephyr_prebuilt.map</div></div><div><br /></div><div>그 결과, linker.cmd 파일에서 __device_start 부분을 확인할 수 있었다. 아래 내용은 linker script로 보이는데, 이게 어떤 것을 의미하는 것일까 ?</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaxbfoUHs1nHqOxTlL_gPVUlpRZqdebPyK9Y8Gz9rbp2KstbTnfPRlIN0WTR6K1Men5WBsJafnO3pO13xUPRCuwGt6T9pphPyvXVybZF71PNGGGpmSlfqS4VgQdQe4HcpJ56QRwxbxdsbk/s897/zephyr_linker_cmd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="310" data-original-width="897" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaxbfoUHs1nHqOxTlL_gPVUlpRZqdebPyK9Y8Gz9rbp2KstbTnfPRlIN0WTR6K1Men5WBsJafnO3pO13xUPRCuwGt6T9pphPyvXVybZF71PNGGGpmSlfqS4VgQdQe4HcpJ56QRwxbxdsbk/w400-h139/zephyr_linker_cmd.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.11] zephyr/build/zephyr/linker.cmd 내용 중에서 발췌</div><br /><div>아직 내용이 정확하지는 않지만, 앞서 언급한 대로 "<b><span style="color: #3d85c6;">build 단계에서 binding 정보와 일치하는 device tree 정보가 linker.cmd 등을 참조하여 elf에 포함되었고, application(device driver)에서는 device_get_binding( ) 함수를 통해 name이 일치하는 device 정보를 바로 추출하여 사용한다</span></b>" 정도로 정리가 될 것 같다.</div><div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 이 부분은 시간을 두고 좀 더 정확하게 분석해 볼 필요가 있다. 😂</span></div></span></div></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">d) C/C++ code에서 device tree 접근하기 </b></div><div style="text-align: left;"><span style="font-family: Nunito;">앞서 복잡하게 분석해 들어간 #define 문의 정확한 의미를 파악하기 위해서는 아래 글이 도움이 될 것이다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/guides/dts/api-usage.html">https://docs.zephyrproject.org/latest/guides/dts/api-usage.html</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">내용이 길어지는 관계로 아래 내용을 copy & paste하는 것으로 설명을 대신하기로 하겠다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif_I6COMf7Q5EyLRWxkfwBGOzddC8KIeCPDiBMMSkOBmz0oq4tPCCDBNWC7-YD5egotw22bcegOFhig0-K748ofx2fi1cOA01CgKYOH_ZHa54sBZ5GFnei1zEMz0Dq9IQD0MnNb-S3Ga-T/s866/zephyr_DT.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="490" data-original-width="866" height="362" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif_I6COMf7Q5EyLRWxkfwBGOzddC8KIeCPDiBMMSkOBmz0oq4tPCCDBNWC7-YD5egotw22bcegOFhig0-K748ofx2fi1cOA01CgKYOH_ZHa54sBZ5GFnei1zEMz0Dq9IQD0MnNb-S3Ga-T/w640-h362/zephyr_DT.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.12] device tree node ID 값을 얻는 방법 <b>[출처 - 참고문헌 1]</b></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px; text-align: left;">📌 위의 내용이 뜻하는 바는 윗 부분의 device tree 내용 중 node 부분을 아래 부분의 DT_XXX( ) macro로 찾을 수 있다는 뜻이다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: white; color: #b45f06; font-family: Nunito; font-size: 14.85px; text-align: left;"><br /></span></div><span style="font-family: Nunito;">앞서도 이미 언급한 바와 같이 zephyr는 device tree blob 형태로 device tree를 사용하지 않고, 이를 header 파일로 적절히 변환(</span><span style="font-family: Nunito;">#define 정보 형태로 기술)</span><span style="font-family: Nunito;">하고, C code에서는 #define 정보를 이용하여 device tree의 node 정보를 획득하게 된다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">Device tree node를 인식하는 방법으로는 크게 아래와 같이 6가지가 있다(매우 중요한 부분이지만 자세한 설명은 생략한다).</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>1) Path에 의한 방법</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>2) Node label을 이용한 방법</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>3) Alias 정보를 이용한 방법</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>4) Instance number를 이용한 방법</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>5) Chosen node를 이용한 방법</i></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><i>6) Parent or child node를 이용한 방법</i></span></div><div style="text-align: left;"><br /></div><div style="text-align: left;">끝으로, 아래 내용은 <span style="font-family: Nunito; text-align: center;">그림 4.8에서 한 차례 언급했던 </span><span><span style="font-family: Nunito;">build/zephyr/include/generated/devicetree_unfixed.h 파일을 보여준다.</span></span></div><div style="text-align: left;"><span><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhibKGJRBcchEGF5mWCMenadtd6nfSmNT8S7jBk0JZemR5mDJmCXbUwt9280h_abRnUCXQm32nrK8nZOPc9J-X9Midzb77pLE2KMBu-5uvCV-66YCPNYdd-2mCy_CkLA_0lm6dFiHdf5srK/s727/zephyr_devicetree_unfixed.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="727" data-original-width="639" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhibKGJRBcchEGF5mWCMenadtd6nfSmNT8S7jBk0JZemR5mDJmCXbUwt9280h_abRnUCXQm32nrK8nZOPc9J-X9Midzb77pLE2KMBu-5uvCV-66YCPNYdd-2mCy_CkLA_0lm6dFiHdf5srK/s320/zephyr_devicetree_unfixed.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.13] device tree가 header로 변경된 모습</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><b style="color: #38761d; font-family: Nunito; font-size: large;">e) blinky 예제의 나머지 부분 </b></div><div>이 부분은 크게 어려운 부분이 아니다. 먼저 <b>(A)</b>에서는 GPIO 5번 pin(GPIO_ACTIVE_HIGH)을 output mode로 설정하고,<b> (B)</b>에서는 무한 loop을 돌면서 GPIO 5번 pin의 값을 5초 간격으로 1 -> 0 -> 1 ... 로 설정 변경해 준다. 그 결과 당연히 LED가 On -> Off -> On ... 을 반복하게 된다.</div></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">_________________________________________________</span></div><div style="text-align: left;"><span style="font-family: Nunito;"> ret = <b>gpio_pin_configure</b>(dev, PIN, GPIO_OUTPUT_ACTIVE | FLAGS); ...... <b>(A)</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div> if (ret < 0) {</div><div> return;</div><div> }</div><div><br /></div><div> while (1) {</div><div> <b>gpio_pin_set</b>(dev, PIN, (int)led_is_on); ...... <b>(B)</b></div><div> led_is_on = !led_is_on;</div><div> <b>k_msleep</b>(SLEEP_TIME_MS);</div><div> }</div><div>_________________________________________________</div><div><br /></div><div>Zephyr는 Linux의 장점 중 하나인 device tree 개념을 그대로 채용하여, 많은 device를 효과적으로 기술하고 있다. 하지만 resource constrained라는 환경 탓에 Linux와는 달리 다소 복잡한 내부 구조를 가져갈 수 밖에 없게 된 듯 보인다.</div><div><br /></div><div>어찌 되었든, 복잡한 내부 구조하고는 무관하게 개발자 입장에서는 몇가지 사실만 제대로 알고 있다면, zephyr 환경에서의 device driver 개발은 그리 어렵지 않을 것으로 보인다.</div><div><br /></div></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">5. 아직 못다한 이야기</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">필자가 blog에 글을 올리는 이유는 모든 것을 다 알고 있는 상태에서 이를 남들에게 과시하기 위해서가 절대 아니다. 필자가 열심히 study한 내용을 글로 정리해 보는 것은 필자 자신에게 가장 큰 도움(정리를 하다 보면 아는 부분과 모르는 부분을 정확히 알 수 있게됨)이 되기 때문이다. 더불어 이렇게 어렵사리 정리한 글이 (도움의 손길이 필요한) 다른 이들에게 조금이나마 도움이 된다면 그 또한 나쁘지 않겠다는 생각에서 그렇게 하는 것이다. <span style="color: #666666;">갑자기 넉두리를 ㅎㅎ</span> 😀</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">아직도 zephyr 관련하여 설명이 충분히 이루어지지 못한 부분(필자가 아직 제대로 파악하지 못한 부분)이 많이 남아 있다. 하지만 여기가 끝이 아니다. 오히려 이제 부터가 시작이다. <span style="color: #ff00fe;">Zephyr가 완벽히 이해될 때까지 계속 고민하고 또 고민할 것이다.</span></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">a) Kernel Services</b></div><div style="text-align: left;"><span style="font-family: Nunito;">RTOS kernel programming은 application 단의 thread programming(예: pthread)에 익숙한 분들에게는 그다지 어려운 내용이 아니다. 아래 page 내용을 참조하여 sample code를 분석해 보기 바란다.</span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="goog_1392746474"><br /></a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/reference/kernel/index.html">https://docs.zephyrproject.org/latest/reference/kernel/index.html</a></span></div><div style="text-align: center;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCTJ4Dm8aPJqMlLcYJQZiBsr6-nTdPcN1UIVORsBNetHNp1nNoqgHz6etcWe7KVtaEAkrxVBHeNdyaWHmd7eetknp7Ht_zfBDHJmoGqdC8Qapp6yT3nYneRVC1IUmbi2uX5mRl-swR0Y5p/s242/zephyr_kernel_services.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="241" data-original-width="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCTJ4Dm8aPJqMlLcYJQZiBsr6-nTdPcN1UIVORsBNetHNp1nNoqgHz6etcWe7KVtaEAkrxVBHeNdyaWHmd7eetknp7Ht_zfBDHJmoGqdC8Qapp6yT3nYneRVC1IUmbi2uX5mRl-swR0Y5p/s0/zephyr_kernel_services.png" /></a></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b style="color: #38761d; font-family: Nunito; font-size: large;">b) 부팅 flow와 application main( ) 함수 호출 과정</b></div><div style="text-align: left;"><span style="font-family: Nunito;">Zephyr의 version이 올라가면서 많은 부분이 수정되었다. Kernel code도 예외는 아니었는데, zephyr의 부팅 코드 흐름을 다시 정리해 보면 다음과 같다. 끝 부분에 main( ) 함수 호출 부분이 보이는가 ? 이 곳에서 application에 있는 main( ) 함수가 호출되는 것이다. 참고로 application 입장에서는 zephyr kernel(zephyr/kernel 디렉토리 코드)은 라이브러리(libkernel.a)에 불과하다.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0jLRNccOM18ElbEW-22MIJWT9u-lGV3eOUYNQO7x2RR93NoNhi-albU2Mr4lkP4aHpRRXwSguPrfazBtnM10O0-U4liMMS4GdNIrSLAuKdrS7aTDM-JVn0v7gEKJGRKaJc3tNMm_4D4yO/s1058/zephyr_boot_flow1.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="799" data-original-width="1058" height="485" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0jLRNccOM18ElbEW-22MIJWT9u-lGV3eOUYNQO7x2RR93NoNhi-albU2Mr4lkP4aHpRRXwSguPrfazBtnM10O0-U4liMMS4GdNIrSLAuKdrS7aTDM-JVn0v7gEKJGRKaJc3tNMm_4D4yO/w640-h485/zephyr_boot_flow1.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-O9nsrJsARr0rABhqn_vxpJa1gEvjX4KgfLtNiXEQmq3OLNqg_2GdhPZHqRlbhyphenhyphenwki5RtR_zwNJMWrtQgXa1aQkfA_y9-9cav0f1r3Avjt7xu-Cbek2jw_wkFkx3lbrYd6JAvEG1CQ3LN/s1062/zephyr_boot_flow2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="337" data-original-width="1062" height="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-O9nsrJsARr0rABhqn_vxpJa1gEvjX4KgfLtNiXEQmq3OLNqg_2GdhPZHqRlbhyphenhyphenwki5RtR_zwNJMWrtQgXa1aQkfA_y9-9cav0f1r3Avjt7xu-Cbek2jw_wkFkx3lbrYd6JAvEG1CQ3LN/w640-h204/zephyr_boot_flow2.png" width="640" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 5.1] zephyr booting flow - arm32 기준</span></div><span style="font-family: Nunito;"><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><span style="background-color: white; color: #b45f06; font-size: 14.85px;">📌 예제 코드를 보다 보면, main() 함수가 없는 경우가 있다(그 대신에 thread를 생성하는 코드만 있음). 이 경에는 main thread(kernel code)는 실행을 종료하게 되며, application에서 생성한 thread만이 동작하게 된다.</span><br /></span><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><b style="color: #38761d; font-family: Nunito; font-size: large;">c) 새로운 보드에 application 추가하기</b><span style="font-family: Nunito;"><br /><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/application/index.html#application">https://docs.zephyrproject.org/latest/application/index.html#application</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;">...</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>d) CMake & Ninja</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/application/index.html#important-build-system-variables">https://docs.zephyrproject.org/latest/application/index.html#important-build-system-variables</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;">...</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>e) Device tree bindings</b></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/guides/dts/bindings.html">https://docs.zephyrproject.org/latest/guides/dts/bindings.html</a></span></div><div style="text-align: left;"><span style="font-family: Nunito;">...</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>f) Flash writing - OpenOCD</b></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://docs.zephyrproject.org/latest/guides/west/build-flash-debug.html#west-build-flash-debug">https://docs.zephyrproject.org/latest/guides/west/build-flash-debug.html#west-build-flash-debug</a></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">...</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div></span></div><div style="text-align: left;"><span style="color: #ff00fe; font-family: Nunito; font-size: large;"><b>To be continued ...</b></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><div><br /></div></div><div style="text-align: left;"><b><span style="color: #0b5394; font-family: Nunito; font-size: x-large;">6. References</span></b></div><div style="text-align: left;"><span style="font-family: Nunito;">[1] https://docs.zephyrproject.org/</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[2] Zephyr Project: Unlocking Innovation with an Open Source RTOS, Kate Stewart, Linux Foundation</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[3] https://www.st.com/en/evaluation-tools/nucleo-f103rb.html</span></div><div style="text-align: left;"><span style="font-family: Nunito;">[4] https://events.static.linuxfound.org/sites/events/files/slides/petazzoni-device-tree-dummies.pdf</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: right;"><b><span style="color: #38761d; font-family: Nunito;">Slowboot</span></b></div></div><p style="text-align: left;"><span style="font-family: Nunito;"><br /></span></p>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com4tag:blogger.com,1999:blog-6346200245600677355.post-7213844158011826342020-10-25T17:59:00.006+09:002024-01-04T19:32:39.074+09:00DPDK와 FD.io VPP로 고성능 Security Gateway 만들기<span style="font-family: Nunito;">이번 posting에서는 open source project인 <a href="https://www.dpdk.org/">DPDK</a>와 <a href="https://fd.io/">FD.io VPP(Vector Packet Processing)</a>를 이용하여 고성능 네트워크 장비를 만드는 방법을 소개해 보고자 한다. 이제 더 이상 ASIC이나 FPGA 방식은 잊어라~ S/W만으로도 충분하다. <span style="font-size: medium;">😎</span></span><div><span style="font-family: Acme;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzJf0L9l1CmYM4NVJHqDV9-Kp1_gdzPpppqfzfVp3QInIKypxjAm7Ro4jjgUKQuVZoVhBWVIZ5L3cfPoBzoz_rhvYiltG6O2s2stX2V_aHAQW94noJVbDXfrLIWLQP6yOrolRvZdjBWpQ2/s300/fdio_logo.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Acme;"><img border="0" data-original-height="168" data-original-width="300" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzJf0L9l1CmYM4NVJHqDV9-Kp1_gdzPpppqfzfVp3QInIKypxjAm7Ro4jjgUKQuVZoVhBWVIZ5L3cfPoBzoz_rhvYiltG6O2s2stX2V_aHAQW94noJVbDXfrLIWLQP6yOrolRvZdjBWpQ2/w288-h161/fdio_logo.png" width="288" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOVwbrOm7-qijRh4qpKePp4XhAl1tC0b3Zesvq8Nyv-ugnebXl-0YOJ9Z0xgkkKCwds2GwL3wv-SgHxmu1N13yAB6SYXH1_KZzEXfTks5TDIPgQwTHQFj6PAF8ABlozMSIoYcSmotjzels/s359/dpdk_logo.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Acme;"><img border="0" data-original-height="140" data-original-width="359" height="114" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOVwbrOm7-qijRh4qpKePp4XhAl1tC0b3Zesvq8Nyv-ugnebXl-0YOJ9Z0xgkkKCwds2GwL3wv-SgHxmu1N13yAB6SYXH1_KZzEXfTks5TDIPgQwTHQFj6PAF8ABlozMSIoYcSmotjzels/w290-h114/dpdk_logo.png" width="290" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Acme;"><br /></span></div><div><br /><span style="font-family: Nunito;"><b><span style="font-size: large;">목차</span></b><br />1. DPDK와 FD.io VPP 소개<br />2. MACCHIATObin 보드(ARM64)에서 VPP 돌려 보기<br /><b><span style="color: #b45f06;">3. Intel PC(x86_64)에서 VPP 돌려 보기</span></b><br />4. <span style="color: #ff00fe;">VPP Wireguard plugin 시험하기</span></span></div><div><span style="font-family: Nunito;">5. VPP 관련 그 밖의 관심있는 주제</span></div><div><span style="font-family: Nunito;">6. References</span><div><span style="font-family: Acme;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">1. DPDK와 FD.io VPP 소개</span></b></div><div><span style="font-family: Nunito;">Intel or AMD CPU 기반의 산업용 network appliance(값싼 장비)를 사용하면서도 ASIC이나 FPGA 등으로 무장한 h/w network 장비(고가의 장비)에 필적하는 성능을 낼 수 있다면 얼마나 좋을까 ? 사실 이 질문에 답을 찾기 위한 노력은 그동안 꾸준히 진행(지난 10여년간 ...)되어 왔는데, 이에 대한 확실한 답을 제시하고 있는 두가지 open source project가 있어 여기에서 소개하고자 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="color: #741b47; font-family: Nunito; font-size: medium;"><b>Intel DPDK and FD.io VPP</b></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCXse66CRXF_m1cSx8Z-lqMZaIXjjhZzBbocj3VnFY_YR3DkyTDEO9z-H-Gef0dOeSWvnPWDpK0WsgeIXuUY753xbKIcAVsdN3OufyVOhMA3farLKaEDJFvdxJcyfLU0kd_EjO0M7q2-g_/s352/supermicro_5019d_ftn4.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="160" data-original-width="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCXse66CRXF_m1cSx8Z-lqMZaIXjjhZzBbocj3VnFY_YR3DkyTDEO9z-H-Gef0dOeSWvnPWDpK0WsgeIXuUY753xbKIcAVsdN3OufyVOhMA3farLKaEDJFvdxJcyfLU0kd_EjO0M7q2-g_/s320/supermicro_5019d_ftn4.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.1] SUPERMICRO 5019-FTN4 [출처 - 참고문헌 6]</span></span></div></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="color: #b45f06; font-family: Nunito;">📌 참고로 위의 Appliance 장비는 AMD EPYC 3251 CPU(8-Core)를 사용하고, 4개의 GbE(Intel i350-AM4) 포트가 장착되어 있다. 이 정도면 Ubuntu server(18.04)를 설치하고, 그 위에서 DPDK & VPP를 돌리기에 무리가 없을 듯 보인다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">우선 <b>DPDK(Data Plane Development Kit)</b>는 아래 그림과 같이 Linux kernel의 고질적인 네트워크 성능 문제(<span style="color: #a64d79;">대용량 network traffic 처리시 interrupt & system call 등에 의한 속도 저하</span>)를 해결하기 위해 Intel이 주도하여 개발하고 있는 project로 NIC driver(주로 Intel, Marvell, Mellanox 등 중심) 개선과 아울러, kernel이 아닌 user space에서 packet을 처리(polling 방식)하도록 함으로써 network 성능을 획기적으로 향상시키고 있다.</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp6XmY8qcx5S5ghjkEvO8kyJaXMaeY1OnWlJqD6MV0bTSXbakHTcozUsFqLa3w7gQKiHhqGBXTopkv8-9GL4D7OjgigDHM9C_ecTNNUbu2eT6Yc5uC4JIiRqNuvWOr7Tx3Lc-dIBqqNeVM/s1130/dpdk_arch2.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="448" data-original-width="1130" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp6XmY8qcx5S5ghjkEvO8kyJaXMaeY1OnWlJqD6MV0bTSXbakHTcozUsFqLa3w7gQKiHhqGBXTopkv8-9GL4D7OjgigDHM9C_ecTNNUbu2eT6Yc5uC4JIiRqNuvWOr7Tx3Lc-dIBqqNeVM/w413-h164/dpdk_arch2.png" width="413" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><span style="text-align: left;">[그림 1.2] DPDK 아키텍쳐 1 [출처 - </span><span style="text-align: left;">참고문헌 3</span><span style="text-align: left;">]</span></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;">📌 User space에서 packet을 처리하기 위해 linux에서 제공하는 UIO(User level i/o) driver가 사용된다.</span></span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;"><br /></span></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqHp_qavpD-j8K6W-bYY0T9PWza3lCaENtVLhjFitWwGiHavyK3ymtwHM9YvVr-A9trk_x-L1xByJYyo-kQFzzo7NeHVjIeQ8dSj4_ANqIsnLczD5D9hWlukSFEqPuAX5ONVys10I81LRr/s389/intel_dpdk_arch.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="389" data-original-width="312" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqHp_qavpD-j8K6W-bYY0T9PWza3lCaENtVLhjFitWwGiHavyK3ymtwHM9YvVr-A9trk_x-L1xByJYyo-kQFzzo7NeHVjIeQ8dSj4_ANqIsnLczD5D9hWlukSFEqPuAX5ONVys10I81LRr/s320/intel_dpdk_arch.png" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.3] DPDK 아키텍쳐 2 [출처 - 참고문헌 3]</span></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;">📌 DPDK는 국내에서도 KAIST, ETRI 등을 중심으로 연구가 활발이 진행되고 있으며, 일반 IT 기업에서도 네트워크 장비 개발에 많이 활용하고 있는 듯 보인다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">DPDK를 사용하면 분명 특정 network adapter(예: Intel 82576 Gigabit Ethernet Controller, Intel® 82599 10-Gigabit Ethernet Controller)를 사용한다는 조건하에서 상당한 성능 개선 효과를 얻을 수 있는게 사실이다. 하지만, user space에서 패킷을 처리한다는 것은 kernel에서 제공하는 다양하고 안정성이 검증된 network 기능(예: TCP/IP stack, L2 bridge, L3 routing, Netfilter, IPsec, Wireguard ...)을 전혀 사용할 수가 없다는 얘기가 된다. 물론 DPDK에는 user space에서 사용할 수 있는 몇가지 간단한 예제도 함께 제공되고 있기는 하지만, 이를 상용 제품에 활용하기에는 무리가 있다. 따라서 linux kernel에서 제공하는 수준의 안정적이면서도 다양한 network 기능을 구현해야 하는 숙제가 남게 된다. 과연 이를 어찌하면 좋을까 ? </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">눈치채셨겠지만, 이를 한방에 해결해 줄 수 있는 후보가 바로 <b><span style="color: #ff00fe;">FD.io VPP</span></b>이다. FD.io VPP는 (network 장비 업계의 최강자) Cisco가 2002년 부터 오랫동안 개발해 오던 것을 open source화한 것으로 아래와 같은 두가지 특징을 갖는다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #0b5394; font-family: Nunito;"><i>1. Vector Packet Processing 기법을 이용하여 획기적인 성능 개선</i></span></div><div><span style="color: #0b5394; font-family: Nunito;"><i>2. 상용 제품으로 바로 사용 가능한 다양한 기능 제공</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDFyrUuciObeR1TMJM6dlkl1OQyuOgttgEq954y39S1aIXnTpPNveYVlHQWAwGVwglehatC0gyMaDiyzI6-k-fpO_2veB2a-ZekI6CHnx-vWHsheKRq9qsipeh0TdDuB8VIgHjLm4xdjr/s833/vpp_features.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="581" data-original-width="833" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoDFyrUuciObeR1TMJM6dlkl1OQyuOgttgEq954y39S1aIXnTpPNveYVlHQWAwGVwglehatC0gyMaDiyzI6-k-fpO_2veB2a-ZekI6CHnx-vWHsheKRq9qsipeh0TdDuB8VIgHjLm4xdjr/w367-h256/vpp_features.png" width="367" /></span></a></div><span style="font-family: Nunito;"><br />FD.io VPP(Cisco)에서 말하는 Vector Packet Processing은 </span><span style="font-family: Nunito;">packet을 </span><span style="font-family: Nunito;">한번에 하나씩 처리하는 기존의 Scalar Packet Processing과 대비되는 개념으로, 아래 그림 1.4 ~ 1.6과 같이 여러개의 packet을 모아 한번(동시)에 처리(이를 위해 </span><b style="font-family: Nunito;">packet processing graph</b><span style="font-family: Nunito;">와 </span><b style="font-family: Nunito;">packet vector</b><span style="font-family: Nunito;">라는 개념이 구현되어 있음)함으로써 packet 처리 속도를 크게 향상시켜준다는 것을 기본 concept으로 하고 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2uwfKIIsHlWa2-A562Kkt38vL6XmnrwO3-AsIR_v-sFtUO1bdEAGm_NNWQrqb-hP1UZ7inn8ws4BBmvJjD23eG5627co9N4JfrnP8hUEAVQukNFeUHxuMxxGSXQQPzdMLEyGik7GoMefg/s727/tech-03.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="680" data-original-width="727" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2uwfKIIsHlWa2-A562Kkt38vL6XmnrwO3-AsIR_v-sFtUO1bdEAGm_NNWQrqb-hP1UZ7inn8ws4BBmvJjD23eG5627co9N4JfrnP8hUEAVQukNFeUHxuMxxGSXQQPzdMLEyGik7GoMefg/s320/tech-03.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.4] Vector Packet Processing 개념 1 [출처 - https://fd.io/vppproject/vpptech/]</span></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">📌 때로는 장황한 설명보다 하나의 그림이 더 효과적일 때가 있다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbj1rFUz4lNGsnzoQTZDIfdCXiScwtpw2Xu_yA7Ju71t4iSGzWaQcgj4sDf3AiVjWTq58UXzh8ltwEdwQkij-EFEcd8dWV3yLNU0Z8KRtzVZJTdR0XDOXYGAXTPGfWMsMCXuyGPF0BjGOW/s840/vpp_vector_processing.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="287" data-original-width="840" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbj1rFUz4lNGsnzoQTZDIfdCXiScwtpw2Xu_yA7Ju71t4iSGzWaQcgj4sDf3AiVjWTq58UXzh8ltwEdwQkij-EFEcd8dWV3yLNU0Z8KRtzVZJTdR0XDOXYGAXTPGfWMsMCXuyGPF0BjGOW/w476-h162/vpp_vector_processing.png" width="476" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.5] Vector Packet Processing 개념 2 [출처 - 참고문헌 2]</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk55xmSdpuc1V8RmBGej313bBynnYmyZMPg4_h0Kr2jNTH68kxLLQ2BTtQwHbscKAZJHT8xtu1lF8JHLpw86F5tJqXMaczHPzu4uP7OVmHlZdnkYuJJlLt2kxp2Aw_QZCIi_HOc3A0dPGh/s1291/fd-io-vpp-forwarding_graph.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="801" data-original-width="1291" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk55xmSdpuc1V8RmBGej313bBynnYmyZMPg4_h0Kr2jNTH68kxLLQ2BTtQwHbscKAZJHT8xtu1lF8JHLpw86F5tJqXMaczHPzu4uP7OVmHlZdnkYuJJlLt2kxp2Aw_QZCIi_HOc3A0dPGh/w372-h231/fd-io-vpp-forwarding_graph.png" width="372" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.6] Vector Packet Processing 개념 3 [출처 - 참고문헌 5]</span></div></span></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06; text-align: left;"><span style="font-family: Nunito;">📌 DPDK와 VPP 조합은 10G, 40G 정도의 ethernet 환경 쯤은 되어야 효과를 극대화할 수 있다.</span></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;">이렇듯 DPDK와 VPP를 적절히 활용한다면, 값싸고 우수한 성능의 network 장비(L2 bridge, L3 router, IPsec Gateway, MPLS 장비, Cloud Load Balancer ...)를 쉽게 개발할 수가 있게 된다. 어떤가 한번 도전해 보고 싶은 마음이 들지 않는가 ?</span></div><div class="separator" style="clear: both; text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjOCpSUrQh2nToRE6yzf8uHt1XMsDW5GL_ZwvMfbBe0kuQOjs9ktZiX4FyR5HG2sujpkTli2Ddvqy9mOoBz_NzWEODq7vg6bhRLdLRuU-Akp9BTpXeonuAUmCmOMtBUQARRBMxKtirkBah/s1128/dpdk_vpp.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="484" data-original-width="1128" height="201" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjOCpSUrQh2nToRE6yzf8uHt1XMsDW5GL_ZwvMfbBe0kuQOjs9ktZiX4FyR5HG2sujpkTli2Ddvqy9mOoBz_NzWEODq7vg6bhRLdLRuU-Akp9BTpXeonuAUmCmOMtBUQARRBMxKtirkBah/w471-h201/dpdk_vpp.png" width="471" /></span></a></div></div><div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="font-family: Nunito;">[그림 1.7] DPDK and VPP [출처 - 참고문헌 4 및 12]</span></span></div></div><div><span style="text-align: left;"><span style="font-family: Nunito;"><br /></span></span></div><div><span style="color: #b45f06; font-family: Nunito;">📌 DPDK + VPP와 유사한 project로는 DPDK + ODP(Open Data Path), DPDK + OVS(Open vSwitch) 및 XDP 등이 있다.</span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;"><br /></span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: #ffe599; font-family: Nunito;"><b><여기서 잠깐 ! - eBPF & XDP project에 관하여></b></span></div><div><span style="background-color: white; font-family: Nunito;"><span>Linux(kernel) 진영에서는 </span><span>(꼭 그런 것은 아니지만) </span><span>DPDK에 대한 대항마로 (아직 초기 단계이기는 하지만) kernel에서 동작하는 XDP(eXpress Data Path)를 밀고 있다. 향후 이 둘(XDP vs DPDK) 간의 경쟁 관계도 지켜볼만한 내용이 될 것 같다. </span></span><span style="background-color: white; font-family: Nunito;">eBPF & XDP에 관해서는 필자의 아래 문서를 참고하기 바란다.</span></div><div><span style="background-color: white; font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><a href="https://github.com/ChunghanYi/spnhacks/blob/master/misc/Linux_XDP_Overview1.pdf">https://github.com/ChunghanYi/spnhacks/blob/master/misc/Linux_XDP_Overview1.pdf</a></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Acme;"><br /><b><span style="color: #3d85c6; font-size: x-large;">2. MACCHIATObin 보드(ARM64)에서 VPP 돌려 보기</span></b></span></div><div><span style="font-family: Nunito;">이번 장에서는 <a href="https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_20.html">지난 번 blog posting</a>에서 소개했던 MACCHIATObin 보드에 FD.io VPP를 올리고, 몇가지 네트워크 동작 시험을 진행해 보고자 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">MACCHIATObin 보드는 지난 번에도 소개한 바와 같이 network interface(dual 10G copper, dual 10G SFP, 2.5G SFP, 1G copper)가 예술(?)이다. 또한 </span><span style="font-family: Nunito;">MACCHIATObin 보드(정확하게 말하자면 Marvell)는 DPDK에 해당하는 <b>MUSDK</b>라는 녀석(SDK)이 존재한다. 따라서 VPP가 제대로된 성능 효과를 누리기 위해서는 이를 사용하도록 porting해 주어야 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtoinWuSYDXvS5kiLQILiGbFu8tVljlyP5AdmWJ-i52HVoJnCKFN9zG0EF4k0n87iRGfXeV0gYaQB9bcOIOholZUx5e70p58kiD9GYyPkKGtGgiEFypjBYWxtFsKbo-0LRxmuEwjqPTSz/s504/mcbin_vpp2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="504" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJtoinWuSYDXvS5kiLQILiGbFu8tVljlyP5AdmWJ-i52HVoJnCKFN9zG0EF4k0n87iRGfXeV0gYaQB9bcOIOholZUx5e70p58kiD9GYyPkKGtGgiEFypjBYWxtFsKbo-0LRxmuEwjqPTSz/s320/mcbin_vpp2.PNG" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.1] MACCHATObin 위에 VPP 올리기</span></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYRkLRE2X8xYbd-V1LgsauKV3uXDuYlvmx-RrNOvfML1ODBH8gaBUoAA3bgb6Jz9kGvikCtFO6q6CAQWiwMC2ZKdI52t_Bz4MAUOmRYSVawO2LW5YERgulNl_YG0DQ-ruxvrfkYffSLnMr/s666/musdk_sys.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Nunito;"><img border="0" data-original-height="440" data-original-width="666" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYRkLRE2X8xYbd-V1LgsauKV3uXDuYlvmx-RrNOvfML1ODBH8gaBUoAA3bgb6Jz9kGvikCtFO6q6CAQWiwMC2ZKdI52t_Bz4MAUOmRYSVawO2LW5YERgulNl_YG0DQ-ruxvrfkYffSLnMr/s320/musdk_sys.png" width="320" /></span></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.2] Marvell MUSDK [출처 - http://macchiatobin.net/]</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">지금부터 소개하는 내용은 아래 site 내용을 기반으로 정리한 것이다. </span></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><a href="https://github.com/MarvellEmbeddedProcessors/vpp-marvell/blob/vpp-devel/README.mrvl"><span style="font-family: Nunito;">https://github.com/MarvellEmbeddedProcessors/vpp-marvell/blob/vpp-devel/README.mrvl</span></a></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">Docker 환경에서 build를 하는 방법도 있으나, (CPU 속도가 충분히 빠르니) 이번에는 target board에서 직접 build를 해 보도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: #fff2cc;"><b><span style="font-family: Nunito;"><MUSDK (part 1) download 하기></span></b></span></div><div><span style="font-family: Nunito;"><i> => MUSDK를 download 한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd /root</span></div><div><span style="font-family: Nunito;"># <b>git clone https://github.com/MarvellEmbeddedProcessors/musdk-marvell.git -b musdk-armada-17.10 musdk-marvell</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><b style="background-color: #fff2cc;"><span style="font-family: Nunito;"><Kernel build 하기></span></b></div><div><span style="font-family: Nunito;"><i> => kernel을 download 후 build하도록 한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd /root</span></div><div><span style="font-family: Nunito;"># <b>git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell.git -b linux-4.4.52-armada-17.10 linux-marvell</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>git am /home/chyi/workspace/VPP/musdk-marvell/patches/linux/*.patch</b></span></div><div><span style="font-family: Nunito;"># <b>make mvebu_v8_lsp_defconfig</b></span></div><div><span style="font-family: Nunito;"># <b>make -j4 Image dtbs modules</b></span></div><div><span style="font-family: Nunito;"># <b>make modules_install</b></span></div><div><span style="font-family: Nunito;"><span># <b>cp </b></span><span style="background-color: white; color: #24292e; white-space: pre;"><b>arch/arm64/boot/Image arch/arm64/boot/dts/marvell/armada-8040-mcbin.dtb /boot/</b></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #24292e; white-space: pre;"><br /></span></span></div><div><span style="font-family: Nunito;"># cd /boot</span></div><div><div><span style="font-family: Nunito;"># ls -la</span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>total 43508</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>drwxr-xr-x 2 root root 4096 Oct 17 07:42 .</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>drwxr-xr-x 21 root root 4096 Oct 17 06:54 ..</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rwxr-xr-x 1 root root 12783616 Feb 12 2018 <b><span style="color: #b45f06;">Image</span></b></i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 2654470 Oct 17 07:42 System.map-4.4.52-armada-17.10.4-g8ac9c68</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 36904 Feb 12 2018 <b><span style="color: #b45f06;">armada-8040-mcbin.dtb</span></b></i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 88315 Oct 17 07:42 config-4.4.52-armada-17.10.4-g8ac9c68</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 3243678 Oct 17 07:42 initrd.img-4.4.52-armada-17.10.4-g8ac9c68</i></span></div><div><span style="font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 12899840 Oct 17 07:42 vmlinuz-4.4.52-armada-17.10.4-g8ac9c68</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">kernel image와 dtb가 교체되었으니, 이 상태에서 target board를 재부팅해 준다.</span></div><div><br /></div><div><span style="background-color: #fff2cc;"><b><span style="font-family: Nunito;"><MUSDK (part 2) build 하기></span></b></span></div><div><span style="font-family: Nunito;"><i> => 이제, 앞서 받아 두었던 MUSDK를 build하도록 한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd musdk-marvell</span></div><div><span style="font-family: Nunito;"># <b>export KDIR=/root/linux-marvell</b></span></div><div><span style="font-family: Nunito;"># <b>./bootstrap</b></span></div><div><span style="font-family: Nunito;"># <b>./configure --enable-shared --enable-bpool-dma=64 --enable-bpool-cookie=32 --enable-sam --prefix=/usr</b></span></div><div><span style="font-family: Nunito;"># <b>make -j4</b></span></div><div><span style="font-family: Nunito;"># <b>make install</b></span></div><div><span style="font-family: Nunito;"># <b>cd modules</b></span></div><div><span style="font-family: Nunito;"># <span style="background-color: white; color: #24292e; white-space: pre;"><b>for i in dmax2 neta pp2 sam uio; do cd $i; make; make -C $KDIR M=`pwd` modules_install; cd -; done</b></span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># ls -l /lib/modules/4.4.52-armada-17.10.4-g2a0096d/extra</span></div><div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>total 1172</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>drwxr-xr-x 2 root root 4096 Oct 16 03:26 .</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>drwxr-xr-x 4 root root 4096 Oct 16 03:24 ..</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 269232 Oct 16 03:26 musdk_uio.ko</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 227240 Oct 16 03:24 mv_dmax2_uio.ko</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 228592 Oct 16 03:25 mv_neta_uio.ko</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 226792 Oct 16 03:25 mv_pp_uio.ko</i></span></div><div><span style="color: #b45f06; font-family: Nunito; font-size: x-small;"><i>-rw-r--r-- 1 root root 232432 Oct 16 03:25 mv_sam_uio.ko</i></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><b style="background-color: #fff2cc;"><span style="font-family: Nunito;"><pp2-sysfs driver build 하기></span></b></div><div><span style="font-family: Nunito;"><i> => mvpp2-sysfs driver를 build한다.</i><br /><br /></span></div><div><span style="font-family: Nunito;"># cd /root</span></div><div><span style="font-family: Nunito;"># <b>git clone https://github.com/MarvellEmbeddedProcessors/mvpp2x-marvell.git -b mvpp2x-armada-17.10 pp2_sysfs</b></span></div><div><span style="font-family: Nunito;"># <b>cd pp2_sysfs/</b></span><span style="font-family: Nunito;"><b>sysfs/</b></span></div><div><span style="font-family: Nunito;"># <b>cp Makefile_sysfs Makefile</b></span></div><div><span style="font-family: Nunito;"># <b>export KDIR=/root/linux-marvell</b></span></div><div><span style="font-family: Nunito;"># <b>export KERNEL_SOURCES=1</b></span></div><div><span style="font-family: Nunito;"># <b>make</b></span></div><div><span style="font-family: Nunito;"># <b>make -C $KDIR M=`pwd` modules_install</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># ls -l /lib/modules/4.4.52-armada-17.10.4-g2a0096d/extra</span></div><div><div><i><span style="font-family: Nunito; font-size: x-small;">total 5752</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">drwxr-xr-x 2 root root 4096 Oct 16 03:31 .</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">drwxr-xr-x 4 root root 4096 Oct 16 03:24 ..</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 269232 Oct 16 03:26 musdk_uio.ko</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 227240 Oct 16 03:24 mv_dmax2_uio.ko</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 228592 Oct 16 03:25 mv_neta_uio.ko</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 226792 Oct 16 03:25 mv_pp_uio.ko</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 232432 Oct 16 03:25 mv_sam_uio.ko</span></i></div><div><i><span style="font-family: Nunito; font-size: x-small;">-rw-r--r-- 1 root root 4689232 Oct 16 03:31 <span style="color: #990000;">mvpp2x_sysfs.ko</span></span></i></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><b style="background-color: #fff2cc;"><span style="font-family: Nunito;"><DPDK (Extract Marvell patches only) download후 patch 파일 생성하기></span></b></div><div><span style="font-family: Nunito;"><i> => Marvell에서 작업한 dpdk source를 download 한 후, marvell에서 작업한 부분(patch)만을 추려내도록 한다. 이 내용은 VPP build시 사용된다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd /root</span></div><div><span style="font-family: Nunito;"># <b>git clone https://github.com/MarvellEmbeddedProcessors/dpdk-marvell.git -b dpdk-17.05-armada-17.10 dpdk-marvell</b></span></div><div><span style="font-family: Nunito;"># mkdir /root/dpdk-patches/</span></div><div><span style="font-family: Nunito;"># <b>cd dpdk-marvell/</b></span></div></div><div><span style="font-family: Nunito;"># <b>git format-patch 2225554..HEAD -o /root/dpdk-patches</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><b style="background-color: #fff2cc;"><span style="font-family: Nunito;"><VPP build 하기></span></b></div><div><span style="font-family: Nunito;"><i> => Marvell에서 작업한 vpp code를 내려 받아 build한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd /root</span></div><div><span style="font-family: Nunito;"># <b>git clone https://github.com/MarvellEmbeddedProcessors/vpp-marvell.git -b vpp-devel vpp-marvell</b></span></div><div><span style="font-family: Nunito;"># cd vpp-marvell/</span></div><div><span style="font-family: Nunito;"># <b>export DPDK_VERSION=17.05</b></span></div><div><span style="font-family: Nunito;"># <b>export AESNI=n</b></span></div><div><span style="font-family: Nunito;"># <b>export LIBMUSDK_PATH=/usr</b></span></div><div><span style="font-family: Nunito;"># <b>make install-dep</b></span></div><div><span style="font-family: Nunito;"><i> => vpp build 및 install에 필요한 다양한 package를 설치한다. 어라, 근데 설치 중 아래와 같은 에러가 발생한다.</i></span></div><div><span style="color: #93c47d; font-family: Nunito; font-size: x-small;"><i><div>sudo: unable to resolve host localhost.localdomain</div><div>Hit:1 http://ports.ubuntu.com/ubuntu-ports xenial InRelease</div><div>Hit:2 http://ports.ubuntu.com/ubuntu-ports xenial-security InRelease</div><div>Hit:3 http://ports.ubuntu.com/ubuntu-ports xenial-updates InRelease</div><div>Reading package lists... Done </div><div>sudo: unable to resolve host localhost.localdomain</div><div>Reading package lists... Done</div><div>Building dependency tree </div><div>Reading state information... Done</div><div>Package python-virtualenv is not available, but is referred to by another package.</div><div>This may mean that the package is missing, has been obsoleted, or</div><div>is only available from another source</div><div><br /></div><div>Package cscope is not available, but is referred to by another package.</div><div>This may mean that the package is missing, has been obsoleted, or</div><div>is only available from another source</div><div><br /></div><div>E: Unable to locate package dh-systemd</div><div>E: Unable to locate package libconfuse-dev</div><div>E: Unable to locate package git-review</div><div>E: Package 'cscope' has no installation candidate</div><div>E: Unable to locate package lcov</div><div>E: Unable to locate package chrpath</div><div>E: Unable to locate package nasm</div><div>E: Package 'python-virtualenv' has no installation candidate</div><div>E: Unable to locate package python-pip</div><div>E: Unable to locate package check</div><div>Makefile:266: recipe for target 'install-dep' failed</div><div>make: *** [install-dep] Error 100</div><div>root@localhost:~/vpp-marvell# sudo</div><div>sudo: unable to resolve host localhost.localdomain</div></i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">#<span style="color: #990000;"> apt-get install software-properties-common</span></span></div><div><span style="font-family: Nunito;"># <span style="color: #990000;">add-apt-repository universe</span></span></div><div><span style="font-family: Nunito;"><i> => 이걸 실행 후, 다시 시도해 본다.</i></span></div><div><span style="font-family: Nunito;"><i><br /></i></span></div><div><span style="font-family: Nunito;"># <b>make install-dep</b></span></div><div><span style="font-family: Nunito;"># <b>make bootstrap</b></span></div><div><span style="font-family: Nunito;">#<b> groupadd vpp</b></span></div><div><span style="font-family: Nunito;"># <b>cp /root/dpdk-patches/* dpdk/dpdk-17.05_patches/</b></span></div><div><span style="font-family: Nunito;"><i> => 앞서 준비해둔 dpdk patch를 적용해 준다.</i></span></div><div><span style="font-family: Nunito;"># <b>make -j4 build-release</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">여기까지 조금은 복잡한 과정을 통해 vpp build가 완료되었다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div><b style="background-color: #fff2cc;"><span style="font-family: Nunito;"><VPP 구동하기></span></b></div><div><span style="font-family: Nunito;">그럼, 지금부터 본격적으로 vpp를 실행해 보도록 하자. 참고로, vpp를 구동하는 방법은 아래와 같이 두가지가 있다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #0b5394; font-family: Nunito;">1. debian package로 만들어 설치(설치 즉시 구동됨)</span></div><div><span style="color: #0b5394; font-family: Nunito;">2. make run-release or make run 등으로 실행</span></div><div><span style="font-family: Nunito;"> </span></div><div><span style="font-family: Nunito;">VPP는 꽤나 덩치가 큰 project이므로, VPP 구동에 필요한 관련 파일을 사전에 파악해 보는 것이 순서일 듯 싶다. 사실 외관상으로만 보면 vpp는 일반적인 user space program의 구성(<b>daemon, 관련 library, config file, control program</b>)과 크게 다를 바가 없다.</span></div><div><span style="font-family: Nunito;">--------------------------------------------------------------------------------------------------</span></div><div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">1) <b>vpp 실행 파일(daemon)</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"> - </span><span style="font-family: Nunito;">build-root/install-vpp-native/vpp => /usr/bin</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div></span></div><div><span style="font-family: Nunito;">2) <b>vpp library 및 plugins 파일</b> </span></div><div><span style="font-family: Nunito;"> - </span><span style="font-family: Nunito;">build-root/install-vpp-native/vpp/lib/* => </span><span style="font-family: Nunito;">/usr/lib/aarch64-linux-gnu/</span></div><div><span style="font-family: Nunito;"> - build-root/install-vpp-native/vpp/lib/vpp_plugins/* => /usr/lib/aarch64-linux-gnu/vpp_plugins</span></div><div><br /></div><div><span style="font-family: Nunito;">3) </span><b style="font-family: Nunito;">vpp config 파일</b></div><div><span style="font-family: Nunito;"><span> - </span><span style="background-color: white; color: #24292e; white-space: pre;">src/scripts/mrvl/mrvl_demo_startup.conf => </span>/etc/vpp/startup.conf</span></div><div><span style="font-family: Nunito;"> - <span style="color: #b45f06;">이 파일은 사용 전에 적절히 수정해 줄 필요가 있다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">4)<b> vpp CLI 파일 </b></span></div><div><span style="font-family: Nunito;"> </span><span style="font-family: Nunito;">- </span><span style="font-family: Nunito;">build-root/build-vpp-native/vpp/bin/vppctl => /usr/bin</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">5) <b>기타 system 설정 파일 변경</b></span></div><div><span style="font-family: Nunito;"> - </span><span style="font-family: Nunito;">/etc/sysctl.d/80-vpp.conf (</span><span style="font-family: Nunito;">hugepage, shared memory 크기 조정)</span></div><div><span style="font-family: Nunito;">-------------------------------------------------------------------------------------------------</span></div><div><span style="font-family: Nunito; text-align: center;"><br /></span></div><div style="text-align: left;"><span style="font-family: Nunito;">여기에서는 <b>make run-release</b>를 이용하여 vpp를 구동시켜 보도록 하자.</span></div><div style="text-align: left;"><span style="font-family: Nunito;"><br /></span></div><div style="text-align: justify;"><span style="font-family: Nunito; text-align: left;"># <b>mkdir -p /etc/vpp/</b></span></div></div><div><span style="font-family: Nunito;"># <b>cp src/scripts/mrvl/mrvl_demo_startup.conf /etc/vpp/startup.conf</b></span></div><div style="text-align: left;"><span style="color: #b45f06; font-family: Nunito;">📌 startup.conf 설정 내용과 관련해서는</span><span style="font-family: Nunito;"><span style="color: #b45f06;"> 다음 장에서 자세히 소개해 보도록 하겠다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <span style="background-color: white; white-space: pre;"><b>modprobe -a musdk_uio mv_dmax2_uio mv_pp_uio mv_sam_uio mvpp2x_sysfs</b></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; white-space: pre;"><i> => 앞서 build해 둔 kernel module(marvell driver)을 구동시킨다.</i></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; white-space: pre;"><br /></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; white-space: pre;"># </span><span style="white-space: pre;"><b>echo 1000 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</b></span></span></div><div><span style="font-family: Nunito;"><i> => hugepage 갯수를 조정한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># cd /root/vpp-marvell</span></div><div><span style="font-family: Nunito;"># <b>export <span style="background-color: white; color: #24292e; white-space: pre;">STARTUP_CONF=/etc/vpp/startup.conf</span></b></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #24292e; white-space: pre;"># <b>make run-release &</b></span></span></div><div></div><div><div><i style="color: #6aa84f; font-family: Nunito; font-size: small;">vlib_plugin_early_init:356: plugin path /usr/lib/vpp_plugins</i></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: acl_plugin.so (Access Control Lists)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: dpdk_plugin.so (Data Plane Development Kit (DPDK))</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: flowprobe_plugin.so (Flow per Packet)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: gtpu_plugin.so (GTPv1-U)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: ila_plugin.so (Identifier-locator addressing for IPv6)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: ioam_plugin.so (Inbound OAM)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:83: Not a plugin: ixge_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: lb_plugin.so (Load Balancer)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: libsixrd_plugin.so (IPv6 Rapid Deployment on IPv4 Infrastructure (RFC5969))</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: memif_plugin.so (Packet Memory Interface (experimetal))</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: nat_plugin.so (Network Address Translation)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>load_one_plugin:184: Loaded plugin: pppoe_plugin.so (PPPoE)</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_export_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/gtpu_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/memif_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/flowprobe_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_pot_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_vxlan_gpe_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/nat_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/pppoe_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/vxlan_gpe_ioam_export_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/udp_ping_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/ioam_trace_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/dpdk_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/acl_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: load_one_plugin:63: Loaded plugin: /usr/lib/vpp_api_test_plugins/lb_test_plugin.so</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>/usr/bin/vpp[2491]: dpdk_config:1214: EAL init args: -c 1 -n 4 --huge-dir /run/vpp/hugepages --file-prefix vpp --master-l </i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>EAL: VFIO support initialized</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>EAL: cannot open /proc/self/numa_maps, consider that all memory is in socket_id 0</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>DPDK physical memory layout:</i></span></div><div><span style="color: #6aa84f; font-family: Nunito; font-size: x-small;"><i>Segment 0: phys:0x89800000, len:268435456, virt:0x7eb2800000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0</i></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">📌 위의 명령 대신 </span></span><span style="font-family: Nunito;"><span style="color: #b45f06;">/usr/bin/vpp -c /etc/vpp/startup.conf & 를 직접 실행해도 된다.</span></span></div><div><br /></div><div><span style="font-family: Nunito;">vpp가 구동되었으니, vppctl을 이용하여 CLI mode로 진입해 본다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>ifconfig eth0 up</b></span></div><div><span style="font-family: Nunito;"># <b>ifconfig eth1 up</b></span></div><div><i> => 먼저 (이후 설정을 대비하여) eth0, eth1 interface를 up 시키자.</i></div><div><br /></div><div><div><span style="font-family: Nunito;">root@localhost:~# <b>telnet 127.0.0.1 5002</b></span></div><div><span style="font-family: Nunito;"><i> => telnet을 통해 vpp 5002 port에 연결한다. </i></span></div><div><span style="font-family: Nunito;"> _______ _ _ _____ ___ </span></div><div><span style="font-family: Nunito;"> __/ __/ _ \ (_)__ | | / / _ \/ _ \</span></div><div><span style="font-family: Nunito;"> _/ _// // / / / _ \ | |/ / ___/ ___/</span></div><div><span style="font-family: Nunito;"> /_/ /____(_)_/\___/ |___/_/ /_/ </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp#</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">이 상태에서 곧 바로, l2 bridge 설정을 해 보도록 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: #fff2cc; font-family: Nunito;"><b><l2 bridge 설정></b></span></div><div><span style="font-family: Nunito;">vpp# <b>set interface state TenGigabitEthernet0 up</b></span></div></div><div><div><span style="font-family: Nunito;">vpp# <b>set interface state TenGigabitEthernet1 up</b></span></div><div><span style="font-family: Nunito;">vpp# <b>create bridge-domain 1</b></span></div><div><span style="font-family: Nunito;">vpp# <b>set interface l2 bridge TenGigabitEthernet0 1</b></span></div><div><span style="font-family: Nunito;">vpp#<b> set interface l2 bridge TenGigabitEthernet1 1</b></span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #b45f06; font-family: Nunito;">📌 위의 설정 내용이 뭘 의미하는지에 대해서도</span><span style="font-family: Nunito;"><span style="color: #b45f06;"> 다음 장에서 자세히 설명하도록 한다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></div><div><span style="font-family: Nunito;">l2 bridge 설정이 완료되었으니, 인터넷 연결 테스트를 해 보자. </span></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div style="text-align: justify;"><span style="color: #0b5394; font-family: Nunito;"><b style="text-align: center;">Windows 10 PC => LAN port[MACCHIATObin board]WAN port => Access Point => Internet</b></span></div><div><span style="font-family: Nunito;"><b><br /></b></span></div><div><span style="font-family: Nunito;"><b>OK, 정상 동작한다.</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">L2 bridge가 정상 동작하는 것을 확인하였으니, 다음 차례는 L3 NAT gateway 설정을 해볼 차례이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="background-color: #fff2cc;"><l3 NAT 설정></b></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>set int state TenGigabitEthernet1 up</b></div><div>vpp# <b>set dhcp client intfc TenGigabitEthernet1 hostname vppgate</b></div><div>vpp# <b>loop create</b></div><div>vpp# <b>set int l2 bridge loop0 1 bvi</b></div><div>vpp# <b>set int ip address loop0 192.168.2.1/24</b></div><div>vpp# <b>set int state loop0 up</b></div><div>vpp# <b>set int l2 bridge TenGigabitEthernet0 1</b></div><div>vpp# <b>set int state TenGigabitEthernet0 up</b></div><div>vpp# <b>nat44 add interface address TenGigabitEthernet1</b></div><div>vpp# <b>set interface nat44 in loop0 out TenGigabitEthernet1 </b></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR"; text-align: justify;"><span style="color: #0b5394; font-family: Nunito;"><b style="text-align: center;">Windows 10 PC(192.168.2.100) => LAN port(192.168.2.1)[MACCHIATObin board]WAN port => Access Point => Internet</b></span></div><div><br /></div></span></div><div><span style="font-family: Nunito;">이 상태에서 인터넷 연결을 시도해 보자. <b style="color: #990000;">어라, 연결이 안된다. </b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ ping 192.168.2.1</span></div><div><span style="font-family: Nunito;"><i> => 이것도 안된다. 왜 그럴까 ?</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">심지어 vppctl를 이용해 CLI 명령 설정 중 vpp daemon이 이유 없이 자주 죽는다. 또한 죽는 시점도 제각각이다. 뭔가 매우 불안정한 느낌이다. 아래 내용은 vpp를 debug mode로 build한 후, gdb로 죽는 상황을 잡아본 것이다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>gdb /usr/bin/vpp</b></span></div><div><span style="font-family: Nunito;">(gdb) <b>run -c /etc/cpp/startup.conf</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjic38G7w7sEz8pw30uSDSJ_nklS7TIHA1iVSVMNxQGRW6L7kS4N_DAEZ4arJGbS49foLNasUP0sxAi1nMsffHZ5nGLNo6m1PKatw94uIylec4U9QGkfTq6mBzXtpvEnv3R0usqZusNnFs7/s1107/vpp_gdb1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="811" data-original-width="1107" height="469" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjic38G7w7sEz8pw30uSDSJ_nklS7TIHA1iVSVMNxQGRW6L7kS4N_DAEZ4arJGbS49foLNasUP0sxAi1nMsffHZ5nGLNo6m1PKatw94uIylec4U9QGkfTq6mBzXtpvEnv3R0usqZusNnFs7/w640-h469/vpp_gdb1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.3] vpp를 gdb로 실행하기</span></div><div><br /></div>(gdb) <b>bt</b><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVbgvdl62k39jVnEUzMPjUec9MEqlr7eitfeCnsa1Ta3I557yRd4L_5Wv4C64_u4_eSpapW-Gc3ihOUigCFWSVMyhMntUjOymNmdx0zHmL6XOwGq0x2B8p8W45WD9oDweEkorYY-_pZHDW/s858/vpp_gdb2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="858" data-original-width="735" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVbgvdl62k39jVnEUzMPjUec9MEqlr7eitfeCnsa1Ta3I557yRd4L_5Wv4C64_u4_eSpapW-Gc3ihOUigCFWSVMyhMntUjOymNmdx0zHmL6XOwGq0x2B8p8W45WD9oDweEkorYY-_pZHDW/w548-h640/vpp_gdb2.png" width="548" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 2.4] gdb backtrace 실행 모습</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp가 죽는 원인을 파악해 보아야 하는데, 아직은 쉽지가 않다(vpp에 익숙해지는데 좀더 시간이 필요한다).<b><span style="color: #e69138;"> </span></b></span><span style="font-family: Nunito;"><b><span style="color: #e69138;">VPP project 자체의 안정성에 문제가 있는 것인지 확인이 필요하다(의심이 간다).</span></b></span><span style="font-family: Nunito;"> 아무래도 좀 old한 방법이기는 하나, PC에 LAN card를 2개 꽂고 동일한 시험을 해 보아야 겠다. </span></div><div><span style="font-family: Nunito;"><div><br /></div></span></div><div><br /></div><div><span style="font-family: Acme;"><b><span style="color: #3d85c6; font-size: x-large;">3. Intel PC(x86_64)에서 VPP 돌려 보기</span></b></span></div><div><span style="font-family: Nunito;">MACCHIATObin 보드에 올렸던 VPP에 심각한 문제(L3 routing & NAT 기능 오동작 및 vpp가 죽는 문제)가 있으니, 이를 PC에서 돌려보면 어떨까 ? 집에 있는 PC에 아래와 같이 구형 Intel NIC(Intel® 82574L Gigabit Ethernet Controller) 2개를 장착하고, 그 위에서 VPP를 돌려 보도록 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvn8Msz-2KykQT38kMT4KJZ8vUkCJ80i4C6aPIU3xJaJk7U77u98DhKQkmjg0eL3Bb2nVPLcMGd6XxIbVQqFzrWVX05PYbMfDODf8HuxavIwU2_C7SdM5ccCc8Ooyxk1Lek9qpSXEB6eos/s350/c04821911.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="176" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvn8Msz-2KykQT38kMT4KJZ8vUkCJ80i4C6aPIU3xJaJk7U77u98DhKQkmjg0eL3Bb2nVPLcMGd6XxIbVQqFzrWVX05PYbMfDODf8HuxavIwU2_C7SdM5ccCc8Ooyxk1Lek9qpSXEB6eos/w96-h191/c04821911.jpg" width="96" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMBpcYuOqr3hrGRra9c5BT7eKt8fsjFbWOwoAYluOFvsREtJGhMwSBy7zTDphI5hsrX7Ayzrboz2IBZbV2Qn-TRENqQZksGz-9YzqR30Alj1nNxBxDeln1RQiV6OMrSUUkfFOwLCZnmOp7/s2048/20201021_194202.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1536" data-original-width="2048" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMBpcYuOqr3hrGRra9c5BT7eKt8fsjFbWOwoAYluOFvsREtJGhMwSBy7zTDphI5hsrX7Ayzrboz2IBZbV2Qn-TRENqQZksGz-9YzqR30Alj1nNxBxDeln1RQiV6OMrSUUkfFOwLCZnmOp7/w259-h194/20201021_194202.jpg" width="259" /></a></div><span style="font-family: Nunito; margin-left: 1em; margin-right: 1em;"> <br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.1] Intel CPU PC와 2 x Intel NIC(<b>82574L</b>)</span></div><span style="font-family: Nunito;"><br /><span style="color: #b45f06;">📌 내가 이런 짓(?)을 다시하게 될 줄이야... 정말 옛날 생각이 난다. 😂</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">아래 내용은 Ubuntu 18.04 LTS(desktop version)를 기준으로 정리한 것이다. </span><span style="font-family: Nunito;">Ubuntu 20.04 LTS에서도 테스트해 보았는데, 몇가지 문제가 있었다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>a) VPP build 하기</b></span></div><div><span style="font-family: Nunito;"><div>MACCHAITObin board에서 build하는 것과는 달리 x86_64 환경에서의 build 절차는 아주 간단하다.</div><div><br /></div><div>$ <b>git clone https://gerrit.fd.io/r/vpp</b></div><div>$ <b>cd vpp</b></div><div>$ <b>make install-dep</b></div><div>$ <b>make build-release</b></div><div><br /></div><div><br /></div></span></div><div><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>b) VPP 구동하기 1</b></span></div><div><span style="font-family: Nunito;"><div>이번에는 make run-release 대신 debian package를 만들어 설치해 보도록 하자.</div><div><br /></div><div>$ <b>make pkg-deb</b></div><div>$ <b>cd build-root; ls -al *.deb</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEiiCQs4wBAsytuOMkJEvT1ahyphenhyphenUAiB3hkIClcC35qgVW48jaPZgW0Qmr_IhWZC6AgZ09OQrv72_O1igafTBdpCq65niWRdqPf8r53F0JSiMof_iNlp02uRhlAYJ0khgvF9MNbTIt35yKkL/s883/vpp_deb_package.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="198" data-original-width="883" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEiiCQs4wBAsytuOMkJEvT1ahyphenhyphenUAiB3hkIClcC35qgVW48jaPZgW0Qmr_IhWZC6AgZ09OQrv72_O1igafTBdpCq65niWRdqPf8r53F0JSiMof_iNlp02uRhlAYJ0khgvF9MNbTIt35yKkL/w400-h90/vpp_deb_package.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] vpp debian package</div><br /><div>$ <b>sudo dpkg -i *.deb</b></div><div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package libvppinfra-dev.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">(데이터베이스 읽는중 ...현재 198109개의 파일과 디렉터리가 설치되어 있습니다.)</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack libvppinfra-dev_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking libvppinfra-dev (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package libvppinfra.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack libvppinfra_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking libvppinfra (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package python3-vpp-api.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack python3-vpp-api_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking python3-vpp-api (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp-api-python.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp-api-python_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp-api-python (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp-dbg.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp-dbg_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp-dbg (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp-dev.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp-dev_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp-dev (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp-plugin-core.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp-plugin-core_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp-plugin-core (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp-plugin-dpdk.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp-plugin-dpdk_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp-plugin-dpdk (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Selecting previously unselected package vpp.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Preparing to unpack vpp_21.01-rc0~275-g784bbcce0_amd64.deb ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Unpacking vpp (21.01-rc0~275-g784bbcce0) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">libvppinfra-dev (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">libvppinfra (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">dpkg: dependency problems prevent configuration of python3-vpp-api:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python3-vpp-api 패키지는 다음 패키지에 의존: python3-cffi: 하지만:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python3-cffi 패키지는 설치하지 않았습니다.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python3-vpp-api 패키지는 다음 패키지에 의존: python3-pycparser: 하지만:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python3-pycparser 패키지는 설치하지 않았습니다.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"><br /></span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">dpkg: error processing package python3-vpp-api (--install):</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> 의존성 문제 - 설정하지 않고 남겨둠</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">dpkg: dependency problems prevent configuration of vpp-api-python:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> vpp-api-python 패키지는 다음 패키지에 의존: python-cffi: 하지만:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python-cffi 패키지는 설치하지 않았습니다.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"><br /></span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">dpkg: error processing package vpp-api-python (--install):</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> 의존성 문제 - 설정하지 않고 남겨둠</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vpp-dbg (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vpp-dev (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vpp (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-console-messages.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">kernel.printk = 4 4 1 7</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-ipv6-privacy.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv6.conf.all.use_tempaddr = 2</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv6.conf.default.use_tempaddr = 2</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-kernel-hardening.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">kernel.kptr_restrict = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-link-restrictions.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">fs.protected_hardlinks = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">fs.protected_symlinks = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-magic-sysrq.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">kernel.sysrq = 176</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-network-security.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv4.conf.default.rp_filter = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv4.conf.all.rp_filter = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv4.tcp_syncookies = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-ptrace.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">kernel.yama.ptrace_scope = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/10-zeropage.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vm.mmap_min_addr = 65536</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /usr/lib/sysctl.d/50-default.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.ipv4.conf.all.promote_secondaries = 1</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">net.core.default_qdisc = fq_codel</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/80-vpp.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vm.nr_hugepages = 1024</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vm.max_map_count = 3096</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vm.hugetlb_shm_group = 0</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">kernel.shmmax = 2147483648</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.d/99-sysctl.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">* Applying /etc/sysctl.conf ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Created symlink /etc/systemd/system/multi-user.target.wants/vpp.service → /lib/systemd/system/vpp.service.</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vpp-plugin-core (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">vpp-plugin-dpdk (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">Processing triggers for libc-bin (2.27-3ubuntu1.2) ...</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;">처리하는데 오류가 발생했습니다:</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> python3-vpp-api</span></i></div><div><i><span style="color: #93c47d; font-size: x-small;"> vpp-api-python</span></i></div></div><div><br /></div><div>어라, 2개의 package<b> python3-vpp-api, vpp-api-python</b>(단, 꼭 필요한 package는 아닌 듯 보임)를 설치하는 과정에서 문제가 발생한다. 일단 아래와 같이 해서 이 문제를 해결하고 넘어가도록 하자.</div><div><br /></div><div><div>chyi@mars:~/workspace/VPP/vpp$ <b>sudo apt --fix-broken install</b></div><div><i><span style="color: #e69138; font-size: x-small;">패키지 목록을 읽는 중입니다... 완료</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">의존성 트리를 만드는 중입니다 </span></i></div><div><i><span style="color: #e69138; font-size: x-small;">상태 정보를 읽는 중입니다... 완료</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">의존성을 바로잡는 중입니다... 완료</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">다음의 추가 패키지가 설치될 것입니다 :</span></i></div><div><i><span style="color: #e69138; font-size: x-small;"> python-cffi python-ply python-pycparser python3-cffi python3-pycparser</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">제안하는 패키지:</span></i></div><div><i><span style="color: #e69138; font-size: x-small;"> python-ply-doc</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">다음 새 패키지를 설치할 것입니다:</span></i></div><div><i><span style="color: #e69138; font-size: x-small;"> python-cffi python-ply python-pycparser python3-cffi python3-pycparser</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">0개 업그레이드, 5개 새로 설치, 0개 제거 및 7개 업그레이드 안 함.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">2개를 완전히 설치하지 못했거나 지움.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">317 k바이트 아카이브를 받아야 합니다.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">이 작업 후 2,041 k바이트의 디스크 공간을 더 사용하게 됩니다.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">계속 하시겠습니까? [Y/n] y</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">받기:1 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 python3-pycparser all 2.18-2 [67.7 kB]</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">받기:2 http://kr.archive.ubuntu.com/ubuntu bionic/universe amd64 python3-cffi all 1.11.5-1 [67.4 kB]</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">받기:3 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-ply all 3.11-1 [46.6 kB]</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">받기:4 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-pycparser all 2.18-2 [67.6 kB]</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">받기:5 http://kr.archive.ubuntu.com/ubuntu bionic/main amd64 python-cffi all 1.11.5-1 [67.3 kB]</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">내려받기 317 k바이트, 소요시간 6초 (53.3 k바이트/초)</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Selecting previously unselected package python3-pycparser.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">(데이터베이스 읽는중 ...현재 199978개의 파일과 디렉터리가 설치되어 있습니다.)</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Preparing to unpack .../python3-pycparser_2.18-2_all.deb ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Unpacking python3-pycparser (2.18-2) ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Selecting previously unselected package python3-cffi.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Preparing to unpack .../python3-cffi_1.11.5-1_all.deb ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Unpacking python3-cffi (1.11.5-1) ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Selecting previously unselected package python-ply.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Preparing to unpack .../python-ply_3.11-1_all.deb ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Unpacking python-ply (3.11-1) ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Selecting previously unselected package python-pycparser.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Preparing to unpack .../python-pycparser_2.18-2_all.deb ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Unpacking python-pycparser (2.18-2) ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Selecting previously unselected package python-cffi.</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Preparing to unpack .../python-cffi_1.11.5-1_all.deb ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Unpacking python-cffi (1.11.5-1) ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python-ply (3.11-1) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python3-pycparser (2.18-2) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python3-cffi (1.11.5-1) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python-pycparser (2.18-2) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python3-vpp-api (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">python-cffi (1.11.5-1) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">vpp-api-python (21.01-rc0~275-g784bbcce0) 설정하는 중입니다 ...</span></i></div><div><i><span style="color: #e69138; font-size: x-small;">Processing triggers for man-db (2.8.3-2ubuntu0.1) ...</span></i></div></div><div><br /></div><div>$ <b>ps aux|grep vpp</b></div><div><i> => (앞서 약간의 문제가 있긴 했지만)package 설치 후, vpp가 정상 구동되는 것을 알 수 있다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvvdC950n6gbRGWdj0JaOC1qeVGwzUFS8LPbGKihHPe-Mwpy0hOiMWXurN84iJ2C99lQQpvGD0Ggtdqc0sePQRxq63BEqfriKTqFnYj__ieo3gfPtFhOuc8k3Hjn3YemJmVKSqQvTNUbov/s943/vpp_runngin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="74" data-original-width="943" height="55" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvvdC950n6gbRGWdj0JaOC1qeVGwzUFS8LPbGKihHPe-Mwpy0hOiMWXurN84iJ2C99lQQpvGD0Ggtdqc0sePQRxq63BEqfriKTqFnYj__ieo3gfPtFhOuc8k3Hjn3YemJmVKSqQvTNUbov/w710-h55/vpp_runngin.png" width="710" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] 구동 중인 vpp daemon 확인</div><div><br /></div><div>-----------------------[참고: make run-release 로 vpp 구동시키기] ------------------</div><div>$ <b>sudo bash</b></div><div>#<b> mkdir -p /etc/vpp/</b></div><div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"># <b>cp src/scripts/mrvl/mrvl_demo_startup.conf /etc/vpp/startup.conf</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">#</span><span style="font-family: Nunito;"> </span><b style="font-family: Nunito;">export <span style="background-color: white; color: #24292e; white-space: pre;">STARTUP_CONF=/etc/vpp/startup.conf</span></b></div></div><div># <b>make run-release &</b></div></span></div><div><span style="font-family: Nunito;">--------------------------------------------------------------------------------------</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp 구동에 사용된 config 파일(/etc/vpp/startup.conf)을 열어 보면 다음과 같다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">#<b> vi </b></span><span style="font-family: Nunito;"><b>/etc/vpp/startup.conf</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAI73x4rrKt3MRjVkd5rpaWrVEvaqch7AQ-FGTPU2EOuY9yQ2zbZxB2kGxDUvA4TZX44E0WQEhTRT_ahOP4zvRqKYkGXJ7KuqDjO4qajyvCwLkzHf1ut250bCUGW18BjFQhXx5PHf_4KXV/s875/vpp_startup_conf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="758" data-original-width="875" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAI73x4rrKt3MRjVkd5rpaWrVEvaqch7AQ-FGTPU2EOuY9yQ2zbZxB2kGxDUvA4TZX44E0WQEhTRT_ahOP4zvRqKYkGXJ7KuqDjO4qajyvCwLkzHf1ut250bCUGW18BjFQhXx5PHf_4KXV/w400-h346/vpp_startup_conf.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.4] /etc/vpp/startup.conf 파일</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">📌 startup.conf의 세부 필드의 의미에 대해서는 아래 site의 내용을 참조하기 바란다.</span></span></div><div style="text-align: center;"><span style="color: #b45f06; font-family: Nunito;"><a href="https://fd.io/docs/vpp/latest/gettingstarted/users/configuring/index.html">https://fd.io/docs/vpp/latest/gettingstarted/users/configuring/index.html</a></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><b style="background-color: #ead1dc;"><주의 사항></b></span></div><div><span style="font-family: Nunito;">VPP 설치 관련 <a href="https://fd.io/docs/vpp/latest/gettingstarted/users/configuring/hugepages.html">guide 문서</a>를 보면, 아래와 같이 <b>/etc/sysctl.d/80-vpp.conf </b>파일의 설정(hugepages 갯수, shared memory 최대 크기)을 조정하도록 권고하고 있다. 이는 vpp의 performance를 끌어올리기 위한 조치(vector packet processing 시 활용)인데, desktop 환경에서는 특별히 주의해서 설정해 주어야 한다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-IeBnw8FXnMl4Mue1ppBMnGcXlbPIUkT9w_iiO3MrhCufjgb5bnT03Sj8d9AZe2L341EJeqCng3KegnaefqYDsm8SYpJPhmgkRC9lfHbNo1jkMYTQemlty_SJb4W3qGt2DDaLalrd2ZzP/s701/vpp_80vpp_conf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="335" data-original-width="701" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-IeBnw8FXnMl4Mue1ppBMnGcXlbPIUkT9w_iiO3MrhCufjgb5bnT03Sj8d9AZe2L341EJeqCng3KegnaefqYDsm8SYpJPhmgkRC9lfHbNo1jkMYTQemlty_SJb4W3qGt2DDaLalrd2ZzP/w400-h191/vpp_80vpp_conf.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.5] /etc/ </span><span style="text-align: left;"><span style="font-family: Nunito;">sysctl.d/80-vpp.conf </span></span><span style="font-family: Nunito;">파일</span></div><div><br /></div><div><span style="font-family: Nunito;">root@mars:/etc/sysctl.d# <b>sysctl -p /etc/sysctl.d/80-vpp.conf</b></span></div><div><span style="font-family: Nunito;">vm.nr_hugepages = 4096</span></div><div><span style="font-family: Nunito;">vm.max_map_count = 9216</span></div><div><span style="font-family: Nunito;">vm.hugetlb_shm_group = 0</span></div><div><span style="font-family: Nunito;">kernel.shmmax = 8589934592</span></div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #990000; font-family: Nunito;">즉, 이 설정을 Ubuntu 18.04 LTS(desktop), RAM 8GB 정도의 환경에서 적용하게 되면, 시스템 재 부팅시 Login 화면이 출력 안되고, 결국에는 시스템이 멈춰 버릴 수 있으니 주의하기 바란다.</span></div><div><span style="font-family: Nunito;">______________________________________________</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">드디어 vpp가 구동되었으니, vppctl로 접속해 보자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>vppctl</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhYyyyNymWRkfd2_yAxRuURvwTX0rx7WbuCWELFRzmySLxjFAlRwnella9fgxlbnDPj3sPGukQWd3mTvPy6ZZFfAbBdA97D1J4W6xdOHfCZYmUXqo9KALySOmvkswodSOrkZpor18hvdnk/s891/vppctl1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="221" data-original-width="891" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhYyyyNymWRkfd2_yAxRuURvwTX0rx7WbuCWELFRzmySLxjFAlRwnella9fgxlbnDPj3sPGukQWd3mTvPy6ZZFfAbBdA97D1J4W6xdOHfCZYmUXqo9KALySOmvkswodSOrkZpor18hvdnk/w400-h99/vppctl1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.6] vppctl로 접속한 모습</span></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;"><span style="color: #b45f06;">📌 앞선 장에서와는 달리 이번에는 telnet을 이용하지 않고 vppctl 명령을 곧 바로 사용하였다. 이는 startup.conf 파일에서 아래와 같이 설정(tcp port 5002가 아니라 domain socket으로 연결)해 주었기 때문이다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">---------------------------------------------</span></span></div><div><span style="font-family: Nunito;"><div><span style="font-size: x-small;">unix {</span></div><div><span style="font-size: x-small;"> nodaemon</span></div><div><span style="font-size: x-small;"> log /var/log/vpp/vpp.log</span></div><div><span style="font-size: x-small;"> full-coredump</span></div><div><span style="font-size: x-small;"> <b><span style="color: #990000;">cli-listen /run/vpp/cli.sock </span></b></span></div><div><span style="font-size: x-small;"> gid vpp</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"> ## run vpp in the interactive mode</span></div><div><span style="font-size: x-small;"> # interactive</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"> ## do not use colors in terminal output</span></div><div><span style="font-size: x-small;"> # nocolor</span></div><div><span style="font-size: x-small;"><br /></span></div><div><span style="font-size: x-small;"> ## do not display banner</span></div><div><span style="font-size: x-small;"> # nobanner</span></div><div><span style="font-size: x-small;">}</span></div><div style="color: #b45f06;">---------------------------------------------</div></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></div><div><span style="font-family: Nunito;">근데, 한가지 문제가 있다. show interface 명령을 실행해 보았는데, 생각과는 달리 2개의 ethernet port가 보이질 않는다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"># <b>vppctl</b></span></div><div><span style="font-family: Nunito;">vpp#<b> show int</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvSc-CHni0Cg4z-JJfLST4Fswt9kRzBcbDlOKLRDMMpB1YbBbGAL2vdPa5-x_fLmaLjr9IiTRkDmyO8EkhZSLUoywWWB_7KxqJ6b0Mjr3EPnnb3myWtlj3s5RYmQyXsMuLpNdUi3m7fYS7/s891/vppctl_without_interfaces.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="191" data-original-width="891" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvSc-CHni0Cg4z-JJfLST4Fswt9kRzBcbDlOKLRDMMpB1YbBbGAL2vdPa5-x_fLmaLjr9IiTRkDmyO8EkhZSLUoywWWB_7KxqJ6b0Mjr3EPnnb3myWtlj3s5RYmQyXsMuLpNdUi3m7fYS7/w400-h86/vppctl_without_interfaces.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.7] interface 확인 모습</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>c) VPP 구동하기 2 - dpdk 설치 및 binding</b></span></div><div>지금까지의 과정으로 vpp가 간단히 구동되면 좋겠으나, 실제로는 한단계 과정이 더 남아 있다. 즉, dpdk driver를 설치하고, network adapter를 dpdk와 binding 시켜주어야만 vpp가 제대로 동작하게 된다.</div><div><br /></div><div>$ <b>sudo apt install dpdk</b></div><div><span style="color: #b45f06;">📌 물론, 아래 방법으로 dpdk source를 내려 받아 build 후 설치하는 방법도 있다.</span></div><div style="text-align: center;"><b>git clone https://github.com/DPDK/dpdk</b></div><div><br /></div><div><span style="color: #b45f06;">----------------------------- [dpdk source build 하기] ------------------------------</span></div><div><div><span style="color: #b45f06;">$ <b>sudo apt install python3-pip</b></span></div><div><span style="color: #b45f06;">$ <b>pip3 install meson ninja</b></span></div></div><div><span style="color: #b45f06;">$ <b>sudo apt install meson</b></span></div><div><span style="color: #b45f06;">$ <b>source ~/.profile</b></span></div><div><div><span style="color: #b45f06;"><br /></span></div><div><span style="color: #b45f06;">$ <b>git clone https://github.com/DPDK/dpdk</b></span></div><div><span style="color: #b45f06;">$ <b>cd dpdk</b></span></div></div><div><span style="color: #b45f06;">$ <b>meson build</b></span></div><div><div><span style="color: #b45f06;">$ <b>cd build</b></span></div><div><span style="color: #b45f06;">$ <b>ninja</b></span></div></div><div><div><span style="color: #b45f06;">$ <b>sudo ninja install</b></span></div><div><span style="color: #b45f06;">$ <b>sudo ldconfig</b></span></div></div><div><span style="color: #b45f06;">________________________________________________________________________</span></div><div><br /></div><div>$ <b>sudo bash</b></div><div>#<b> sudo dpdk-devbind -s</b></div><div><i> => dpdk-devbind 명령으로 ethernet adapter가 DPDK에 bind되어 있는지를 확인해 본다. 당연히 처음에는 아무것도 dpdk에 binding되어 있지 않을 것이다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdnJi_6Kq9nk097TNY_5KRqf6zEj8vyzgBDKGt2pw-YDho0TmlxanslVKKmimZYSDy88MHBNKlkLLG3r0mhNVg-CiKv3v-t8lbGYE4T6HJT0CtlybSQn_WpKgvC7ZpTiLSRMWXTh8Zsvl/s1168/dpdk_bind1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="779" data-original-width="1168" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhdnJi_6Kq9nk097TNY_5KRqf6zEj8vyzgBDKGt2pw-YDho0TmlxanslVKKmimZYSDy88MHBNKlkLLG3r0mhNVg-CiKv3v-t8lbGYE4T6HJT0CtlybSQn_WpKgvC7ZpTiLSRMWXTh8Zsvl/w400-h266/dpdk_bind1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.8] dpdk binding 상태 확인 모습</div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #6aa84f;">Network devices using DPDK-compatible driver</span></div><div><span style="color: #6aa84f;">============================================</span></div><div><span style="color: #990000;"><b><none></b></span></div><div><span style="color: #6aa84f;"><br /></span></div><div><span style="color: #6aa84f;">Network devices using kernel driver</span></div><div><span style="color: #6aa84f;">===================================</span></div><div><span style="color: #6aa84f;">0000:01:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller 8168' if=enp1s0 drv=r8169 unused=vfio-pci,uio_pci_generic </span></div><div><span style="color: #6aa84f;">0000:</span><b><span style="color: #990000;">02:00.0</span></b><span style="color: #6aa84f;"> '</span><span style="color: #351c75;">82574L Gigabit Network Connection</span><span style="color: #6aa84f;"> 10d3' if=enp2s0 drv=e1000e unused=vfio-pci,uio_pci_generic </span></div><div><span style="color: #6aa84f;">0000:</span><b><span style="color: #990000;">03:00.0</span></b><span style="color: #6aa84f;"> '</span><span style="color: #351c75;">82574L Gigabit Network Connection</span><span style="color: #6aa84f;"> 10d3' if=enp3s0 drv=e1000e unused=vfio-pci,uio_pci_generic </span></div><div><span style="color: #6aa84f;">...</span></div><div><div><br /></div><div># <b>sudo dpdk-devbind --bind uio_pci_generic <span style="color: #990000;">02:00.0</span></b></div><div># <b>sudo dpdk-devbind --bind uio_pci_generic <span style="color: #990000;">03:00.0</span></b></div></div><div><i> => 2개의 PCI ethernet controller를 dpdk에 bind시킨다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj18xlaGhOKcbTazkpgD1iRGO4V-1reVlJr3qcBTY-OMsaRtXVJuttu4na85pUVTId6PHUcbU6irTPICSAlFCtGxsjZA8QhlSz8GB_nvIzeXp15XnXxgmGc0KVuH_8a6wS2iHRGZbwxysDO/s880/dpdk_bind2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="329" data-original-width="880" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj18xlaGhOKcbTazkpgD1iRGO4V-1reVlJr3qcBTY-OMsaRtXVJuttu4na85pUVTId6PHUcbU6irTPICSAlFCtGxsjZA8QhlSz8GB_nvIzeXp15XnXxgmGc0KVuH_8a6wS2iHRGZbwxysDO/w400-h150/dpdk_bind2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.9] 2개의 Intel NIC이 dpdk에 binding된 모습</div><div><br /></div><div><span style="color: #b45f06;">📌 unbind하려면 아래와 같이 해주면 된다.</span></div><div><div style="text-align: center;"><span style="color: #b45f06;"># sudo dpdk-devbind --unbind 0000:02:00.0</span></div><div style="text-align: center;"><span style="color: #b45f06;"># sudo dpdk-devbind --unbind 0000:03:00.0</span></div></div><div><br /></div><div># <b>service vpp restart</b></div><div>dpdk binding이 변경되었으니, vpp를 재구동 시킨다.</div><div><br /></div><div># <b>vppctl</b></div><div>vpp#<b> show int</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVV_lf2JUTPfSOGuVgoeozUz7uKIu-ipeH19Kc30V-G7w403F9RVUTC3eBETdhphsnbtF90L3lWsHM-QgKw3JnPXitM0IuUSwrEQXt7Qrwgt7oyDTiWeRgvtLL7g1nAKP5y7k2o_zaogfX/s868/vppctl2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="235" data-original-width="868" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVV_lf2JUTPfSOGuVgoeozUz7uKIu-ipeH19Kc30V-G7w403F9RVUTC3eBETdhphsnbtF90L3lWsHM-QgKw3JnPXitM0IuUSwrEQXt7Qrwgt7oyDTiWeRgvtLL7g1nAKP5y7k2o_zaogfX/w400-h109/vppctl2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.10] 2개의 gigabit interface 출력 모습</div><div><br /></div><div>자, 이제 정말로 vpp를 사용할 수 있는 기본 준비가 모두 완료되었다. 이제 부터 l2 bridge, L3 gateway 설정을 차례로 진행해 보도록 하자.</div><div><br /></div><div><div style="font-family: "Noto Sans CJK KR"; text-align: center;"><span style="font-family: Nunito;"><b><참고: Network port 설정></b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><div style="text-align: center;">GigabitEthernet2/0/0 : WAN</div><div style="text-align: center;">GigabitEthernet3/0/0 : LAN</div><div style="text-align: center;"><br /></div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-mNXsOfwZioHbroISKqJBJXYSHfU4cTvg4vvaBWDcAg8oBrJ6WAwK7Q8n93L0xyq5rqNP_-5x4JMOa04qUGaumnMyh5uxDRnFBj91QKbSU86uXJlB0mMMZ8N8PGoMFnd_KkQlbbIOPBsi/s623/PC_vpp_gateway.PNG" style="font-family: "Noto Sans CJK KR"; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="520" data-original-width="623" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-mNXsOfwZioHbroISKqJBJXYSHfU4cTvg4vvaBWDcAg8oBrJ6WAwK7Q8n93L0xyq5rqNP_-5x4JMOa04qUGaumnMyh5uxDRnFBj91QKbSU86uXJlB0mMMZ8N8PGoMFnd_KkQlbbIOPBsi/s320/PC_vpp_gateway.PNG" width="320" /></a></div><div style="text-align: center;">[그림 3.11] L2 bridge 네트워크 구성도</div></span></div></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #38761d; font-family: Nunito; font-size: medium;"><b>d) L2 bridge 설정하기</b></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>set interface state GigabitEthernet3/0/0 up</b></div><div>vpp# <b>set interface state GigabitEthernet2/0/0 up</b></div><div><i> => WAN, LAN interface를 up 시킨다.</i></div><div>vpp# <b>create bridge-domain 1</b></div><div><i> => l2 bridge domain(1번 domain)을 하나 생성한다.</i></div><div>vpp# <b>set interface l2 bridge GigabitEthernet3/0/0 1</b></div><div>vpp# <b>set interface l2 bridge GigabitEthernet2/0/0 1</b></div><div><i> => l2 bridge domain 1에 WAN, LAN interface를 포함시킨다.</i></div><div><br /></div></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7RUAIDvcqwQ8x8UW4QHJ_PFUwgIwRjt1sbE-WnXuXzXsypjjgXVEnEaSx7294kMzz0uiLj2K4OQDJ6qPiS3dNIz_7aS0zy2khpjHS9OSdHFPRistmQJrrP8iCTUQX0gXFb64vdS61hjNs/s776/vpp_l2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="361" data-original-width="776" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7RUAIDvcqwQ8x8UW4QHJ_PFUwgIwRjt1sbE-WnXuXzXsypjjgXVEnEaSx7294kMzz0uiLj2K4OQDJ6qPiS3dNIz_7aS0zy2khpjHS9OSdHFPRistmQJrrP8iCTUQX0gXFb64vdS61hjNs/w400-h186/vpp_l2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.12] L2 bridge 설정 모습</span></div><div><span style="font-family: Nunito;"><br /></span></div><span style="font-family: Nunito;">이 정도만 하면 아주 기본적인 L2 bridge가 하나 만들어지게 된다. 이 상태에서 인터넷 연결을 시도해 보도록 하자.</span></div><div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div style="text-align: center;"><span style="font-family: Nunito;"><b><span style="color: #0b5394;">Windows 10 PC => LAN port [</span><span style="color: #800180;">Intel PC Gateway</span><span style="color: #0b5394;">] WAN port => Access Point => Internet</span></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">예상대로 정상 동작한다. 이 상태에서 CPU 사용량을 체크해 보도록 하자.<br /></span><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYvUuonhnnL5yEnPOJUlP_BxY2n74btVBFbOH4CTTFN9o8jJm1iTVMDUJapUuYRB3rtkwIfcsHQdXRnvsBg5xsa61s-CdYCOs0ynlyfzQ0ar5XZLYlxZj0wJDfEqylZSkMbSL3ZWundOE5/s828/vpp_top.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="795" data-original-width="828" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYvUuonhnnL5yEnPOJUlP_BxY2n74btVBFbOH4CTTFN9o8jJm1iTVMDUJapUuYRB3rtkwIfcsHQdXRnvsBg5xsa61s-CdYCOs0ynlyfzQ0ar5XZLYlxZj0wJDfEqylZSkMbSL3ZWundOE5/s320/vpp_top.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 3.13] Intel PC의 CPU 사용량</span></div></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06; font-family: Nunito; text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b45f06; font-family: Nunito; text-align: left;">📌 허걱, CPU 사용률이 100%에 육박한다. 하지만 이건 정상이다. dpdk는 cpu core 중 하나를 packet capture(polling) 용으로만 사용한다. 즉, cpu를 놀리지 않고 열심히 packet capture만 하도록 하여 성능을 향상 시키겠다는 뜻이다. 물론, 이게 맘에 안든다면 startup.conf의 설정을 조정하여 cpu 사용률을 10 ~ 20% 수준으로 떨어뜨릴 수도 있다. 하지만 이렇게 되면 100%의 성능을 내기는 어렵게 된다.</span></div><div class="separator" style="clear: both; text-align: center;"><span style="color: #b45f06; font-family: Nunito; text-align: left;"><br /></span></div><b style="color: #38761d; font-family: Nunito; font-size: large;">e) L3 NAT 설정하기</b><span style="font-family: Nunito;"><br /></span><span style="font-family: Nunito;"><span><div># <b>service vpp restart</b></div><div> <i>=> l2 bridge 설정을 날려야 하니, vpp를 재 시작하도록 한다.</i></div><div><br /></div><div># <b>vppctl</b></div><div>vpp# <b>set int state GigabitEthernet2/0/0 up</b></div></span></span><span style="font-family: Nunito;"><span><div><i> => WAN interface를 up시킨다.</i></div><div>vpp# <b>set dhcp client intfc GigabitEthernet2/0/0 hostname vppsg</b></div><div><i> => dhcp client를 사용하여 상위 gateway(예: 무선 Access Point)로 부터 ip & dns 정보 등을 할당 받는다.</i></div></span></span><span style="font-family: Nunito;"><span><div><br /></div><div>vpp# <b>loop create</b></div></span></span><span style="font-family: Nunito;"><span><div>vpp# <b>set int l2 bridge loop0 1 bvi</b></div><div><i> => l2 bridge를 하나 생성한다.</i></div></span></span><span style="font-family: Nunito;"><span><div>vpp# <b>set int ip address loop0 192.168.3.1/24</b></div></span></span><span style="font-family: Nunito;"><span><div>vpp# <b>set int state loop0 up </b></div></span></span><span style="font-family: Nunito;"><span><div><i> => l2 bridge에 대표 ip 192.168.3.1/24를 할당하고, interface를 up 시킨다.</i></div><div>vpp# <b>set int l2 bridge GigabitEthernet3/0/0 1</b></div></span></span><span style="font-family: Nunito;"><span><div>vpp# <b>set interface state GigabitEthernet3/0/0 up</b></div><div><i> => LAN interface를 l2 bridge에 포함시키고, interface를 up시킨다.</i></div><div><br /></div></span></span><span style="font-family: Nunito;"><span><div>vpp# <b>nat44 add interface address GigabitEthernet2/0/0</b></div></span></span><span style="font-family: Nunito;"><span><div><i> => NAT44 interface로 WAN port를 등록한다.</i></div><div>vpp# <b>set interface nat44 in loop0 out GigabitEthernet2/0/0</b></div><div><i> => l2 bridge(loop0 interface)를 input으로 하고, WAN port를 output으로 하는 NAT44 rule을 추가한다.</i></div><div><br /></div><div>vpp# <b>show int addr</b></div><div><i> => 지금까지 설정한 내용을 확인해 보면 다음과 같다. WAN port의 경우 DHCP 서버로 부터 ip(192.168.7.207/24)를 정상적으로 받아오고 있음을 알 수 있다.</i></div></span></span><span style="font-family: Nunito;"><span><div><span style="color: #b45f06;">GigabitEthernet2/0/0 (up):</span></div><div><span style="color: #b45f06;"> L3 192.168.7.207/24</span></div><div><span style="color: #b45f06;">GigabitEthernet3/0/0 (up):</span></div><div><span style="color: #b45f06;"> L2 bridge bd-id 1 idx 1 shg 0 </span></div><div><span style="color: #b45f06;">local0 (dn):</span></div><div><span style="color: #b45f06;">loop0 (up):</span></div><div><span style="color: #b45f06;"> L2 bridge bd-id 1 idx 1 shg 0 bvi</span></div><div><span style="color: #b45f06;"> L3 192.168.3.1/24</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPZrGHosYg2lUCdZ53jOTjswnDs7DmcZVV7zrZYAmpax6COm9bp4GUrOXPmQMR1wa6bbDXGL0SWrJFVZaCllJVgM55DYIDegGm-tle0uyWKrtHSAtDNhdHarXeas0ajHgGm5HIALs9GJRf/s926/vpp_nat.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="911" data-original-width="926" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPZrGHosYg2lUCdZ53jOTjswnDs7DmcZVV7zrZYAmpax6COm9bp4GUrOXPmQMR1wa6bbDXGL0SWrJFVZaCllJVgM55DYIDegGm-tle0uyWKrtHSAtDNhdHarXeas0ajHgGm5HIALs9GJRf/w400-h394/vpp_nat.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.14] L3 NAT 설정</div><div><br /></div></span></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">기본적인 L3 gateway 설정을 끝냈으니, 역시 이 상태에서 인터넷 연결을 시도해 보도록 하자.</span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR"; text-align: center;"><span style="font-family: Nunito;"><b>Windows 10 PC(<span style="color: #b45f06;">192.168.3.10/24</span>) => LAN port(<span style="color: #b45f06;">192.168.3.1/24</span>) [<span style="color: #800180;">Intel PC Gateway</span>]WAN port => Access Point => Internet</b></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;"><br /></span></div><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Nunito;">예상대로 정상 동작한다. 2장에서와는 달리 <b><span style="color: #990000;">매우 안정적인 느낌이다</span></b>. 여러가지 설정을 해 보았는데, vpp는 한차례도 죽지를 않았다. 장시간 켜 놓아도 마찬가지다. 이만하면 vpp 꽤나 쓸만한 녀석이라는 생각이 든다. 😃</span></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Acme;"><br /></span></div><div><b><span style="color: #3d85c6; font-family: Acme; font-size: x-large;">4. VPP Wireguard Plugin 시험하기</span></b></div><div><span style="font-family: Nunito;">FD.io VPP에는 아주 다양한 기능이 있다. 그 중에서도 (현재 개발 중인 상태이기는 하지만) Wireguard가 눈에 띈다. 제대로 동작할지 어떨지 직접 시험해 보기로 하자.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcp6R0LGZAEuXWppf5MiXtDpEEVSbG0WiH-J-sI3VzZhtut6koFkKSXhs8sXvrsfc-Jd1KgHGuBAMyJ2i-xHzH9D3zvws4i8zdP1B7pE5_vFg2OJic6Vx_oOglzxqoNFJ1QWjXoapA0RPk/s736/vpp_gateway_wireguard.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="736" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcp6R0LGZAEuXWppf5MiXtDpEEVSbG0WiH-J-sI3VzZhtut6koFkKSXhs8sXvrsfc-Jd1KgHGuBAMyJ2i-xHzH9D3zvws4i8zdP1B7pE5_vFg2OJic6Vx_oOglzxqoNFJ1QWjXoapA0RPk/w400-h235/vpp_gateway_wireguard.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: Nunito;">[그림 4.1] VPP Wireguard 시험 환경</span></div></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><b style="font-family: Nunito;">Windows 10 PC => <span style="color: #b45f06;">VPP Gateway(WireGuard Plugin)</span> => Access Point => [Internet] <= LTE Egg <= <span style="color: #0b5394;">Ubuntu 18.04(WireGuard)</span></b></div><div><span style="font-family: Nunito;"><br /></span></div><div style="text-align: center;"><span style="font-family: Nunito;">VPP Gateway: <b>10.1.1.100</b></span></div><div style="text-align: center;"><span style="font-family: Nunito;">Ubuntu 18.04: <b>10.1.1.200</b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #b45f06; font-family: Nunito;"><b><VPP Gateway></b></span></div><div><span style="font-family: Nunito;"><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGndYDYcdvrrbaVpzdbaORv_zX9C46pYrte_weoWfs_DYNl0ZlYTQFecFtnuIgf4nqb8LDkPGpzGpfPbyM3NPDle6g8J1L5YESge4dBdpBikeS9yX_arOIC-laws9KDSWhZ1XD0CKEBIR_/s971/vpp_wireguard_usage.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="147" data-original-width="971" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGndYDYcdvrrbaVpzdbaORv_zX9C46pYrte_weoWfs_DYNl0ZlYTQFecFtnuIgf4nqb8LDkPGpzGpfPbyM3NPDle6g8J1L5YESge4dBdpBikeS9yX_arOIC-laws9KDSWhZ1XD0CKEBIR_/w640-h96/vpp_wireguard_usage.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.2] VPP wireguard 명령 사용법</div><div><br /></div><div>vpp# <b>wireguard create listen-port 51920 src 10.1.1.100</b></div><div>wg0</div><div><i> => 재밌게도 wg0 interface가 자동으로 생성된다. wireguard create 명령을 다시 시도하면 wg1이 생성되게 된다.</i></div><div><br /></div><div>vpp# <b>show wireguard interface </b></div><div>[0] wg0 src:10.1.1.100 port:51920 <span style="color: #bf9000;">private-key</span>:GAAAADAAAADw7RGUM38AABDtEZQzfwAAk9Gh7jN/AAA= 1800000030000000f0ed1194337f000010ed1194337f000093d1a1ee337f0000 <span style="color: #c27ba0;">public-key</span>:<span style="color: #b45f06;">OlmkEvwpaY40jKiHM7Ntyvn5tf1SvqOC/6A308JEIlc=</span> 3a59a412fc29698e348ca88733b36dcaf9f9b5fd52bea382ffa037d3c2442257 mac-key: da4c390d28bc5307b6ad42d89b8ea57923819d44e4956b9aa3eb85454e1f7f8f</div></span></div><div><span style="font-family: Nunito;"><i> => index 0번인 wireguard interface의 속성 정보(private, public key)가 출력된다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp# <b>set int state wg0 up</b></span></div><div><span style="font-family: Nunito;">vpp# <b>set int ip address wg0 10.1.1.100/24</b></span></div><div><span style="font-family: Nunito;"><i> => wg0 interface에 ip 주소를 부여하고 up 시킨다.</i></span></div><div><br /></div><div><span style="font-family: Nunito;">vpp# <b>wireguard peer add wg0 public-key oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs= endpoint 0.0.0.0 port 0 allowed-ip 10.1.1.0/24 persistent-keepalive 25</b></span></div><div><span style="font-family: Nunito;"><i> => peer 정보를 추가한다.</i></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;">📌 wireguard peer add 명령 사용법에 bug가 있다. 즉 dst-port [port_dst] 대신 port [port_dst]를 사용해야 한다.</span></span></div><div><span style="font-family: Nunito;"><span style="color: #b45f06;"><br /></span></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>show wireguard peer </b></div><div>[0] endpoint:[10.1.1.100:51920->0.0.0.0:0] wg0 keep-alive:25 adj:5</div><div> key:oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs= a06a90106753868e63c28aaddda2226185df7a1413cbcdc53582870ba1c1514b</div><div> allowed-ips: 10.1.1.0/24</div></span></div><div><span style="font-family: Nunito;"><i> => peer의 정보를 출력한다.</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">vpp# <b>ping 10.1.1.200</b></span></div><div><span style="font-family: Nunito;"><div><i> => 아래 Ubuntu 18.4에서의 wireguard 설정 후, ping을 시도해 본다.</i></div><div>Statistics: 5 sent, 0 received, 100% packet loss</div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #0b5394; font-family: Nunito;"><b><Ubuntu 18.04 - WireGuard></b></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #222222;">$ <b>wg genkey | tee privatekey | wg pubkey > publickey</b></span></span></div><div><span style="font-family: Nunito;"><span style="background-color: white; color: #222222;">$ <b>sudo ip link add dev wg0 type wireguard</b></span><br style="background-color: white; color: #222222;" /><span style="background-color: white; color: #222222;">$ <b>sudo ip address add dev wg0 </b></span><a data-saferedirecturl="https://www.google.com/url?q=http://10.1.1.200/24&source=gmail&ust=1603616434141000&usg=AFQjCNEotvUMqYtuWnk7pOYkFjGI7RHDfg" href="http://10.1.1.200/24" style="background-color: white; color: #1155cc;" target="_blank"><b>10.1.1.200/24</b></a><br style="background-color: white; color: #222222;" /><span style="background-color: white; color: #222222;">$ <b>sudo ip link set up dev wg0</b></span><br style="background-color: white; color: #222222;" /><br style="background-color: white; color: #222222;" /><span style="background-color: white; color: #222222;">$ <b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer OlmkEvwpaY40jKiHM7Ntyvn5tf1Svq</b></span><b><wbr style="background-color: white; color: #222222;"></wbr><span style="background-color: white; color: #222222;">OC/6A308JEIlc= allowed-ips </span><a data-saferedirecturl="https://www.google.com/url?q=http://10.1.1.0/24&source=gmail&ust=1603616434141000&usg=AFQjCNFGtfy4rLCwKjvrcwWnyhTWNNihpQ" href="http://10.1.1.0/24" style="background-color: white; color: #1155cc;" target="_blank">10.1.1.0/24</a><span style="background-color: white; color: #222222;"> endpoint </span><a data-saferedirecturl="https://www.google.com/url?q=http://59.13.59.57:51920&source=gmail&ust=1603616434141000&usg=AFQjCNEIpGWztovDQOEb3IlABbRYefWHyw" href="http://59.13.59.57:51920/" style="background-color: white; color: #1155cc;" target="_blank">X.X.X.X:51920</a><span style="background-color: white; color: #222222;"> persistent-keepalive 25</span></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">$ <b>ping 10.1.1.100</b></span></div><div><span style="font-family: Nunito;"><i> => 역시 안된다. 왜 안될까 ? 아직 "Development" 상태라서 그런것 같긴 한데 ... 그래도 이상하다. 안되는 걸 올려 두었을 것 같지는 않은데 .. 😈</i></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="color: #b45f06;"><span style="font-family: Nunito;">네트워크 환경을 Local 망으로 바꾸어 동일한 시험을 해 보았으나, 역시나 동작하지 않았다. 아무래도</span><span style="font-family: Nunito;"> VPP에 포함되어 있는 Wireguard plugin code를 분석해 보아야 겠다.</span></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="background-color: #fcff01; font-family: Nunito;"><b><2024년 들어 3년만에 다시 시도></b></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">아래와 같이 vpp 설정을 다시 진행해 보았더니, 이번엔 정상 동작한다. 😎😎😎 신규 testbed 구성은 다음과 같다. 편의상 반대쪽(wireguard kernel) 설정은 생략하였다.</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">VPP(LAN: 192.168.10.1/24, WAN: <span style="color: #b45f06;">192.168.3.33</span>/24, </span><span style="font-family: Nunito;">vpn ip: <span style="color: #0b5394;">172.16.1.99</span></span><span style="font-family: Nunito;">) </span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><=></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;">wireguard kernel(LAN: 192.168.5.1/24, WAN: <span style="color: #b45f06;">192.168.3.101</span>/24, </span><span style="font-family: Nunito;">vpn ip: <span style="color: #0b5394;">172.16.1.254</span></span><span style="font-family: Nunito;">)</span></div><div><span style="font-family: Nunito;"> </span></div><div><span style="font-family: Nunito;">-----------------------</span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>set interface state TenGigabitEthernet3b/0/0 up <span style="color: #38761d;">#vpp 장비 LAN port up</span></b></div><div>vpp# <b>set interface state TenGigabitEthernet3b/0/2 up <span style="color: #38761d;">#vpp 장비 WAN port up</span></b></div><div><br /></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/0 192.168.10.1/24 <span style="color: #38761d;">#vpp LAN ip 설정</span></b></div><div>vpp# <b>set int ip address TenGigabitEthernet3b/0/2 192.168.3.33/24 <span style="color: #38761d;">#vpp WAN ip 설정</span> </b></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div>vpp# <b>wireguard create listen-port 59760 src 192.168.3.33 <span style="color: #38761d;">#wireguard interface 생성(keypair 생성 포함)</span></b></div><div>wg0</div><div>vpp# <b>show wireguard interface</b> </div><div>[0] wg0 src:192.168.3.33 port:59760 private-key:EAAAADAAAAAg72qwxn8AAAoAAAAAAAAAwPzoB8d/AAA= 100000003000000020ef6ab0c67f00000a00000000000000c0fce807c77f0000 public-key:Fp57l81Z2RCToioDipRIN54/a+bVeD4Lpc1CDdDyJBo= 169e7b97cd59d91093a22a038a9448379e3f6be6d5783e0ba5cd420dd0f2241a mac-key: 72d149c21d7b81ba57fb201daded7c62775c107a4192a4fc49d1c131ed87bece</div><div><br /></div><div><div>vpp# <b>set interface state wg0 up <span style="color: #38761d;">#wg0 interface up</span></b></div><div>vpp# <b>set int ip address wg0 172.16.1.99/24 </b><b><span style="color: #38761d;">#wg0 interface ip 설정</span></b></div><div>vpp# <b>show int addr</b></div><div>TenGigabitEthernet3b/0/0 (up):</div><div>TenGigabitEthernet3b/0/1 (dn):</div><div>TenGigabitEthernet3b/0/2 (up):</div><div><span style="color: #ffa400;"> L3 192.168.3.33/24</span></div><div>TenGigabitEthernet3b/0/3 (dn):</div><div>local0 (dn):</div><div>wg0 (up):</div><div><span style="color: #ffa400;"> L3 172.16.1.99/24</span></div></div><div><br /></div><div>vpp# <b>wireguard peer add wg0 public-key</b> <b>EgJxYfRtnM1iYO4W223wstMy/45iMCRGf/b4qSryzT0= endpoint 192.168.3.101 allowed-ip 0.0.0.0/0 allowed-ip 172.16.1.254/32 dst-port 59760 persistent-keepalive 25 <span style="color: #38761d;">#wireguard peer 설정</span></b></div><div><br /></div><div>vpp# <b>set interface mtu packet 1420 wg0 <span style="color: #38761d;">#wireguard mtu 설정</span> </b></div><div> </div><div>vpp# <b>ip route add 0.0.0.0/0 via 172.16.1.99 wg0 <span style="color: #38761d;">#wg0를 이용하는 routing entry 설정</span></b></div><div><br /></div><div><div>vpp# <b>ping 8.8.8.8 </b> </div><div><span style="color: #ffa400;">참고) vpp에서 kernel wireguard 장비를 통해 internet(8.8.8.8)으로 ping 시도</span></div><div>116 bytes from 8.8.8.8: icmp_seq=1 ttl=56 time=36.5289 ms</div><div>116 bytes from 8.8.8.8: icmp_seq=2 ttl=56 time=36.1525 ms</div></div><div><br /></div><div>$ <b>sudo tcpdump -i eth2 port 59760 </b> <b><span style="color: #38761d;">#kernel wireguard 장비에서 wireguard packet capture</span></b></div><div><div>19:19:27.564590 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:19:27.600483 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:19:28.564570 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:19:28.600506 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div></div><div>...</div><div><br /></div><div>vpp# <b>ip route del 0.0.0.0/0 via 172.16.1.99 wg0 </b></div><div>vpp# <b>ip route add 192.168.5.0/24 via 172.16.1.99 wg0 </b></div><div><br /></div><div><div>vpp# <b>ping 192.168.5.1</b></div><div><span style="color: #ffa400;">참고) vpp에서 kernel wireguard 장비 LAN ip로 ping 시도</span></div><div>116 bytes from 192.168.5.1: icmp_seq=1 ttl=64 time=.3942 ms</div><div>116 bytes from 192.168.5.1: icmp_seq=2 ttl=64 time=.3891 ms</div></div><div><br /></div><div>$ <b>sudo tcpdump -i eth2 port 59760 </b> <b><span style="color: #38761d;">#kernel wireguard 장비에서 wireguard packet capture</span></b></div><div><div>19:21:27.238980 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:28.238698 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:28.238996 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:29.238651 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:29.238940 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div><div>19:21:30.238610 IP 192.168.3.33.59760 > 192.168.3.101.59760: UDP, length 128</div><div>19:21:30.238815 IP 192.168.3.101.59760 > 192.168.3.33.59760: UDP, length 128</div></div><div><br /></div><div>정상적으로 tunneling이 되고 있음을 알 수 있다. 😍</div><div><br /></div><div><b><span style="color: #38761d;"><wireguard kernel 장비의 wireguard wg0 설정 상태></span></b></div><div><div>$ sudo wg show wg0</div><div>interface: wg0</div><div> public key: EgJxYfRtnM1iYO4W223wstMy/45iMCRGf/b4qSryzT0=</div><div> private key: (hidden)</div><div> listening port: 59760</div><div><br /></div><div>peer: 5lHQb8X5i7pzAevP192fbZBBgEqwaCTZboACsdAbE2s=</div><div> endpoint: 192.168.3.33:59760</div><div> allowed ips: 172.16.1.99/32, 192.168.10.0/24</div><div> latest handshake: 31 seconds ago</div><div> transfer: 98.46 KiB received, 321.60 KiB sent</div><div> persistent keepalive: every 10 seconds</div></div><div><br /></div><div><span style="color: #cc0000;">주의) 근데, 뭐가 잘 못 되었을까 ? 정작 vpn ip 간에는 ping이 안된다. 즉, ping 172.16.1.254(from 172.16.1.99) 혹은 ping 172.16.1.99(from 172.16.1.254)이 안된다.</span></div><div><br /></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><div style="font-family: "Noto Sans CJK KR";"><span style="font-family: Acme;"><b><span style="color: #3d85c6; font-size: x-large;">5. VPP 관련 그 밖의 관심있는 주제</span></b></span></div><div>VPP는 아래 site에서 볼 수 있듯이 많은 feature를 가지고 있다.</div><div><br /></div><div style="text-align: center;"><a href="https://fd.io/vppproject/vppfeatures/">https://fd.io/vppproject/vppfeatures/</a></div><div style="text-align: center;"><br /></div><div>그 중에서 특별히 좀더 테스트해보고 싶은 내용을 열거해 보면 다음과 같다. 앞으로 시간을 두고 하나씩 확인해 보아야 겠다. 😜</div><div><ul style="text-align: left;"><li><span style="color: #b45f06; font-family: Nunito;"><div><i>L2 bridge (full 기능)</i></div></span></li><li><span style="color: #b45f06; font-family: Nunito;"><div><i>VxLAN</i></div></span></li><li><span style="color: #b45f06; font-family: Nunito;"><div><i>QoS</i></div></span></li><li><span style="color: #b45f06; font-family: Nunito;"><div><div><i>ACL</i></div></div></span></li><li><span style="color: #b45f06; font-family: Nunito;"><div><div><i>NAT44, NAT46, DS-LITE...</i></div></div></span></li><li><span style="font-family: Nunito;"><div><i>Load Balancer</i></div></span></li><li><i>IPSec</i></li><li><span style="font-family: Nunito;"><div><i>MPLS 등..</i></div></span></li></ul></div></span></div><div><span style="font-family: Nunito;"><div><br /></div><div><b><span style="color: #bf9000; font-family: Acme; font-size: large;">To be continued...</span></b></div></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Nunito;"><br /></span></div><div><span style="font-family: Acme;"><br /><b><span style="color: #3d85c6; font-size: x-large;">6. References</span></b></span></div><div><span style="font-family: Nunito;">[1] https://fd.io/vppproject/vpptech/</span></div><div><span style="font-family: Nunito;">[2] Cisco Ultra Packet Core - High Performance and Features, Aeneas Dodd and Daniel Walton</span></div><div><span style="font-family: Nunito;">[3] intel DPDK - Data Plane Development Kit, One Convergence Devices Ptv. LTD, Saif</span></div><div><span style="font-family: Nunito;">[4] DPDK Summit - DPDK Architecture And Roadmap Discussion, Kannan Babu Ramia & Deepak Kumar Jain, Intel</span></div><div><span style="font-family: Nunito;">[5] https://www.metaswitch.com/blog/fd.io-takes-over-vpp</span></div><div><span style="font-family: Nunito;">[6] https://mitxpc.com/products/as-5019d-ftn4</span></div><div><span style="font-family: Nunito;">[7] https://github.com/MarvellEmbeddedProcessors/vpp-marvell</span></div><div><span style="font-family: Nunito;">[8] https://blog.apnic.net/2020/04/17/kernel-bypass-networking-with-fd-io-and-vpp/</span></div><div><span style="font-family: Nunito;">[9] https://software.intel.com/content/www/us/en/develop/articles/build-a-fast-network-stack-with-vpp-on-an-intel-architecture-server.html</span></div><div><span style="font-family: Nunito;">[10] https://vpp.flirble.org/master/d4/dc4/md_src_plugins_wireguard__r_e_a_d_m_e.html</span></div><div><span style="font-family: Nunito;">[11] https://ettrends.etri.re.kr/ettrends/152/0905002032/</span></div><div><span style="font-family: Nunito;">[12] https://media.frnog.org/FRnOG_28/FRnOG_28-3.pdf</span></div><div><span style="font-family: Nunito;"><br /></span><div><span style="font-family: Acme;"><br /></span></div><div style="text-align: right;"><b><span style="color: #38761d; font-family: Mukta; font-size: medium;">Slowboot</span></b></div></div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-23142387968954842092020-09-30T21:30:00.015+09:002023-02-15T20:01:24.047+09:00WireGuard VPN 해부<p>이번 시간에는 <a href="https://wireguard.com">WireGuard VPN</a>의 동작 원리(protocol)를 상세히 살펴본 후, <a href="https://macchiatobin.net/">MACCHIATObin 보드</a>와 <a href="https://www.gl-inet.com/products/gl-mt300n-v2/">Gl.iNet MangoBox </a>위에 WireGuard를 올리고, 이 둘간을 연결하는 방법(direct 연결 및 relay server를 경유한 연결)에 관하여 소개해 보고자 한다.</p><div class="separator" style="clear: both; text-align: center;"> <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn0eMI70Xbkc6MlDzvq83msXQ9C5ite5do7_0AGciAUpAWZbmo6CyZexz3yq1RLg6tO5NMvUWEAEreiuiZqb7l8hHpVGOExpD9Zs2BGxKn7ad_56EgnpP8_95Lrikf0_FaRbcdhG1iqzF2/s683/wg_direct.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="437" data-original-width="683" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn0eMI70Xbkc6MlDzvq83msXQ9C5ite5do7_0AGciAUpAWZbmo6CyZexz3yq1RLg6tO5NMvUWEAEreiuiZqb7l8hHpVGOExpD9Zs2BGxKn7ad_56EgnpP8_95Lrikf0_FaRbcdhG1iqzF2/w320-h205/wg_direct.PNG" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi3NujCLUPhyphenhyphenaNw_HiYGblksqEBAyngYltOQ58Xh633ehsZAWrrJ-v5QacI4zoW5QxzTF9XqL3sDWjCMlm_b57pyAlIYez7t9maaFmogVgGwfSub1tl9eLtg-XFgW70Gj9DBcmSDn0tPRQ/s705/wg_relay_testbed1.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="541" data-original-width="705" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi3NujCLUPhyphenhyphenaNw_HiYGblksqEBAyngYltOQ58Xh633ehsZAWrrJ-v5QacI4zoW5QxzTF9XqL3sDWjCMlm_b57pyAlIYez7t9maaFmogVgGwfSub1tl9eLtg-XFgW70Gj9DBcmSDn0tPRQ/s320/wg_relay_testbed1.PNG" width="320" /></a><br /></div></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><br /></div><div class="separator" style="clear: both;">See also my <a href="https://github.com/ChunghanYi/spnhacks/blob/master/wg/WireGuard_Analysis3.pdf">WireGuard Analysis</a> document. 😎</div><div class="separator" style="clear: both;"> </div></div><div><b><span style="font-size: medium;">목차</span></b></div><div><i>1. WireGuard VPN Protocol 해부</i></div><div><i>2. P2P 통신 1: WireGuard VPN으로 Peer간 Direct 연결하기</i></div><div><i>3. P2P 통신 2: WireGuard VPN으로 Relay Server 구성하기</i></div><div><i>4. WireGuard VPN Kernel Code 분석</i></div><div><i>5. WireGuard VPN 활용 예(Use Cases)</i></div><div><i>6. References</i></div><div>_______________________________________________</div><div><br /></div><div><br /></div><div><div><div><b><font color="#3d85c6" size="6">1. WireGuard VPN Protocol 해부</font></b></div></div><div>WireGuard와 관련해서는 이미 지난 blog post를 통해 두차례 소개한 바 있다. 따라서 여기에서는 같은 내용을 반복 설명하기 보다는, 지난번 설명에서 미흡했던 부분을 중심으로 정리해 보고자 한다.</div></div><div><br /></div><div> <a href="https://slowbootkernelhacks.blogspot.com/2020/04/espressobin-wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/04/espressobin-wireguard-vpn.html</a></div><div style="text-align: left;"> <i> => 3 ~ 4장</i></div><div style="text-align: left;"> <a href="https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html">https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html</a></div><div style="text-align: left;"><i> => 4장</i></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 MACCHIATObin board와 Gl.iNet MangoBox에 관해서는 아래 내용을 참고하도록 하자.</span></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_25.html">https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_25.html</a></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_20.html">https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_20.html</a></div><div><br /></div><div><b><span style="color: #38761d; font-size: medium;">1.1) WireGuard Protocol</span></b></div><div>지금부터는 WireGuard protocol의 동작 과정을 message handshaking 과정(key 교환 과정)을 중심으로 상세히 분석해 보도록 하겠다.</div><div><br /></div><div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 WireGuard는 Diffie-Hellman(DH) key 교환 방식을 기초로 하는 <a href="http://www.noiseprotocol.org/">Noise protocol</a>을 기반으로 만들어졌다. 정확한 protocol 명칭은 Noise </span><span style="color: #ff00fe;"><span style="font-size: 14.85px;">IKpsk2 이다.</span></span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 따라서 WireGuard protocol을 정확히 이해하기 위해서는 Noise protocol과 <a href="https://ko.wikipedia.org/wiki/%EB%94%94%ED%94%BC-%ED%97%AC%EB%A8%BC_%ED%82%A4_%EA%B5%90%ED%99%98">Diffie-Hellman</a>의 동작 원리를 어느 정도는 이해하고 있어야 한다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9VsxuPE8wwKAa0MJhRhoBUUpxZnaiDJIXUSEdwKKpLbfzUY_l2ETYmQpIlFruFTUqVj_cqLCTIolH4zJj7Eyd-FWAFD6jXgQCTU68tU_AOcRr7b_fWnz-gYBPIftHbz7UoGnG9Ogqp08h/s1040/ecdh_algo.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="569" data-original-width="1040" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9VsxuPE8wwKAa0MJhRhoBUUpxZnaiDJIXUSEdwKKpLbfzUY_l2ETYmQpIlFruFTUqVj_cqLCTIolH4zJj7Eyd-FWAFD6jXgQCTU68tU_AOcRr7b_fWnz-gYBPIftHbz7UoGnG9Ogqp08h/w400-h219/ecdh_algo.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="background-color: white;">[그림 1.1] ECDH 개요</span></div></div><div><br /></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/spnhacks/blob/master/misc/Crypto_Algorithms2.pdf">https://github.com/ChunghanYi/spnhacks/blob/master/misc/Crypto_Algorithms2.pdf</a></div><div><br /></div><div>위 그림이 이해가 되는 분들은 다음으로 넘어가도 좋다. 😋</div><div><br /></div><div><br /></div><div><span style="background-color: white;"><div style="font-size: 14.85px;"><b style="font-size: 14.85px;"><용어 정리></b></div><div style="font-size: 14.85px;"><b style="font-size: 14.85px;"><div style="font-size: medium; font-weight: 400;"><span style="font-size: 14.85px;">__________________________________</span><span style="font-size: 14.85px;">__________________________________</span></div><div><span style="font-size: 14.85px;"><span style="font-size: 14.85px;"><br /></span></span></div></b></div><div style="font-size: 14.85px;"><b><span style="color: #674ea7;">Initiator</span></b> : Key 교환을 위해 handshaking을 시작하는 측</div><div style="font-size: 14.85px;"><b><span style="color: #674ea7;">Responder </span></b>: Initiator로 부터의 요청을 받아 처리하는 측</div><div style="font-size: 14.85px;"><span style="color: #990000;"> <i>=> Initiator와 Responder는 사전에 정해진 것이 아니며, 상황에 따라 Initiator도 Responder도 될 수 있음.</i></span></div><div style="font-size: 14.85px;"><br /></div><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Si_pub</span></b> : Initiator의 static(고정) public key(32 bytes). 즉, 사전(before handshake)에 미리 만들어둔 Initiator 측의 public key</div><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Si_priv</span></b> : Initator의 <span style="font-size: 14.85px;">static(고정) private key(</span><span style="font-size: 14.85px;">32 bytes)</span><span style="font-size: 14.85px;">. </span><span style="font-size: 14.85px;">즉, 사전에 미리 만들어둔 Initiator 측의 private key</span></div><div style="font-size: 14.85px;"><span style="font-size: 14.85px;"><span style="font-size: medium;"><span style="font-size: 14.85px;"><b><span style="color: #bf9000;">Ei_pub</span></b> : <span style="font-size: 14.85px;">Initator</span>의 </span><span style="background-color: transparent; font-size: 14.85px;">ephemeral(임시) public key</span><span style="font-size: 14.85px;">(32 bytes)</span></span></span></div><div style="font-size: 14.85px;"><span style="font-size: 14.85px;"><span style="font-size: medium;"><span style="background-color: transparent; font-size: 14.85px;"><b><span style="color: #bf9000;">Ei_priv</span></b> : </span><span style="font-size: 14.85px;"><span style="font-size: 14.85px;">Initator</span>의 </span><span style="background-color: transparent; font-size: 14.85px;">ephemeral(임시) private key</span><span style="font-size: 14.85px;">(32 bytes)</span></span></span></div></span><span style="background-color: white;"><div style="font-size: 14.85px;"><span style="font-size: 14.85px;"><br /></span></div><div style="font-size: 14.85px;"><span style="font-size: 14.85px;"><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Sr_pub</span></b> : <span style="font-size: 14.85px;">Responder</span>의 static(고정) public key(32 bytes). 즉, 사전에 미리 만들어둔 <span style="font-size: 14.85px;">Responder</span> 측의 public key</div><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Sr_priv</span></b> : <span style="font-size: 14.85px;">Responder</span>의 <span style="font-size: 14.85px;">static(고정) private key(</span><span style="font-size: 14.85px;">32 bytes)</span><span style="font-size: 14.85px;">. </span><span style="font-size: 14.85px;">즉, 사전에 미리 만들어둔 </span><span style="font-size: 14.85px;">Responder</span><span style="font-size: 14.85px;"> 측의 private key</span></div></span></div><div><span style="font-size: 14.85px;"><b><span style="color: #bf9000;">Er_pub</span></b> : Responder의 </span><span style="background-color: transparent; font-size: 14.85px;">ephemeral(임시) public key</span><span style="font-size: 14.85px;">(32 bytes)</span></div></span><span style="background-color: white;"><div><span style="background-color: transparent; font-size: 14.85px;"><b><span style="color: #bf9000;">Er_priv</span></b> : </span><span style="font-size: 14.85px;">Responder의 </span><span style="background-color: transparent; font-size: 14.85px;">ephemeral(임시) private key</span><span style="font-size: 14.85px;">(32 bytes)</span></div></span><span style="background-color: white;"><div style="font-size: 14.85px;"><br /></div><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Q</span></b> : 32 byte preshared 대칭 키(symmetric key)</div><div style="font-size: 14.85px;"><br /></div><div style="font-size: 14.85px;"><b><span style="color: #bf9000;">Ti_send, Ti_recv</span></b> : 실제 패킷 암호화에 사용되는 대칭키(32 bytes), handshaking의 결과로 얻게됨.</div><div style="font-size: 14.85px;"><b style="font-size: 14.85px;"><span style="color: #bf9000;">Tr_send, Tr_recv</span></b><span style="font-size: 14.85px;"> : 실제 패킷 암호화에 사용되는 대칭키(32 bytes)</span><span style="font-size: 14.85px;">, handshaking의 결과로 얻게됨.</span></div><div style="font-size: 14.85px;"><span style="color: #990000; font-size: 14.85px;"><i> => Ti_send = Tr_recv, Ti_recv = Tr_send</i></span></div><div style="font-size: 14.85px;"><br /></div><div><span style="font-size: 14.85px;"><b><span style="color: #38761d;">DH(sk, pk)</span></b> : X25519 공개키 기반의 Diffi-Hellman 함수, sk = private(or secret) key, pk = public key</span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><span style="font-size: 14.85px;"><b><span style="color: #38761d;">aead-enc(key, nonce, plaintext, aad)</span></b> : 암호화 함수, key = 32byte 암호키, nonce = 64bit random 값, plaintext = 암호화할 내용, aad = </span>arbitrary length additional authenticated data</div><div><span style="font-size: 14.85px;"><b><span style="color: #38761d;">aead-dec(key, nonce, ciphertext, aad)</span> </b>: 복호화 함수, ciphertext = 복호화할 내용</span></div><div><span style="color: #990000; font-size: 14.85px;"><i> => 암/복호화 알고리즘 : ChaCha20-Poly1305</i></span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><span style="font-size: 14.85px;"><b><span style="color: #38761d;">Hash(data)</span></b> : BLAKE2s 해쉬 함수, 임의의 길이의 data를 입력으로 받아 32byes 결과 값을 만들어 줌.</span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><span style="font-size: 14.85px;"><b><span style="color: #38761d;">HKDFn(salt, input keying material)</span></b> : n번째 key 값을 생성해주는 함수로, 내부적으로는 HAMC을 위한 hash 함수로 BLAKE2s가 사용됨.</span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><span style="font-size: 14.85px;"><div style="font-size: medium;"><span style="font-size: 14.85px;"><b><Protocol 분석을 위한 참고 사항></b></span></div><div style="font-size: medium;"><span><div style="font-size: 14.85px;"><i><span style="color: #38761d;">- handshake pattern <b>IKpsk2</b></span></i></div><div style="font-size: 14.85px;"><i><span style="color: #38761d;">- DH function <b>X25519</b></span></i></div><div style="font-size: 14.85px;"><i><span style="color: #38761d;">- cipher function <b>ChaCha20-Poly1305</b></span></i></div><div style="font-size: 14.85px;"><i><span style="color: #38761d;">- hash function <b>BLAKE2s</b></span></i></div><div style="font-size: 14.85px;"><i><span style="color: #38761d;">- prologue <b>WireGuard v1 zx2c4 Jason@zx2c4.com</b> (34 bytes)</span></i></div></span></div></span></div><div><span style="font-size: 14.85px;">__________________________________</span><span style="font-size: 14.85px;">__________________________________</span></div><div><span style="font-size: 14.85px;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKKAiilwrRYQwZIyZ4TswD7e8i1tNEXO7LxaCosD6IyiC8-fT_Ce2sLB4S4Y_nQJEacpnxHAj-oMjnUn439gJTkamZFywNaHeU96p-5q05YVlDacr2c-R69j32XCu81f6NTgqQgRRtAEG-/s317/wg_ikpsk2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="165" data-original-width="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKKAiilwrRYQwZIyZ4TswD7e8i1tNEXO7LxaCosD6IyiC8-fT_Ce2sLB4S4Y_nQJEacpnxHAj-oMjnUn439gJTkamZFywNaHeU96p-5q05YVlDacr2c-R69j32XCu81f6NTgqQgRRtAEG-/s0/wg_ikpsk2.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] IKpsk2 절차 요약 <b>[출처 - 참고문헌 3]</b></div><span style="font-size: 14.85px;"><br /></span></div><div style="font-size: 14.85px;"><br /></div></span></div></div><div><b><span style="color: #990000;">0)</span></b> <b><- s : <span style="color: #38761d;">a pre-message 단계</span></b></div><div><i> <span style="color: #ff00fe;">=> 이 단계는 key 교환을 시작하기 위한 사전 준비 단계로 offline 상에서 진행된다.</span></i></div><div><br /></div><div><div>시작에 앞서 아래 정보(Noise protocol name 및 prologue 값)를 이용하여 h0, h1(32-byte handshake hash) 및 ck0(32-byte chaining key) 등을 미리 준비해 둔다.</div><div><br /></div><div><div><span style="color: #3d85c6;">h0 = Hash("<b>Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s</b>")</span></div><div><span style="color: #3d85c6;">ck0 = h0</span></div><div><span style="color: #3d85c6;">h1 = Hash(h0 ||"<b>WireGuard v1 zx2c4 Jason@zx2c4.com</b>")</span></div></div></div><div><span style="color: #3d85c6;"><br /></span></div><div>각각의 peer(Initiator와 Responder)는 Curve25519 공개키 알고리즘을 이용하여 private/public key(이를 static key라고 칭함)를 생성 후, 자신의 public key(Si_pub, Sr_pub)를 상대방에게 전달(out-of-band 즉 offline 상태에서 전달)한다. 이후 각각의 peer는 Si_pub or Sr_pub로 부터 hash 값을 구한다.</div><div><br /></div><div><span style="color: #0b5394;">h2 = Hash(h1 ||Sr_pub )</span></div><div><span style="background-color: white; font-size: 14.85px;"><div><br /></div></span></div><div><b><span style="color: #990000;">1)</span></b> <b>-> e, es, s, ss : <span style="color: #38761d;">Handshake Initiation 단계</span></b></div><div><i><span style="color: #ff00fe;"> => 이 단계는 Initiator가 Reponder에게 message를 보내고, 각각 그에 맞는 action을 취하는 단계에 해당한다.</span></i></div><div><br /></div><div>먼저 Initiator는 ephemeral key pair(Curve25519 기반 임시 private/public key 쌍)를 생성한 후, 임시 공개키(Ei_pub)를 Responder에게 전달한다. 이후 Initiator는 h2와 Ei_pub를 이용하여 h3(Hash 값)를 계산하고, HDKF 함수를 통해 ck0와 Ei_pub로 부터 ck1(32-byte chaining key)을 생성(유도: derivation)해 낸다.</div><div><br /></div><div><div><span style="color: #0b5394;">I: (Ei_priv , Ei_pub) = DHGen; publish Ei_pub</span></div><div><span style="color: #0b5394;">R: Read Ei_pub</span></div><div><span style="color: #0b5394;">h3 = Hash(h2 || Ei_pub)</span></div></div><div><span style="color: #0b5394;">ck1 = HKDF1 (ck0 , Ei_pub)</span></div><div><br /></div><div>Initiator는 Ei_priv(자신의 임시 private key), Sr_pub(Responder의 고정 public key)를 가지고 DH(Diffie-Hellman) 함수를 돌려 symmetric key(대칭키)를 얻어낸다. Responder 역시 Sr_priv, Ei_pub(자신의 고정 private key와 Initiator의 임시 public key)를 가지고 DH 함수를 돌려 symmetric key(대칭키) 값을 구한다. 이후 HKDF 함수를 통해 ck2(32-byte chaining key)와 k0(32-byte handshake cipher key)를 재 계산해 낸다.</div><div><i><span style="color: #ff00fe;"> ==> 1차 DH( ) 함수 실행</span></i></div><div><span style="color: #0b5394;">I: (ck2 , k0 ) = HKDF2 (ck1 , <b>DH(Ei_priv, Sr_pub)</b>)</span></div><div><div><span style="color: #0b5394;">R: (ck2 , k0 ) = HKDF2 (ck1 , <b>DH(Sr_priv , Ei_pub)</b>)</span></div></div><div><br /></div><div><span style="color: #666666;">(1차 암호화에 사용할 대칭키가 준비되었으므로)</span> Initiator는 자신의 고정 public key(Si_pub)를 암호화(k0 대칭키 사용)한 후, Responder로 보낸다. 만일 Responder가 이를 복호화한 후 자신이 보유하고 있는 Si_pub(offline으로 사전에 전달 받은 공개키)와 비교해 일치하지 않는다면, handshaking 과정은 중단된다(<span style="color: #6aa84f;">일종의 인증 과정으로 볼 수 있음</span>).</div><div><br /></div><div><div><span style="color: #0b5394;">I: enc-id = aead-enc(k0 , 0, Si_pub , h3); publish enc-id</span></div><div><span style="color: #0b5394;">R: Si_pub = aead-dec(k0 , 0, enc-id, h3); abort on failure</span></div><div><span style="color: #0b5394;">h4 = Hash(h3 || enc-id)</span></div></div><div><br /></div><div>이후 Initiator는 자신의 고정 private key(Si_priv)와 Responder의 고정 public key(Sr_pub)를 가지고 DH 함수를 돌려 symmetric key 값을 계산한다. Responder 역시 자신의 고정 private key(Sr_priv)와 Initiator의 고정 public key(Si_pub) 값을 가지고 DH 함수를 돌려 동일한 symmetric key 값을 구한다. 이후 각각 HDKF 함수를 통해 ck3와 k1(암호화에 사용할 symmetric key)를 생성해 낸다.</div><div><i><span style="color: #ff00fe;"> ==> 2차 DH( ) 함수 실행</span></i></div><div><div><span style="color: #0b5394;">I: (ck3 , k1) = HKDF2 (ck2 , <b>DH(Si_priv , Sr_pub)</b>)</span></div><div><span style="color: #0b5394;">R: (ck3 , k1) = HKDF2 (ck2 , <b>DH(Sr_priv , Si_pub)</b>)</span></div></div><div><br /></div><div><span style="color: #666666;">(이번 단계의 마지막 절차로)</span> Initiator는 시간 값을 암호화해서 보내고 Responder는 이를 복호화한다. 만일 실패한다면 handshake 과정은 역시 중단된다.</div><div><br /></div><div><div><span style="color: #0b5394;">I: enc-time = aead-enc(k1 , 0, time, h4 ); publish enc-time</span></div><div><span style="color: #0b5394;">R: time = aead-dec(k1 , 0, enc-time, h4 ); abort on failure</span></div><div><span style="color: #0b5394;">h5 = Hash(h4 || enc-time)</span></div></div><div><br /></div><div><b><span style="color: #990000;">2)</span></b> <b><- e, ee, se, psk : <span style="color: #38761d;">Handshake Response 단계</span></b></div><div><i><span style="color: #ff00fe;"> => 이 단계는 Responder가 Initiator에게 message를 보내고, 각각 그에 맞는 action을 취하는 단계에 해당한다.</span></i></div><div><br /></div><div><span style="color: #666666;">(반대로)</span> Responder는 Curve25519 공개키 암호 알고리즘을 이용해 임시 암호 key 쌍(ephemeral key pair)을 만들어 낸 후, 공개키(Er_pub)를 Initiator에게 보낸다. 그후 Responder는 hash 값(h6)과 HKDF 함수를 통해 ck4 값을 계산해 낸다.</div><div><br /></div><div><div><span style="color: #0b5394;">R: (Er_priv , Er_pub ) = DHGen; publish Er_pub</span></div><div><span style="color: #0b5394;">I: Read Er_pub</span></div><div><span style="color: #0b5394;">h6 = Hash(h5 || Er_pub)</span></div><div><span style="color: #0b5394;">ck4 = HKDF1(ck3 , Er_pub)</span></div></div><div><br /></div><div>그 다음 Reposnder는 자신의 임시 private key(Er_priv)와 (b) 단계에서 받아둔 상대방의 임시 public key(Ei_pub)에 대해 DH 함수를 이용해 symmetric key를 계산해 낸다. Initiator도 동일한 방식, 즉 DH(Ei_priv, Er_pub)를 통해 symmetric key를 계산해 낸다.</div><div><i><span style="color: #ff00fe;"> ==> 3차 DH( ) 함수 실행</span></i></div><div><div><span style="color: #0b5394;">R: ck5 = HKDF1 (ck4 , <b>DH(Er_priv , Ei_pub)</b>)</span></div><div><span style="color: #0b5394;">I: ck5 = HKDF1 (ck4 , <b>DH(Ei_priv , Er_pub)</b>)</span></div></div><div><br /></div><div>Responder는 자신의 임시 private key(Er_priv)와 Initiator의 고정 public key(Si_pub)를 가지고 DH 함수를 돌려 symmetric key를 만들어 낸다. 마찬가지로 Initiator도 자신의 고정 private key(Si_priv)와 Responder의 임시 public key(Er_pub)를 가지고 동일한 symmetric key를 생생해 낸다.</div><div><i><span style="color: #ff00fe;"> ==> 4차 DH( ) 함수 실행</span></i></div><div><div><span style="color: #0b5394;">R: ck6 = HKDF1 (ck5 , <b>DH(Er_priv , Si_pub)</b>)</span></div><div><span style="color: #0b5394;">I: ck6 = HKDF1 (ck5 , <b>DH(Si_priv , Er_pub)</b>)</span></div></div><div><br /></div><div>만일 preshared key(Q)를 사전(사전 준비 단계, 즉 offline 단계)에 준비해 두었다면, 이를 이용(mix)해 HKDF 함수를 돌려 새로운 key 값을 유도해 낸다. <span style="color: #e06666;"><b>참고로, 이 preshared key(Q)를 사용하게 되면, PQC(Post Quantum Cryptography) 알고리즘을 사용하지 않고도, Quantum attack을 일정부분 막아낼 수 있다. 물론 post-quantum attack을 방지하기 위한 근본적인 해결책은 PQC 알고리즘을 적용하는 것이긴 하지만 말이다.</b></span></div><div><br /></div><div><div><span style="color: #0b5394;">(ck7 , τ, k2 ) = HKDF3 (ck6 , Q)</span></div><div><span style="color: #0b5394;">h7 = Hash(h6 || τ )</span></div></div><div><br /></div><div><span style="color: #666666;">(이번 단계의 마지막 과정으로)</span> Responder는 빈(empty) payload를 암호화(k2 키값 사용)해서 Initiator에게 보내고, Initiator는 이를 복호화하여 빈 payload인지를 확인한다. 만일 복호화에 실패(빈 payload가 아니라면)한다면 지금까지의 handshake 과정은 여기서 중단되게 된다.</div><div><br /></div><div><div><span style="color: #0b5394;">R: enc-empty = aead-enc(k2 , 0, empty, h7); publish enc-empty</span></div><div><span style="color: #0b5394;">I: empty = aead-dec(k2 , 0, enc-empty, h7); abort on failure</span></div><div><span style="color: #0b5394;">h8 = Hash(h7 || enc-empty)</span></div></div><div><br /></div><div><b><span style="color: #990000;">3) </span><span style="color: #38761d;">Handshaking 완료 단계</span></b></div><div>끝으로, 지금까지의 과정을 통해 얻는 ck7(chaining key) 값과 e(empty string)에 대해 HKDF 함수를 통해 한번 더 hashing해 줌으로써, 최종 송신 및 수신용 암호키(Ti_send, Ti_recv)를 얻게 된다. 이후 지금까지 임시로 만들어 사용했던 ephemeral key 등은 모두 삭제된다.</div><div><br /></div><div><div><span style="color: #0b5394;">I: (Ti_ send , Ti_recv ) = HKDF 2 (ck7 , e)</span></div><div><span style="color: #0b5394;">R: (Tr_recv , Tr_send ) = HKDF 2 (ck7 , e )</span></div></div><div><span style="color: #0b5394;"><br /></span></div><div>이후 이 두개의 암호 키 쌍 (Ti_send, Ti_recv), (Tr_recv, Tr_send)를 사용하여 실제 data에 대한 암호화 및 복호화를 수행한다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; text-align: left;">📌 위의 내용을 요약해 보면, WireGuard 키교환 protocol은 두개의 Curve25519 공개키 쌍(Static, Ephemeral)을 생성한 후, 이를 이용해 DH 함수를 4번 호출(E/S, S/S, E/E, E/S)하는 과정을 통해 실제 암호화에 사용할 대칭키를 생성하는 것임을 알 수 있다. 물론 이 과정에서 중간에 생성된 <u>대칭키로 암/복호화는 과정을 통해 상호 인증</u>을 하고 있으며, 중간 중간에 생성한 암호키에 대해 여러 차례의 Hash 함수를 거치도록 함으로써 암호키의 복잡도(역으로 유추하기 어렵게 만듦)를 높이고 있음도 알 수 있다.</span></div><div class="separator" style="clear: both; text-align: justify;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT_ErsY9yZ1pZh33TXOIu3lf1BHvpD9PDrKt2Gwq641KOWmI8fxnLcyxIjzSAf859jul8wOFzuUDzmVwoaLsemw2PabVNz_GH7c3NISexk34yHqLXi68ftuevo3nVim3iZQcPfM8X4c0En/s831/noise_session_key_gen.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="224" data-original-width="831" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT_ErsY9yZ1pZh33TXOIu3lf1BHvpD9PDrKt2Gwq641KOWmI8fxnLcyxIjzSAf859jul8wOFzuUDzmVwoaLsemw2PabVNz_GH7c3NISexk34yHqLXi68ftuevo3nVim3iZQcPfM8X4c0En/w400-h108/noise_session_key_gen.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #ff00fe;"><span style="background-color: white; font-size: 14.85px; text-align: left;">📌</span><span style="background-color: white; font-size: 14.85px; text-align: left;"> </span><span style="background-color: white; font-size: 14.85px; text-align: left;">최종적으로 생성되는 </span><span style="text-align: left;">암호 키 쌍 (Ti_send, Ti_recv), (Tr_recv, Tr_send)은 새로운 handshaking 마다 새롭게 생성되므로, perfect forward secrecy를 보장한다고 말할 수 있다.</span></span></div></div><div class="separator" style="clear: both; text-align: left;">________________________________________</div><div class="separator" style="clear: both; text-align: center;"><br /></div>지금까지 설명한<span style="color: #666666;"> (조금은 복잡하고 난해한) </span>handshaking 과정을 하나의 그림으로 표현해 보면 다음과 같다. 앞서 설명한 바와 같이 내부적으로는 아주 복잡한 과정을 거치지만, 겉으로 보기에는 <span style="color: #666666;">(마치 TCP 3-way handshaking 처럼)</span> <b>3번의 handshaking 과정(1.5 RTT handshake)만에 암호화에 사용할 대칭 key 교환이 안전</b>하게 이루어 짐을 알 수 있다.<div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2TarEgfLoigqmkcIOSpyvP5H2vcxHBCP05fPzjXGIjx1ee4VV-EZvm52c1b100ewpKr258x_gaMvOk8YXBHtU4J6Z-OV9cD3VrWQD97DdMHJWCPw2u_yzYxAJwred7CkMtKeQ6oHm4tak/s732/wg_handshake.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="266" data-original-width="732" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2TarEgfLoigqmkcIOSpyvP5H2vcxHBCP05fPzjXGIjx1ee4VV-EZvm52c1b100ewpKr258x_gaMvOk8YXBHtU4J6Z-OV9cD3VrWQD97DdMHJWCPw2u_yzYxAJwred7CkMtKeQ6oHm4tak/w640-h232/wg_handshake.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.3] 정상 상태에서의 WireGuard Handshake 절차 <b>[출처 - 참고문헌 3]</b></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌</span><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"> </span><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">IKEv2, SSL/TLS의 key 교환과 비교할 때, WireGuard(Noise 변형)의 key 교환 방식은 (인증서 등을 동원하지는 않았지만) 안정성 면에서 손색이 없다고 판단된다.</span></div><div><br /></div><div>한편, 아래 그림은 정상적인 Handshaking 과정이 아니라, Initiator or Responder가 부하가 걸려 있을 경우(under load 상태 즉, 처리할 패킷이 많아 큐에 쌓여 있는 상태), Cookie를 생성하여 해당 Cookie를 처리하는 경우에 대해서만 handshaking을 이어나가도록 하는 내용(나머지 패킷은 drop)을 보여주고 있다. 아래 그림 중 왼쪽은 Reponder가 under load 상태인 경우이고, 오른쪽은 Initiator가 under load 상태인 경우를 보여준다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5mISo9sZIIjEFCyo2zendECJXYDsPhr0JROLWa_dOlrgd6e4G-n3UzMvjcJCwUJjTszLkoPL2F2ut5lYgr97mBF12bHZ6CCDgBjDpXbfB83nXYZwxz_G6U5COJL6RsQXr8Swmi8zPxemp/s744/wg_cookie_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="466" data-original-width="744" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5mISo9sZIIjEFCyo2zendECJXYDsPhr0JROLWa_dOlrgd6e4G-n3UzMvjcJCwUJjTszLkoPL2F2ut5lYgr97mBF12bHZ6CCDgBjDpXbfB83nXYZwxz_G6U5COJL6RsQXr8Swmi8zPxemp/w640-h400/wg_cookie_flow.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.4] 부하 발생시 WireGuard Handshake 절차 <b>[출처 - 참고문헌 3]</b></div><div><b style="text-align: center;"><br /></b></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌 Cookie Reply 메시지가 발생하는 경우는 under load 상황(예: DoS attack 상황)으로 (linux kernel 상에 구현된 wireguard의 경우) 대략 512개의 handshake packet이 queue에 쌓여 있을 경우를 under load 상황으로 인지한다.</span></b></div><div><span style="font-size: 14.85px; text-align: center;"><span style="background-color: white; color: #ff00fe; text-align: left;"><div style="text-align: center;">under_load = skb_queue_len(&wg->incoming_handshakes) >=</div><div style="text-align: center;"> MAX_QUEUED_INCOMING_HANDSHAKES / 8;</div></span></span></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><b style="text-align: center;"><br /></b></div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d; font-size: medium;">1.2) WireGuard Protocol Message Format</span></b></b></div><div><span style="text-align: center;">앞 절에서는 </span><span style="text-align: center;">handshake 과정(or </span><span style="text-align: center;">Key 교환 과정)을 암호 알고리즘 중심으로 살펴 보았으니, 이번에는 패킷 중심으로 분석해 보도록 하자.</span></div><div><span style="text-align: center;"><br /></span></div><div style="text-align: left;">WireGuard handshake message type은 아래와 같이 총 4가지가 있다(아주 간결하다).</div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_yfrG73egUf7n_txhHirYj_gvuOSFfGVgevD-ijSvyRsD1tNMIhJusLp8m6lszHdM0tJASgJQFWmzkKNuM9Ms0ROMA8U7BfupY2FOuWrQBCi3lGHst0me5FJhQ2QOhaLTYEIO3t9UzFcY/s435/wg_message_types.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="173" data-original-width="435" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_yfrG73egUf7n_txhHirYj_gvuOSFfGVgevD-ijSvyRsD1tNMIhJusLp8m6lszHdM0tJASgJQFWmzkKNuM9Ms0ROMA8U7BfupY2FOuWrQBCi3lGHst0me5FJhQ2QOhaLTYEIO3t9UzFcY/s320/wg_message_types.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.5] WireGuard handshake message type<b>[출처 - 참고문헌 3]</b></div></div><div><span style="color: #ff00fe;"><span style="font-size: 14.85px;"><br /></span></span><span style="text-align: center;">이중 첫번째 messge type(1)인 <b><span style="color: #b45f06;">Handshake Initiation</span></b> message의 format은 다음과 같다.</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXPYLnclTMnESLBRt56vwVV7XXDIwZdIu8byspfbZjmzV2ELUd6GB7y2Mz17Mw-DJ-VfpldjmonWn5MPbYK-P0mMBr53M6bSPQVRhDRS8W2qttocMlqE8ayT08PRxXySflbSux7IANc6Ol/s750/wg_initiator_message.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="508" data-original-width="750" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXPYLnclTMnESLBRt56vwVV7XXDIwZdIu8byspfbZjmzV2ELUd6GB7y2Mz17Mw-DJ-VfpldjmonWn5MPbYK-P0mMBr53M6bSPQVRhDRS8W2qttocMlqE8ayT08PRxXySflbSux7IANc6Ol/w400-h271/wg_initiator_message.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.6] Handshake Initiation Message Format(148 bytes) <b>[출처 - 참고문헌 3]</b></div><div class="separator" style="clear: both; text-align: center;"><b><br /></b></div><div class="separator" style="clear: both; text-align: left;"><b><필드의 의미></b></div><div>______________________</div><div><b><span style="color: #6aa84f;">Type</span></b> : 1 = <span style="text-align: center;"><i>Handshake Initiation message</i></span></div><div style="text-align: left;"><b><span style="color: #6aa84f;">Reserved (3 bytes)</span></b> : <i>정의되지 않은 field(나중에 사용할 목적으로 공간만 잡아둠)</i></div><div><b><span style="color: #6aa84f;">Sender Index(4 bytes)</span></b> : <i>random하게 생성된 index(local identifier) 값. 이걸 보내는 이유는 Responder가 응답을 보낼 때 Receiver Index field에 이 값을 넣어 보내기 위함임. Initiator는 이 index 값을 사용하여 자신의 hash table을 lookup하게 됨.</i></div><div><span style="color: #6aa84f;"><b>Initiator ephemeral public key(32 byes)</b> </span>: <i>initiator가 생성한 임시 public key</i></div><div><b><span style="color: #6aa84f;">Encrypted initiator static public key(48 bytes)</span></b> : <i>initiator가 생성한 고정 public key. 암호화하여 48 bytes(= 암호화된 32 bytes + 16 bytes authentication tag)가 됨.</i></div><div><span style="color: #6aa84f;"><b>Encrypted timestamp(28 bytes)</b> </span>: <i>암호화된 timestamp(28 = 12(96 bits) + 16 bytes authentication tag)</i></div><div><b><span style="color: #6aa84f;">MAC1(16 bytes)</span> </b>: <i>Responder의 고정 public key를 hash 처리하여 여기에 실어서 보냄. Responder는 자신의 public key로 부터 동일한 hash 값을 계산하여 비교하게 됨. <u><span style="color: #e06666;">일종의 인증용</span></u>으로 볼 수 있을 듯.</i></div><div><b><span style="color: #6aa84f;">MAC2(16 bytes) </span></b>: <i>Cookie Reply 단계에서 받은 cookie(32 bytes)를 복호화한 후, 여기에 실어서 응답함. 평상시(under load 상황이 아닌 경우)에는 MAC2 field는 그냥 무시됨.</i></div><div>______________________</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">두번째 message <span style="text-align: center;">type(2)인 <b><span style="color: #b45f06;">Handshake Response</span></b> message의 format은 다음과 같다.</span> </div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1i7rVcXtbxjNJzlYdH7cmMkZ3rEaEN4j0-2469Ab9LJT5oQqlZ8RpirF_nHfYeF37PoM45_9GQykNBjrt1qzcFysx_Q9tJEGDytb4FNUlmklcTimsgnUU12MSJB_D39JOlSzrnyAIj0_k/s748/wg_reponse_message.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="341" data-original-width="748" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1i7rVcXtbxjNJzlYdH7cmMkZ3rEaEN4j0-2469Ab9LJT5oQqlZ8RpirF_nHfYeF37PoM45_9GQykNBjrt1qzcFysx_Q9tJEGDytb4FNUlmklcTimsgnUU12MSJB_D39JOlSzrnyAIj0_k/w400-h183/wg_reponse_message.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.7] Handshake Response message format(92 bytes) <b>[출처 - 참고문헌 3]</b></div><div><br /></div><div><b><필드의 </b><b>의미</b><b>></b></div><div>______________________</div><div><b><span style="color: #6aa84f;">Type</span></b> : 2 = <span style="text-align: center;"><i>Handshake Response message</i></span></div><div><span style="text-align: center;"><b style="text-align: left;"><span style="color: #6aa84f;">Reserved (3 bytes)</span></b><span style="text-align: left;"> : </span><i style="text-align: left;">정의되지 않은 field(나중에 사용할 목적으로 공간만 잡아둠)</i></span></div><div><span style="text-align: center;"><b><span style="color: #6aa84f;">Sender Index(4 bytes)</span></b> : </span><i>random하게 생성된 index(local identifier) 값.</i></div><div><span style="color: #6aa84f;"><b>Receiver Index(4 bytes)</b> </span>: <i>Initiator로 부터 받은 Sender Index 값을 여기에 적어 돌려 보냄. Message format 어디를 봐도 ip address에 관한 부분은 없음. 즉, wireguard는 endpoint ip 주소가 변경되어도 tunnel이 유지되는데, 그 이유(index & public key 기반)를 여기에서 찾을 수 있겠음.</i></div><div><b><span style="color: #6aa84f;">Responder ephemeral publick key(32 bytes)</span></b> : <i>Responder가 생성한 자신의 임시 public key</i></div><div><i><b><span style="color: #6aa84f;">Encrypted empty(16 bytes) </span></b>: 빈 data를 암호화하여 전달(16 bytes authentication tag만 존재).</i> <i>Initiator는 복호화한 결과가 빈 data가 아니면 handshaking 과정을 중단하게 됨.</i></div><div><div><b><span style="color: #6aa84f;">MAC1(16 bytes)</span> </b>: <i>Initiator의 고정 public key를 hash 처리하여 여기에 저장함. Initiator는 자신의 public key로 부터 동일한 hash 값을 계산하여 비교하게 됨. 일종의 <span style="color: #e06666;"><b><u>인증용</u></b></span>으로 볼 수 있을 듯.</i></div><div><b><span style="color: #6aa84f;">MAC2(16 bytes) </span></b>: <i>Cookie Reply 단계에서 받은 cookie(16 bytes)를 여기에 실어서 응답함.</i></div></div><div>______________________</div><div><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">다음으로 세번째 message </span>type(3)인 <b><span style="color: #b45f06;">Cookie Reply</span></b> message의 format은 다음과 같다.<span style="text-align: left;"> </span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT1x5Ypk-I-qhVeGqsX4uyPbhXIu53JDydSDjC6Je6zdVSAdo9PNmWJS4j8zpwFVQuPjf3aIS6cusH_3l9bNqxvBM-gwFcqAfZVWPpkulLJM7kQHohRJNe44Zzjrf0GmqDVi4xm7cXboz2/s743/wg_cookie_message.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="743" height="130" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT1x5Ypk-I-qhVeGqsX4uyPbhXIu53JDydSDjC6Je6zdVSAdo9PNmWJS4j8zpwFVQuPjf3aIS6cusH_3l9bNqxvBM-gwFcqAfZVWPpkulLJM7kQHohRJNe44Zzjrf0GmqDVi4xm7cXboz2/w400-h130/wg_cookie_message.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.8] Cookie Reply message format(64 bytes) <b>[출처 - 참고문헌 3]</b></div><div><b style="text-align: center;"><br /></b></div><div><b style="text-align: center;"><b style="text-align: left;"><필드의 </b><b style="text-align: left;">의미</b><b style="text-align: left;">></b></b></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;">______________________</span></b></div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #6aa84f;">Type</span></b><span style="font-weight: 400; text-align: left;"> : 3 = </span></b><span style="text-align: justify;"><i>Cookie Reply message</i></span></div><div><span style="text-align: justify;"><b style="text-align: left;"><span style="color: #6aa84f;">Reserved (3 bytes)</span></b><span style="text-align: left;"> : </span><i style="text-align: left;">정의되지 않은 field(나중에 사용할 목적으로 공간만 잡아둠)</i></span></div><div><span style="color: #6aa84f;"><b>Receiver Index(4 bytes)</b> </span>: <i>Initiator or Responder로 부터 받은 Sender Index 값을 여기에 적어 돌려 보냄.</i></div><div><b><span style="color: #6aa84f;">Nonce(24 bytes)</span></b> : <i>아래 cookie를 암호화는 과정에서 사용되는 nonce 값.</i></div><div><b><span style="color: #6aa84f;">Encrypted cookie(32 bytes)</span></b> : <i>cookie는 random number + peer ip 주소/port를 조합한 내용을 BLAKE2s로 hash(16 bytes 결과 생성)한 후, 이를 plaintext 형태로 보내지 않고, 다시 암호화해서 보내게 됨. 32bytes = 16bytes(암호화된 hash 값) + 16 authentication tag(by Polcy1305)</i></div><div><br /></div><div><div><span style="color: #0b5394;"> nonce ∈ R {0, 1} 192</span></div><div><span style="color: #0b5394;"> encrypted-cookie = XChaCha20Poly1305(cookie-key, nonce, cookie, msg)</span></div></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;">______________________</span></b></div><div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><b><span style="font-weight: 400; text-align: left;"><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌 Cookie를 만들기 위해 peer의 source ip 주소가 사용됨.</span></b></span></b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">마지막으로 네번째 message </span><span style="text-align: justify;">type(4)인 <b><span style="color: #b45f06;">Transport Data</span></b> message의 format은 다음과 같다.</span><span style="text-align: left;"> </span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5v9F0m56SnV6DNRaLsLk7XR49j6EszjIcJYpXmz8kmG3mvKz9ed_NZSRshoxhB2mDiY0xR9PgYUnguw1drAhvmMBO3Zact4ljHdw0lXRK2fjvgeiiAT7H8BmhGIsL6yxZGCSHDdH3XnLE/s735/wg_data_message.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="140" data-original-width="735" height="76" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5v9F0m56SnV6DNRaLsLk7XR49j6EszjIcJYpXmz8kmG3mvKz9ed_NZSRshoxhB2mDiY0xR9PgYUnguw1drAhvmMBO3Zact4ljHdw0lXRK2fjvgeiiAT7H8BmhGIsL6yxZGCSHDdH3XnLE/w400-h76/wg_data_message.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.9] Transport Data(실제 암호화된 packet) message format(최소 32 이상) <b>[출처 - 참고문헌 3]</b></div></div><div><b style="text-align: center;"><br /></b></div><div><b style="text-align: center;"><b style="text-align: left;"><필드의 </b><b style="text-align: left;">의미</b><b style="text-align: left;">></b></b></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;">______________________</span></b></div><div><b style="text-align: center;"><b><b style="text-align: left;"><span style="color: #6aa84f;">Type</span></b><span style="font-weight: 400; text-align: left;"> : 4 = </span></b><span style="font-weight: 400; text-align: justify;">Transport Data message</span></b></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: justify;"><b style="text-align: left;"><span style="color: #6aa84f;">Reserved (3 bytes)</span></b><span style="text-align: left;"> : </span><i style="text-align: left;">정의되지 않은 field(나중에 사용할 목적으로 공간만 잡아둠)</i></span></b></div><div><span style="color: #6aa84f;"><b>Receiver Index(4 bytes)</b> </span>: <i>Initiator or Responder로 부터 받은 Sender Index 값을 여기에 적어 돌려 보냄.</i></div><div><b><span style="color: #6aa84f;">Counter (8 bytes) </span></b>:<i> handshake과정이 성공할 경우, Initiator & Responder는 0 부터 시작하는 Nonce 값을 관리하게 됨(이 값은 encryption 과정에서 사용되고, encryption 후에 1씩 증가시킴). 이 Nonce 값을 encoding 후 Counter 필드에 실어서 보냄. 이 Counter 값은 UDP packet이 중복 수신되는 경우를 방지하는 용도 즉, 동일한 Counter 값을 가진 UDP packet이 수신될 경우 drop 시키는 목적(<b><span style="color: #e06666;"><u>replay attck 차단</u></span></b>)으로도 사용됨.</i></div><div><b><span style="color: #6aa84f;">Encrypted packet (>= 16 bytes)</span></b> : <i>실제 ip packet을 암호화하기 위해 16 bytes의 배수인지 체크하여 아닐 경우 padding 처리(0으로 채움)를 한 후, 암호화를 하게 됨. 패킷 암호화 후에는 Poly1305 알고리즘을 이용하여 checksum 16 byte를 생성하여 packet의 맨끝에 추가하게 됨. </i></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;">______________________</span></b></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;"><br /></span></b></div><div><b style="text-align: center;"><span style="font-weight: 400; text-align: left;"><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌위의 그림 1.9와 같이 Wireguard tunnel header는 16 byte로 고정되어 있어, parsing 과정이 필요 없다. 따라서 가변 길이 header를 갖는 protocol에 비해 (parsing 과정이 필요 없으무로) 그만큼 빠른 속도를 내기에 유리하다(또한 h/w 화 하기에도 유리하다).</span></b></span></b></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌Encrypted packet size가 16(empty payload)인 packet은 Keepalive mssage이다.</span></b></div><div><br /></div><div><span style="background-color: #fff2cc;"><b><여기서 잠깐 !></b></span></div><div><span><i> => WireGuard의 MTU 값이 1420인 이유에 대하여...</i></span><br /></div><div><span><br /></span></div><div><b>20 </b>or <b><span style="color: #990000;">40</span></b> bytes : 20 = minimum IPv4 header size, 40 = mininum IPv6 header size</div><div>+</div><div><b><span style="color: #990000;">8</span></b> bytes : UDP header size</div><div>+</div><div><b><span style="color: #990000;">32</span> </b>bytes : WireGuard message header size(그림 1.9 참조)</div><div>= 80</div><div><br /></div><div>따라서 <b>1500 - 80 = 1420</b>이 된다. 만일 IPv4 망만을 사용한다고 가정하면 1440으로 설정해도 되겠다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWT7O6vTNokAImd_fViBtjzGHBOGyDGa4sYpD-4fViR1fboDw46Dy0KrhY-NQ_OH2pw02X4ec_fbz5OvRPee-cTODhbtwMaBWrhjD9Z86tfdF6cnUxeEkqdBn8ksV4jLUIIcawGkrMQ2a1/s373/wg_packet_format.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="373" data-original-width="260" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWT7O6vTNokAImd_fViBtjzGHBOGyDGa4sYpD-4fViR1fboDw46Dy0KrhY-NQ_OH2pw02X4ec_fbz5OvRPee-cTODhbtwMaBWrhjD9Z86tfdF6cnUxeEkqdBn8ksV4jLUIIcawGkrMQ2a1/s320/wg_packet_format.PNG" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.10] WireGuard IP tunnel packet format</div><div>_______________________________</div><div><br /></div><div><div><div><span style="background-color: #fff2cc;"><b><여기서 잠깐 !></b></span></div><div><span><i> <span style="color: #e06666;"><b>=> x.509 인증서를 사용하지 않는 wireguard ~ 그럼 인증 및 ECDSA와 같은 서명 & 검증 기능은 ?</b></span></i></span></div></div><div><br /></div><div>WireGuard는 x.509 인증서를 사용하지 않는다. ECDSA 등을 이용한 서명 & 검증 기능 같은 것도 사용하지 않는다. 그럼 인증을 어떻게 한단 말인가 ? 앞서도 잠시 언급하긴 했지만, 암호화의 과정, 즉 private key로 암호한 내용을 public key로 복호화 가능한지 여부, 혹은 offline으로 전달한 public key에 대한 hash 값(MAC1)을 수신 측에서 다시 계산하여 일치하는지를 확인하는 방법 등을 통해 정당한 peer인지를 확인(인증)하도록 하고 있다.</div><div>물론, 이러한 인증 방식이 x.509 인증서 기반 or ECDSA 서명/검증 방식에 비해서 보안 강도가 좀 낮다고 주장하는 이도 있을 수 있겠으나, 복잡하다고 무조건 좋은 것은 아니며, 간결함과 빠른 속도가 때로는 해법일 수도 있다는 의견을 드리고 싶다.</div><div>Wireguard는 간결하고, 빠른 handshaking 과정 덕분에 2분 간격으로 새로운 handshaking 과정을 수행하게 되고, 그 과정에서 새로운 암호키를 생성하고 있으니, 그야말로 완벽한 PFS(Perfect Forward Secrecy)를 지원한다고 말할 수 있겠다.</div><div>_______________________________</div></div><div><br /></div><div><div><div><span style="background-color: #fff2cc;"><b><여기서 잠깐 !></b></span></div><div><b><span style="color: #3d85c6;"><span><i> <span>=> </span></i></span><i>WireGuard message format을 보면 어디에도 peer의 endpoint(ip & port) 정보가 포함되어 있지 않다. 그렇다면 wireguard는 여러 peer(peer table) 중에서 정확하게 원하는 peer 하나를 어떻게 찾아 낼 수 있을까 ?</i></span></b></div></div><div><i><br /></i></div><div>그 해답은 static public key와 index(sender, receiver) 필드에 있다.</div><div><span style="text-align: center;">[그림 1.6] Handshake Initiation Message Format을 보면, initiator는 첫번째 DH() 결과로 얻은 key 값 즉, ck2를 이용하여 자신의 static public key를 암호화한 후, </span>random하게 생성된 index(local identifier) 값 등과 함께 handshake initiation message를 구성 후, 이를 responder에게 전달한다.<br /></div></div><div>Message를 수신한 responder는 역시 DH()를 이용해 ck2를 얻은 후, initiator가 암호화해서 보내준 static public key를 복호화하게 되고, 이를 이용해 peer(initiator)가 누구인지를 1차적으로 알게 된다. 이후 responder는 initiator로 부터 받은 sender index 값을 receiver index에 넣고, 역시 자신이 random하게 생성한 sender index 값 등으로 Handshake Response Message를 만들어 initiator에게 돌려 보낸다.</div><div>Responder로 부터 handshake response message를 수신한 initiator는 receiver index 필드 값이 자신이 전에 만들어 보낸 index 값인지를 확인하게되고, 이를 통해 peer table에서 원하는 peer를 정확하게 선택할 수 있게 된다.</div><div>따라서, 앞서 설명한 static public key 및 sender/receiver index 값은 initiator 및 responder 각각에서 운용하는 peer table에서 원하는 peer를 lookup하는데 사용하는 값으로 해석될 수 있다.</div><div>_______________________________</div><div><br /></div><div>끝으로 WireGuard protocol의 handshake state machine 관련 그림을 추가하는 것으로 이번 장을 끝마치도록 하겠다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyTw0JMvq3iLwJ80zJKZ-SL8VRbhiBD9ZHiQwGXvPIHc1gquK8Rgbb9rs8B9DWD7hIRMn7VpnPtTOgpH2heAhyphenhyphenj57yhilIsmxQQuLDuH8TsdrFWAvTOHoTm1KZVsbXmIUABh09169Ut644/s576/wg_handshake_state_machine.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="526" data-original-width="576" height="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyTw0JMvq3iLwJ80zJKZ-SL8VRbhiBD9ZHiQwGXvPIHc1gquK8Rgbb9rs8B9DWD7hIRMn7VpnPtTOgpH2heAhyphenhyphenj57yhilIsmxQQuLDuH8TsdrFWAvTOHoTm1KZVsbXmIUABh09169Ut644/w400-h365/wg_handshake_state_machine.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.11] WireGuard handshake state machine <b>[출처 - 참고문헌 3]</b></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#3d85c6" size="6">2. P2P 통신 1: WireGuard VPN으로 Peer간 Direct 연결하기</font></b></div><div>이번 장에서는 아래와 같은 네트워크 환경에서 WireGuard를 이용하여 안전한 1:1 VPN 통신이 이루어지는지를 확인해 보고자 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUmNRFWVOWrxQVF5BP1HXr64moZmBFS5BG1H-PYS19PxaHsZqRYFAypBAN_2SLO3Y5P0VFfuw3emuyhaSbjQtDBWo8rqSHW1Zc99j_4hFTJnwW9uOOZL_Ldb78cH0Td0YBVZlYudPcZ2pg/s682/wg_testbed3.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="682" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUmNRFWVOWrxQVF5BP1HXr64moZmBFS5BG1H-PYS19PxaHsZqRYFAypBAN_2SLO3Y5P0VFfuw3emuyhaSbjQtDBWo8rqSHW1Zc99j_4hFTJnwW9uOOZL_Ldb78cH0Td0YBVZlYudPcZ2pg/w400-h281/wg_testbed3.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] WireGuard를 이용한 direct VPN 구성(1)</div><div><br /></div><div><br /></div><div><div><div class="separator" style="clear: both;"><b style="background-color: #d0e0e3;"><MACCHIATObin board></b></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;">root@localhost:~/workspace# </span><span style="color: #333333;"><span style="font-size: 14.85px;"><b>./wg genkey | tee ./privatekey | ./wg pubkey > ./publickey</b></span></span></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #333333; font-size: 14.85px;">root@localhost:~/workspace# </span><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;"><b>ip link add dev wg0 type wireguard</b></span><br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;" /><span style="background-color: white; font-family: inherit; font-size: 14.85px;"><span style="color: #333333;">root@localhost:~/workspace# </span><b><span style="color: #333333;">ip address add dev wg0 </span><span style="color: #b45f06;">10.1.1.200</span><span style="color: #333333;">/24</span></b></span><br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;" /><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;">root@localhost:~/workspace# <b>ip link set up dev wg0</b></span></div><span style="background-color: white; color: #333333; font-size: 14.85px;">root@localhost:~/workspace# </span><b>./wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs=</span> allowed-ips 10.1.1.0/24 <span style="color: #a64d79;">endpoint 0.0.0.0:0</span></b></div><div><i> => endpoint 값으로 0.0.0.0:0을 준 이유는 반대편 endpoint가 LTE 망을 타고 나오기 때문이다.</i></div><div><i> => peer 다음에 들어가는 public key는 1장의 내용을 기준으로 하면, <b><span style="color: #38761d;">peer의 고정(static) public key </span></b>값이다.</i></div><div><br /></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">root@localhost:~/workspace# </span><span style="color: #333333;"><span style="font-size: 14.85px;"><b>iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE</b></span></span></div><div><br /></div><div><b style="background-color: #d0e0e3;"><Ubuntu B></b></div></div><div><div class="separator" style="clear: both;"><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;">root@localhost:~/workspace$<b> sudo </b></span><b style="color: #333333; font-size: 14.85px;">wg genkey | tee ./privatekey | wg pubkey > ./publickey</b></div><div class="separator" style="clear: both;"><span style="background-color: white; color: #333333; font-size: 14.85px;">root@localhost:~/workspace$</span><b style="color: #333333; font-size: 14.85px;"> </b><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;"><b>sudo ip link add dev wg0 type wireguard</b></span><br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;" /><span style="background-color: white; font-family: inherit; font-size: 14.85px;"><span style="color: #333333;">root@localhost:~/workspace$ </span><b><span style="color: #333333;">sudo ip address add dev wg0 </span><span style="color: #b45f06;">10.1.1.100</span><span style="color: #333333;">/24</span></b></span><br style="background-color: white; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 14.85px;" /><span style="background-color: white; color: #333333; font-family: inherit; font-size: 14.85px;">root@localhost:~/workspace$<b> sudo ip link set up dev wg0</b></span></div></div><div><span style="background-color: white; color: #333333; font-size: 14.85px;">root@localhost:~/workspace$ </span><b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">FB6Tnz76Kl/DGXSNxlNqXZ+yNCvQVg3FGsYORQoe+mw=</span> allowed-ips 10.1.1.0/24 <span style="color: #a64d79;">endpoint x.x.x.x:59760</span></b></div><div><i> => endpoint 값 x.x.x.x는 왼쪽 상단의 Wi-Fi Access Point의 WAN IP 주소이다.</i></div><div><i> </i><i>=> peer 다음에 들어가는 public key는 1장의 내용을 기준으로 하면, <b><span style="color: #38761d;">peer의 고정(static) public key </span></b>값이다.</i></div><div><br /></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌 위의 설정이 제대로 먹히려면 사전에 왼쪽 상단의 공유기에서 아래와 같은 port forwarding 설정을 해 주어야 한다.</span></b></div><div style="text-align: center;"><span style="color: #ff00fe;"><span style="background-color: white; font-size: 14.85px;">0.0.0.0/0 ---> x.x.x.x:59760 ---> MACCHIATObin private IP:59670</span></span></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div>이 상태에서 ping test를 해 보도록 하자. OK, 정상 동작한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTppoq0kOd0WxVV0Oz4qBik2_6ASBujgAJXpGnWq4kG5o2P0niPzwOpaS8xtZEAfvx0zuPe7S6lPugzIwhdeGyzqsFUBb78qs64E5k0c29oYDMaBdBQzblNDALyoZG-qsUx7lWCCm9IAet/s566/ping_from_mcbin_to_ubuntu.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="240" data-original-width="566" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTppoq0kOd0WxVV0Oz4qBik2_6ASBujgAJXpGnWq4kG5o2P0niPzwOpaS8xtZEAfvx0zuPe7S6lPugzIwhdeGyzqsFUBb78qs64E5k0c29oYDMaBdBQzblNDALyoZG-qsUx7lWCCm9IAet/s320/ping_from_mcbin_to_ubuntu.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.2] ping from 10.1.1.200 to 10.1.1.100</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4Hrt7fUHqP7uh2JqDjP0qq-dC3sEnZOWcgp_jzCFyLyMFL2rEGgVERb1-PWbyrIR50QujhMYuLQGsCHlAV-55Nk4LrnLFouBXRZfND1Ne0ixqACftS6RywsUbhxXko7m8QxCUaV9htnwM/s602/ping_from_ubunu_A_to_B.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="198" data-original-width="602" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4Hrt7fUHqP7uh2JqDjP0qq-dC3sEnZOWcgp_jzCFyLyMFL2rEGgVERb1-PWbyrIR50QujhMYuLQGsCHlAV-55Nk4LrnLFouBXRZfND1Ne0ixqACftS6RywsUbhxXko7m8QxCUaV9htnwM/s320/ping_from_ubunu_A_to_B.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.3] ping from Ubuntu A to Ubuntu B</div><br /><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌그림 2.1의 오른쪽 망이 LTE로 연결되어 있으므로, Ubuntu B -> MACCHIATObin 쪽으로 먼저 ping을 시도해야 한다(그래야 tunnel이 뚫린다).</span></b></div><div><br /></div><div><span style="color: #666666;">(또 다른 테스트베드인) </span>아래 환경은 우측망에 MangBox가 추가된 점이 앞서와 다르다.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjViYrm83aCtlYIPVX3TO8WJjZzy6xXyxhyR6KKe0HjeXWIvqyffpYMjJcUlBOU_6mKZYV4-fBxU0BdqOVZKsAyVDOe24jqbJfxT_xe0akXKgA_Antxyebzfrh04j8kgHMwe3Q2GepKkgbd/s683/wg_direct.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="437" data-original-width="683" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjViYrm83aCtlYIPVX3TO8WJjZzy6xXyxhyR6KKe0HjeXWIvqyffpYMjJcUlBOU_6mKZYV4-fBxU0BdqOVZKsAyVDOe24jqbJfxT_xe0akXKgA_Antxyebzfrh04j8kgHMwe3Q2GepKkgbd/w400-h256/wg_direct.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.4] WireGuard를 이용한 direct VPN 구성(2)</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: left;"><span style="color: #666666;">(위 내용에는 없지만 MangBox에 Wireguard를 문제없이 설치했다면)</span> 여기서 특별히 문제가 될 만한 부분은 OpenWrt firewall 설정 뿐이다. 즉, wireguard를 위한 별도의 zone(wg)을 하나 만들고, wg <=> lan, wg <=> wan 간에 forwarding이 가능하도록 firewall 설정을 추가해주기만 하면 문제 없이 tunnel이 뚫릴 것이다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"># Add the firewall zone</div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci add firewall zone</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].name='wg'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].input='ACCEPT'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~#<b> </b></span><b>uci set firewall.@zone[-1].forward='ACCEPT'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].output='ACCEPT'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].masq='1'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].mtu_fix='1'</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"># Add the WireGuard interface to it</div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@zone[-1].network='wg0'</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"># Forward WAN and LAN traffic to/from it</div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci add firewall forwarding</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].src='wg'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].dest='wan'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci add firewall forwarding</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].src='wg'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].dest='lan'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci add firewall forwarding</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].src='lan'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].dest='wg'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci add firewall forwarding</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].src='wan'</b></div><div class="separator" style="clear: both; text-align: left;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci set firewall.@forwarding[-1].dest='wg'</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>uci commit firewall</b></div><div class="separator" style="clear: both;"><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #333333; font-size: 14.85px;">root@mango:~# </span><b>/etc/init.d/firewall restart</b></div></div></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">나머지 설정은 크게 어려운 부분이 없으니, 이에 관해서는 독자 여러분의 몫으로 남겨두도록 하겠다. 😋</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">_________________________________________</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">이번 장에서는 WireGuard VPN을 이용하여 peer간에 1 대 1 통신이 가능한지를 실험을 통해 확인해 보았다. 이 실험의 전제 조건은 두개의 peer가 위치한 <span style="color: #666666;">(최소한)</span> 어느 한쪽의 NAT 장비(firewall, 공유기, CGNAT 등)에서는 port forwarding 설정을 해 주어야 한다는 것이었다. 하지만, 이것이 불가능한 경우에는 어찌해야 할까 ? </span><span style="text-align: left;">다음 장에서는 양쪽 NAT 장비 모두에서 port forwarding이 불가할 경우(예: LTE <-> LTE), 이를 해결하는 방법을 소개하도록 하겠다.</span></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div><br /></div><div><br /></div><div><b><font color="#3d85c6" size="6">3. P2P 통신 2: WireGuard VPN으로 Relay 서버 구성하기</font></b></div><div>우리는 <a href="https://slowbootkernelhacks.blogspot.com/2020/09/espressobin-ultra-macchiatobin-switch_25.html">이전 blog post</a>에서 n2n를 이용하여 NAT 장비의 설정을 변경하지 않으면서도 2개의 peer간에 상호 통신(P2P 통신)이 가능하다는 것을 체험하였다. 이 절에서는 WireGuard를 이용하여 비슷한 동작이 가능하다는 사실을 확인해 보고자 한다.</div><div><br /></div><div>우선 먼저 아래 환경(2개의 LTE 망과 1개의 Ethernet 망)에서 relay 구성이 가능한지를 확인해 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk1JNCzU5YO13DWl8cdaeK-f7rHL9rhdwEJP7qZsfFPVR4CqTYoZFoqjP9UclZ_aUyTENybKNQ6X6g6DJOlYX7DDnGn9X-gjJ7quBw-9fGYWYduQAThFyjftgmK5ObH03-4bUh0QgCX1Hy/s785/wg_testbed5.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="597" data-original-width="785" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjk1JNCzU5YO13DWl8cdaeK-f7rHL9rhdwEJP7qZsfFPVR4CqTYoZFoqjP9UclZ_aUyTENybKNQ6X6g6DJOlYX7DDnGn9X-gjJ7quBw-9fGYWYduQAThFyjftgmK5ObH03-4bUh0QgCX1Hy/w400-h304/wg_testbed5.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] WireGuard server를 이용한 relay VPN 구성(1)</div><div><br /></div><div><b style="text-align: center;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; font-weight: 400; text-align: left;">📌 n2n과 wireguard의 외관상의 차이는 n2n은 중앙에 전용 supernode가 필요했지만, wireguard는 동일한 기능을 가진 제 3의 wireguard를 relay server로 활용한다는 점이다.</span></b></div><div><br /></div><div><div><div><div><div class="separator" style="clear: both;"><b style="background-color: #d0e0e3;"><상단 Relay Server></b></div><div class="separator" style="clear: both;">$ echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf</div></div><div><div>$ echo "net.ipv4.conf.all.proxy_arp = 1" >> /etc/sysctl.conf</div><div>$ <b>sudo sysctl -p /etc/sysctl.conf</b></div></div><div><i> => ip forwarding 및 proxy arp 기능을 enable시킨다.</i></div><div><div><div><br /></div><div>$ <b>wg genkey | tee ./privatekey | wg pubkey > ./publickey</b></div><div>$ <b>sudo ip link add dev wg0 type wireguard</b></div><div>$ <b>sudo ip address add dev wg0 <span style="color: #b45f06;">10.1.1.254</span>/24</b></div><div>$<b> sudo ip link set up dev wg0</b></div><div><i> => wg0 interface 기본 설정</i></div><div><b><br /></b></div><div>$ <b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">bLEjXKumUj9X7FEVIJYsJSDMfUFjrHfBAGtvg++hmnQ=</span> allowed-ips <span style="color: #a64d79;">10.1.1.200/32 </span>endpoint 0.0.0.0:0</b></div><div><i> => Ubuntu(A)를 peer로 등록</i></div><div><br /></div><div>$ <b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">oGqQEGdTho5jwoqt3aIiYYXfehQTy83FNYKHC6HBUUs=</span> allowed-ips <span style="color: #a64d79;">10.1.1.100/32</span> endpoint 0.0.0.0:0</b></div></div><div><i> => Ubuntu(B)를 peer로 등록</i> </div><div><i><br /></i></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 Relay server는 allowed-ips 값으로 10.1.1.0/24와 같이 network을 사용하면 안되며, 위와 같이 정확히 peer 자체를 기술해 주어야 한다.</span></b></div><div><br /></div><div>$ <b>sudo iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT</b></div><div>$ <b>sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT</b></div><div>$ <b>sudo iptables -A FORWARD -i wg0 -o wg0 -m conntrack --ctstate NEW -j ACCEPT</b></div><div><i> => wg packet을 forwarding해 줌.</i></div><div><br /></div><div>$ <b><span style="color: #666666;">sudo iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o wlx909f3309fe00 -j MASQUERADE</span></b></div><div><i> => physical interface에 대해 masquerading rule 추가</i></div><div><i> => 이 상황에서 반드시 필요한 설정은 아님.</i></div><div><br /></div><div>$ <b>sudo ifconfig wg0 mtu 1300</b></div><div><i><span style="color: #990000;"> => (중요) LTE 내부에 GTP tunnel이 사용되는 관계로 이를 고려하여 mtu size를 1300(대략적인 값임)으로 줄여 줌.</span></i></div></div><div><br /></div><div><br /></div><div><b style="background-color: #d0e0e3;"><Ubuntu A></b></div></div><div><div class="separator" style="clear: both;"><div>$ <b>wg genkey | tee ./privatekey | wg pubkey > ./publickey</b></div><div>$ <b>sudo ip link add dev wg0 type wireguard</b></div><div>$ <b>sudo ip address add dev wg0 <span style="color: #b45f06;">10.1.1.200</span>/24</b></div><div>$<b> sudo ip link set up dev wg0</b></div><div><br /></div></div></div><div>$<b> </b><b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">Q1hf3SMjpq0+ckzs71hcwSBkrMG+m6bB4xTl1s6pU1I=</span> allowed-ips 10.1.1.0/24 endpoint x.x.x.x.:59760</b></div></div><div><b><br /></b></div><div><div><b style="background-color: #d0e0e3;"><Ubuntu B></b></div><div><div class="separator" style="clear: both;"><div><div class="separator" style="clear: both;"><div>$ <b>wg genkey | tee ./privatekey | wg pubkey > ./publickey</b></div><div>$ <b>sudo ip link add dev wg0 type wireguard</b></div><div>$ <b>sudo ip address add dev wg0 <span style="color: #b45f06;">10.1.1.100</span>/24</b></div><div>$<b> sudo ip link set up dev wg0</b></div><div><br /></div></div></div><div>$<b> </b><b>sudo wg set wg0 listen-port 59760 private-key ./privatekey peer <span style="color: #38761d;">Q1hf3SMjpq0+ckzs71hcwSBkrMG+m6bB4xTl1s6pU1I=</span> allowed-ips 10.1.1.0/24 endpoint x.x.x.x.:59760</b></div></div></div></div></div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 </span></b><span style="color: #ff00fe;">NAT 장비를 통해 연결된 tunnel이 NAT 장비에 의해 끊어지지 않도록 하기 위해서는 위의 명령 끝 부분에 "persistent-keepalive 25" 설정을 추가해 주어야 한다.</span></div><div><br /></div><div>자, 모든 설정이 완료되었으니, ping test를 해 보도록 하자.</div><div><br /></div><div><b style="background-color: #d0e0e3;"><Ubuntu A></b></div><div>$ <b>ping 10.1.1.254</b></div><div> <i> => OK, relay server까지 ping이 된다.</i></div><div>$ <b>ping 10.1.1.100</b></div><div> <i>=> OK, relay server를 경유하여 peer(Ubuntu B)에게 ping이 전달된다.</i></div><div><br /></div><div><b style="background-color: #d0e0e3;"><Ubuntu B></b></div><div><div>$ <b>ping 10.1.1.254</b></div><div><i> => OK, </i><i> relay server까지 ping이 된다.</i></div><div>$ <b>ping 10.1.1.200</b></div><div><i> => OK, </i><i>relay server를 경유하여 peer(Ubuntu A)에게 ping이 전달된다.</i></div><div><br /></div></div><div>이 상태에서 relay server에서 wg 명령을 실행해 본 결과는 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjADbPi1qILAMrqbmypAH48ImLNHuMSb80hjnXiXbgHaLgwM4dZ8yH0Eaq8d8Kk8TZR0ebBsfKmQKqBBU6WkTAQ0xfQNYb6qjuaMfOAMSnsCcO9yQWSSd26HQ6qM2jzkzfmma69_TvxIxP4/s548/wg_relay_server_status.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="325" data-original-width="548" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjADbPi1qILAMrqbmypAH48ImLNHuMSb80hjnXiXbgHaLgwM4dZ8yH0Eaq8d8Kk8TZR0ebBsfKmQKqBBU6WkTAQ0xfQNYb6qjuaMfOAMSnsCcO9yQWSSd26HQ6qM2jzkzfmma69_TvxIxP4/s320/wg_relay_server_status.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] Relay server의 wg 상태 확인</div><div><br /></div><div>다음으로 테스트할 환경은 외부에 Server(예: AWS EC2)가 있고, 두개의 서로 다른 Ethernet 망이 존재하는 좀 더 일반적인 상황이 되겠다. <span style="color: #666666;">(하지만 설정과 관련해서는 앞서의 내용과 크게 다를 바가 없으니) </span>이와 관련해서는 독자 여러분이 직접 설정 & 확인해 보시기 바란다. 😋 😂</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8795z-v4HUwAStIQfvX3RydiS6d2t9fVYqqhW1kR54PNkv4E-7-_YWJP56_MpHZL2COBrVHBCb9_PENb2Z4oJGI2Y8nQw4kbWBzEDsDl_08TXhyphenhyphenV6Xu4KVX09inwxdfMV0eZ2l3bv4PMT/s746/wg_relay_testbed2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="539" data-original-width="746" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8795z-v4HUwAStIQfvX3RydiS6d2t9fVYqqhW1kR54PNkv4E-7-_YWJP56_MpHZL2COBrVHBCb9_PENb2Z4oJGI2Y8nQw4kbWBzEDsDl_08TXhyphenhyphenV6Xu4KVX09inwxdfMV0eZ2l3bv4PMT/s320/wg_relay_testbed2.PNG" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] WireGuard server를 이용한 relay VPN 구성(2)</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW2hnWQOroj_3i2-tgcqwurW5qKCAYRq7AVgoDiHJ35bORnEPUDNpUbjP4OYbHhzhPZCYEekFBfrLuyv04dTzT5qEVi1Xo8KRgaczaaveKR_RrvbGSSRllxuLggcXEGmCEgO4Vdw1oviJ-/s705/wg_relay_testbed1.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="541" data-original-width="705" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgW2hnWQOroj_3i2-tgcqwurW5qKCAYRq7AVgoDiHJ35bORnEPUDNpUbjP4OYbHhzhPZCYEekFBfrLuyv04dTzT5qEVi1Xo8KRgaczaaveKR_RrvbGSSRllxuLggcXEGmCEgO4Vdw1oviJ-/s320/wg_relay_testbed1.PNG" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.4] WireGuard server를 이용한 relay VPN 구성(3)</div><div><br /></div><div><br /></div><div>어떤가 ? 이 정도면 WireGuard를 어디에 사용하면 좋을지 견적(?)이 나오지 않는가 ? 😎</div><div><br /></div><div><div><span style="background-color: #fff2cc;"><b><여기서 잠깐 !></b></span></div><div><span><i> => WireGuard + UDP hole punching에 관하여 ...</i></span></div></div><div><span><i><br /></i></span></div><div><span>지금까지 3장에서 소개한 내용은 NAT device 뒷단에 위치한 WireGuard peer간에 원할한 통신을 위해 별도의 relay server를 두는 방식에 관한 것이었다. 이 방식은 어떠한 상황에서든 p2p 연결이 가능하게 만드는 장점이 있는 반면, relay server를 운용하면서 발생하는 비용과 relay server에 의한 병목(peer가 많아질 수록 심해짐)이 발생할 수 있다는 단점도 가지고 있다. 따라서 이러한 문제를 해결하기 위해 Hole punching 개념이 등장하게 되는데, 아래에 이와 관련한 재밌는 글이 하나 있어 소개해 본다.</span></div><div><span><br /></span></div><div style="text-align: center;"><span><a href="https://www.jordanwhited.com/posts/wireguard-endpoint-discovery-nat-traversal/">https://www.jordanwhited.com/posts/wireguard-endpoint-discovery-nat-traversal/</a></span></div><div><span><br /></span></div><div><span><span style="color: #666666;">(결론부터 얘기하자면) </span>위에서 제시하는 방법은 흥미를 유발(<span style="color: #990000;">DNS를 사용하여 peer의 endpoint 정보를 알아냄</span>)하기는 하나, 2개의 peer 중 한쪽이 Full Cone NAT인 상황에서나 가능한 방법이라고 말할 수 있겠다. 즉, 양쪽이 Symmetric NAT나 Port Restricted Cone NAT으로 구성된 경우에는 통하지 않는다.</span></div><div><span><i>___________________________________________________</i></span></div><div><br /></div><div><br /></div><div><div><b><font color="#3d85c6" size="6">4. WireGuard VPN Kernel Code 분석</font></b></div><div>이번 장에서는 WireGuard kernel code를 대략적으로 분석해 보고자 한다.</div></div><div><br /></div><div><div><b style="background-color: #ffe599;"><분석 Point></b></div><div>1) 주요 data structure를 살펴 본다.</div><div>2) 주요 코드의 흐름을 파악한다.</div><div><i> - 초기화 부분</i></div><div><i> - 패킷 수신 및 복호화</i></div><div><i> - 패킷 송신 및 암호화</i></div><div>3) 기타 hash table(public key, Index 기반) 관련 코드를 분석해 본다.</div><div>4) noise IK code가 1장에서 설명한 대로 되어 있는지 확인해 본다.</div><div>______________</div></div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 </span></b><span style="color: #ff00fe;">정말 대략적으로 분석하였다. 코드 분석 후 전체 구조를 한눈에 볼 수 있는 그럴 듯한 몇 장의 그림을 만들어야 하는데... 좀 귀찮다^^... 😂</span></div><div><br /></div><div>WireGuard kernel code는 아래 보이는 내용이 전부이다. 코드량은 많지 않지만 정말로 군더더기 하나 없이 잘 구현되어 있다. <b>왜 Torvalds 형님이 그렇게 극찬을 했는지 이해가 된다.</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSYhNbTzNV3Q1wmLmwF-t4HHwBwqRc58WJkAocNyIpXLozGgwEOzJI7sY3QOOANqln7GYgctfeNM9vNONUgjGsjrLOJ0dOzIJeOSHJFjhQALHT3Jq_AWWph_PEZjOt-BPsO3TzogyWQz_n/s815/wg_kernel_ls.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="130" data-original-width="815" height="102" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSYhNbTzNV3Q1wmLmwF-t4HHwBwqRc58WJkAocNyIpXLozGgwEOzJI7sY3QOOANqln7GYgctfeNM9vNONUgjGsjrLOJ0dOzIJeOSHJFjhQALHT3Jq_AWWph_PEZjOt-BPsO3TzogyWQz_n/w640-h102/wg_kernel_ls.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.1] Wireguard kernel code 목록</div><div><br /></div><div>그럼, 먼저 주요 파일의 용도(역할)를 간단히 정리하고 넘어가기로 하자.</div><div>____________________________________________</div><div><div><b>allowedips.[ch] </b></div><div><ul style="text-align: left;"><li><i>allowed ips 관련 코드</i></li></ul></div><div><b>cookie.[ch] </b></div><div><ul style="text-align: left;"><li><i>cookie 관련 코드</i></li></ul></div><div><b>device.[ch]</b></div><div><ul style="text-align: left;"><li><i>net_device 관련 코드 - wg_open/wg_stop/wg_xmit/wg_setup/wg_newlink ...</i></li></ul></div><div><b>main.c</b></div><div><ul style="text-align: left;"><li><i>main routine - mod_init/mod_exit</i></li></ul></div><div><b>netlink.[ch]</b></div><div><ul style="text-align: left;"><li><i>userspace tool인 wg와의 netlink socket 통신 코드, device(net_device) 자신 및 peer에 대한 설정</i></li></ul></div><div><b>noise.[ch]</b></div><div><ul style="text-align: left;"><li><i>wireguard key handshaking protocol code(1장에서 설명한 내용)</i></li></ul></div><div><b>peer.[ch]</b></div><div><ul style="text-align: left;"><li><i>peer 생성/삭제 관련 코드</i></li></ul></div><div><b>peerlookup.[ch]</b></div><div><ul style="text-align: left;"><li><i>2개의 hash table(public key 기반 hash table, index 기반 hash table)에 대한 operation(alloc, add, remove, lookup) 정의</i></li></ul></div><div><b>queueing.[ch]</b></div><div><ul style="text-align: left;"><li><i>(중간 중간에) packet을 담아두는 queue(ptr_ring buffer) 관련 operation(alloc, init, free) 정의</i></li></ul></div><div><b>ratelimiter.[ch]</b></div><div><ul style="text-align: left;"><li><i>rate limit 관련 코드</i></li></ul></div><div><b>receive.[ch]</b></div><div><ul style="text-align: left;"><li><i>패킷 수신 관련 코드(복호화 포함)</i></li></ul></div><div><b>send.[ch]</b></div><div><ul style="text-align: left;"><li><i>패킷 송신 관련 코드(암호화 포함)</i></li></ul></div><div><b>socket.[ch]</b></div><div><ul style="text-align: left;"><li><i>send4/6( ) 함수 호출하여 패킷 송신, .encap_rcv = wg_receive 통해 udp tunnel 패킷 수신부 정의</i></li></ul></div><div><b>timers.[ch]</b></div></div><div><ul style="text-align: left;"><li><i>wireguard에서 사용하는 각종 timer 정의</i></li></ul></div><div><div><br /></div><div>wireguard-linux-compat/src/<b>crypto/zinc</b>$ ls -al</div><div><ul style="text-align: left;"><li><i>wireguard에서 사용하는 암호/해쉬 알고리즘 위치</i></li></ul></div><div><i><b>blake2s</b> : blake2s hash 함수</i></div><div><i><b>chacha20 </b> : chacha20 stream cipher 암호 알고리즘</i></div><div><i><b>chacha20poly1305.c </b>: chapoly AEAD 코드</i></div><div><i><b>curve25519 </b>: curve25519 공개키 암호 알고리즘</i></div><div><i><b>poly1305 </b>: poly1305 message authentication 알고리즘</i></div></div><div>____________________________________________</div><div><br /></div><div><div>Wireguard는 아래 그림과 같이 wg tool과 wireguard kernel module로 구성되어 있다. 이 둘은 netlink socket을 통해 연결되어 있는데, 이는 netlink.c 파일에 구현되어 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzCyEFrrwr-TO771RYDmdkK-6aEJWukIn94JIWsutqi8ZBMt8x6BV8Q4wzUJTNmBzXw0W5vMaNoSmJEoIdvJsNpTtpUTStUz_aCNGucQ1WKQ8Fg_ng67NvtB60x3Xag2IXnDZjen1PEeT6/s784/wg_tool_kernel.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="453" data-original-width="784" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzCyEFrrwr-TO771RYDmdkK-6aEJWukIn94JIWsutqi8ZBMt8x6BV8Q4wzUJTNmBzXw0W5vMaNoSmJEoIdvJsNpTtpUTStUz_aCNGucQ1WKQ8Fg_ng67NvtB60x3Xag2IXnDZjen1PEeT6/w400-h231/wg_tool_kernel.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.2] wg tool과 wireguard kernel module 간의 netlink socket 통신</div></div><div><br /></div><div>그럼, 본격적으로 code 분석에 들어가 보자.</div><div><br /></div><div>제일 먼저 살펴 볼 파일은 당연히 main.c인데, 이 파일 안에는 모듈 시작 함수인 mod_init( )과 종료 함수인 mod_exit( ) 만이 기술되어 있다. 이중 mod_init( ) 함수는 wg_noise_init( ), wg_device_init( ), wg_genetlink_init( ) 등 몇가지 초기화 함수를 호출하는게 전부인 것을 알 수 있다. <span style="color: #38761d;">도대체 1장에서 설명한 handshaking은 어디에서 시작하는 것일까 ?</span></div><div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi504HLuQf3mbPLPKvOlnvHC8ZUzLXFhDE8cSsSj-gQkZk_V36YBy8-S0Q1A96yXU4aG0H-jiP9aV_UFdHuwArVVRShGSEZssuPflsDls3LxDTOcQfwyVeWMdahK7bYyhH4thiyt-kfr19I/s874/wg_kernel_init.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="609" data-original-width="874" height="279" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi504HLuQf3mbPLPKvOlnvHC8ZUzLXFhDE8cSsSj-gQkZk_V36YBy8-S0Q1A96yXU4aG0H-jiP9aV_UFdHuwArVVRShGSEZssuPflsDls3LxDTOcQfwyVeWMdahK7bYyhH4thiyt-kfr19I/w400-h279/wg_kernel_init.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.3] mod_init( ) 함수 - <b>main.c</b></div></div><div><br /></div><div><span style="color: #666666;">(미리 답을 하자면)</span> 실제 handshaking 시작에 관여하는 코드는 아래 그림 4.6(<b>wg_newlink 함수</b>)과 4.7(<b>wg_peer_create 함수</b>)이라고 볼 수 있다. 하지만, 이 코드로 곧 바로 넘어가기 전에, wireguard에서 가장 중요하게 다루고 있는 두개의 data structure 즉, <b>struct wg_device</b>와<b> struct wg_peer</b>를 먼저 살펴 보는 것이 순서일 것 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0fgibyKSgiw4_yaUoUNSqKG9tDGwxxu5pk18Yq05GUlfhhSEzvv_Qk0srotskaf9UqfaWR5vqAq-g2sjSmZxD-J-YRQ3yscgnZVGK7-Y9KYy1i43ErPMREkbgL-dfYcshx59QQkju57wb/s1099/wg_kernel_00.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="1099" height="373" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0fgibyKSgiw4_yaUoUNSqKG9tDGwxxu5pk18Yq05GUlfhhSEzvv_Qk0srotskaf9UqfaWR5vqAq-g2sjSmZxD-J-YRQ3yscgnZVGK7-Y9KYy1i43ErPMREkbgL-dfYcshx59QQkju57wb/w640-h373/wg_kernel_00.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.4] wg_device structure - <b>device.h</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0k5OsBW2k3qVkIzeGKHDO0OrKsfRricDg2BMqyCQsB7HXJ8PakKW9cIymiPwOhHNkuXDVrfkJlGnMiI7wKC1d1dIRertJXHZN3J1W2YCJPbJL4Bms_8_1jB5FwAMLcT8g4yGmTZ6D8ZJH/s666/wg_kernel_01.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="574" data-original-width="666" height="345" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0k5OsBW2k3qVkIzeGKHDO0OrKsfRricDg2BMqyCQsB7HXJ8PakKW9cIymiPwOhHNkuXDVrfkJlGnMiI7wKC1d1dIRertJXHZN3J1W2YCJPbJL4Bms_8_1jB5FwAMLcT8g4yGmTZ6D8ZJH/w400-h345/wg_kernel_01.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.5] wg_peer structure - <b>peer.h</b></div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 </span></b><span style="color: #ff00fe;">여기서 자세히 설명하지는 않지만, 위의 두 data structure를 구성하는 각 필드의 내용을 면밀히 살펴보기 바란다. </span></div><div><br /></div><div>그럼, 이제부터 <b>wg_newlink( )</b> 함수와 <b>wg_peer_create( )</b> 함수를 살펴 보기로 하자.</div><div><br /></div><div>먼저 "ip link add dev wg0 type wireguard" 명령 실행시 호출되는 <b>wg_newlink( )</b> 함수는 2개의 hash table을 생성하고, handshake용 worker(function) 및 work queue를 생성한다. 또한 packet을 encrypt & decrypt하는 worker와 packet crypt workqueue를 생성하는 역할도 한다. 맨 마지막에는 netdevice를 등록하면서 함수를 종료한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwYXqOtZId6t4UVCELeS-1zTHfeb_wzmXBRAxPTJwJAjG_Tw2dXW5qHYyDubNp0JxuXToLCXE2AcwXr9rb7dwDUENLqdZhRuz3uQ87JHQMEuC-AdBkJViJa4ibGQcSkh_DVyQCX65VjHWp/s963/wg_kernel_1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="963" data-original-width="961" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwYXqOtZId6t4UVCELeS-1zTHfeb_wzmXBRAxPTJwJAjG_Tw2dXW5qHYyDubNp0JxuXToLCXE2AcwXr9rb7dwDUENLqdZhRuz3uQ87JHQMEuC-AdBkJViJa4ibGQcSkh_DVyQCX65VjHWp/w399-h400/wg_kernel_1.png" width="399" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.6] wg_newlink( ) 함수 - <b>device.c</b></div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 </span></b><span style="color: #ff00fe;">wireguard kernel code는 기본적으로 net_device 형태로 되어 있다. 2~3장에서 wg0 interface가 생성되었던 것을 기억하는가 ? </span></div><div><br /></div><div>한편 <b>wg_peer_create( )</b> 함수는 "wg set peer ..." 명령 실행시 호출되는 함수로 peer를 hash table에 등록함과 동시에 실제 handshake 동작이 시작되도록 하는 역할을 한다. 더불어 packet을 외부로 내보내기 위한 worker를 초기화하고, decrypt된 패킷을 처리하는 napi 함수를 등록하는 일도 수행한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHXqku30jnIV8EvcHYQezfM70bmKIu8nM2XEvLiBgVrIF4PowM_sc8g7vwSnTKN04mabfCX8FhA9ruOW4LLbFBojAjfesH4dJ6O9J-h19Oc5mokTL-dwyjsF5Y6HBOo28NFtNbM6hJpIh/s921/wg_kernel_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="850" data-original-width="921" height="369" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLHXqku30jnIV8EvcHYQezfM70bmKIu8nM2XEvLiBgVrIF4PowM_sc8g7vwSnTKN04mabfCX8FhA9ruOW4LLbFBojAjfesH4dJ6O9J-h19Oc5mokTL-dwyjsF5Y6HBOo28NFtNbM6hJpIh/w400-h369/wg_kernel_2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.7] wg_peer_create( ) 함수 - <b>netlink.c => peer.c</b></div><div><br /></div><div>Handshake를 초기화하고 시작하는 코드를 살펴 보았으니, 다음 차례는 packet이 어떻게 transmit or receive되는지를 확인해 보아야 할 것이다.</div><div>먼저 아래 코드(그림 4.8 ~ 4.9)는 패킷 수신부가 어떻게 동작하는지를 정리한 것이다.</div><div><br /></div><div style="text-align: center;"><span style="color: #b45f06;"><b>암호화된 ip tunnel 패킷 수신(wg_receive) -> tunnel 제거 및 복호화(</b><span style="text-align: left;"><b>decrypt_packet) </b></span><b>-> 상위로 전달(</b><span style="text-align: left;"><b>wg_packet_rx_poll</b></span><span style="text-align: left;"><b>)</b></span></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gFYCr2-Fw4BaxH4kfOzs0RSLeGHJHvTj8PyhP9j72OJNMS84tP08c6WEwGRCzJtff6y9vU7HNrs1Au0NksYr_mMXsOCGTsbwFVtYaGDU1X5aym0B_5pHyaLYWQEhECnF6IHmyemdNGn6/s1093/wg_kernel_3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="903" data-original-width="1093" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1gFYCr2-Fw4BaxH4kfOzs0RSLeGHJHvTj8PyhP9j72OJNMS84tP08c6WEwGRCzJtff6y9vU7HNrs1Au0NksYr_mMXsOCGTsbwFVtYaGDU1X5aym0B_5pHyaLYWQEhECnF6IHmyemdNGn6/w400-h330/wg_kernel_3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.8] wg_receive( ) 함수 - <b>socket.c => receive.c</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi74JbWz1Tm4zVVnNebXq5mcXoqWb13Ea57lST3RjX1_k-ceR0eG1sfzoryR94IS12CESWWz_VRDbAeE9iO7WylNv8BJ-T_uQbgeC4IHTcAv6HNAOEW2xDhPPO7R0HftDSSCW_9VHiWftlR/s844/wg_kernel_4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="477" data-original-width="844" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi74JbWz1Tm4zVVnNebXq5mcXoqWb13Ea57lST3RjX1_k-ceR0eG1sfzoryR94IS12CESWWz_VRDbAeE9iO7WylNv8BJ-T_uQbgeC4IHTcAv6HNAOEW2xDhPPO7R0HftDSSCW_9VHiWftlR/w400-h226/wg_kernel_4.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.9] wg_packet_decrypt_worker( ) 함수 - <b>receive.c</b></div><div><br /></div><div>다음으로 패킷 송신부(그림 4.10 ~ 12)를 살펴 보면 다음과 같다.</div><div><br /></div><div style="text-align: center;"><b><span style="color: #b45f06;">wg_xmit( ) -> ptr_ring buffer -> encrypt_packet( ) -> send4( )</span></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgci7-qM1f_wM5bZNkzdxprU52XaDN_mrtAX3_kRkl3PPqfbZ1D3HzWz-D0XvL6qvSFN08o2YOPauhNcGTrjmlQOy516TQ3SjiZ49oiDiBBQA9u35tX2KofzvjWGFhXpvoWKb_J9hoIcZL5/s989/wg_kernel_5.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="673" data-original-width="989" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgci7-qM1f_wM5bZNkzdxprU52XaDN_mrtAX3_kRkl3PPqfbZ1D3HzWz-D0XvL6qvSFN08o2YOPauhNcGTrjmlQOy516TQ3SjiZ49oiDiBBQA9u35tX2KofzvjWGFhXpvoWKb_J9hoIcZL5/w400-h272/wg_kernel_5.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.10] wg_xmit( ) 함수 - <b>device.c</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLyzZyO_7wgrJu9tRoqY7J95i2X82QW375jly1f1WVaOOnYocLfD8WOzfeWoafr6iPePNAewSXDHd1dbBGodzk6NHa6I59clZ064J4oif6feneKtrvRnbUTy9hz_Lq0oGYHoOsS44oAXVx/s862/wg_kernel_6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="704" data-original-width="862" height="326" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLyzZyO_7wgrJu9tRoqY7J95i2X82QW375jly1f1WVaOOnYocLfD8WOzfeWoafr6iPePNAewSXDHd1dbBGodzk6NHa6I59clZ064J4oif6feneKtrvRnbUTy9hz_Lq0oGYHoOsS44oAXVx/w400-h326/wg_kernel_6.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.11] wg_packet_encrypt_worker( ) 함수 - <b>device.c => send.c</b></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6T0urPBSkWcsik_T5VnUo74_aPSF_D6dfN1X45ywo7yszCkX_cvhHR-dVZQ3UQfTXrCpazEu8jY_fryF5wKBGWdkt2CsvCSWt5aq9xpqBJ_18JcLE7L42r9-5e_uegYUMyRR1qP5UZKz7/s1100/wg_kernel_7.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="737" data-original-width="1100" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6T0urPBSkWcsik_T5VnUo74_aPSF_D6dfN1X45ywo7yszCkX_cvhHR-dVZQ3UQfTXrCpazEu8jY_fryF5wKBGWdkt2CsvCSWt5aq9xpqBJ_18JcLE7L42r9-5e_uegYUMyRR1qP5UZKz7/w400-h268/wg_kernel_7.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.12] wg_packet_tx_worker( ) 함수 - <b>send.c</b></div></div><div><br /></div><div><span style="color: #b45f06;"><b>지금까지 살펴본 그림 4.6 ~ 4.12의 과정을 handshake message tx/rx와 실제 data message tx/rx의 관점에서 다시 요약해 보면 다음과 같다.</b></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Q2KUuIeoS8nIY8J3krwQsBwRzj7myaLyIXHmjJziZ17LO5V76ScEN6BqKqZjD8Q9mEBNdQHFaP-aDEZEU0wnkALwqPU3qmkSATMXH6_4lEURsILshnSQCCPHt7HSI5LKwqRrL_C6fO7U/s867/wg_handshake_tx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="533" data-original-width="867" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_Q2KUuIeoS8nIY8J3krwQsBwRzj7myaLyIXHmjJziZ17LO5V76ScEN6BqKqZjD8Q9mEBNdQHFaP-aDEZEU0wnkALwqPU3qmkSATMXH6_4lEURsILshnSQCCPHt7HSI5LKwqRrL_C6fO7U/w400-h246/wg_handshake_tx_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.13] handshake message tx flow</div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr8yEZUsDjTHbW34Do0jmOLYBdvF-SoPvuBrdCzKR8F-Ko1clPIaDWw3K_81c7ggGyRSNaYSlaLcBlwcfZC6InGT1AInxadiV4-eLxiP8ge7ZY-dhynFH-c3uhDKIoBonVeHgzeUYQmwIX/s986/wg_handshake_rx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="538" data-original-width="986" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr8yEZUsDjTHbW34Do0jmOLYBdvF-SoPvuBrdCzKR8F-Ko1clPIaDWw3K_81c7ggGyRSNaYSlaLcBlwcfZC6InGT1AInxadiV4-eLxiP8ge7ZY-dhynFH-c3uhDKIoBonVeHgzeUYQmwIX/w400-h219/wg_handshake_rx_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.14] handshake message rx flow</div></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfqs2B5-LMUxpnTRml63HohLnFDcAHGbdcFS1xkfQLFVtZCcwdqgzKK_j3cwcTmc16sloqTN4ewK3U-a70FeHcU0VslOidayYRnuYdK2PA33EV1sl_PSqsvvLvFmdGCq-8rq403EvLFeLZ/s542/wg_packet_tx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="542" data-original-width="487" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfqs2B5-LMUxpnTRml63HohLnFDcAHGbdcFS1xkfQLFVtZCcwdqgzKK_j3cwcTmc16sloqTN4ewK3U-a70FeHcU0VslOidayYRnuYdK2PA33EV1sl_PSqsvvLvFmdGCq-8rq403EvLFeLZ/s320/wg_packet_tx_flow.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.15] data message tx flow</div></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzEx59qyBwaCJk4vH5-a_glRwdv7IMap16o8GuS4oSHSExDKgS-ZJ1i95SY_4JDfnZGwSqhtS2bzfKYysJEvW0jRCvS6lB-sg6kQvfRH9xDQo8Ki5BDRKTiO5Kw97R4Nrh0_qXyWAidDXj/s787/wg_packet_rx_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="612" data-original-width="787" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzEx59qyBwaCJk4vH5-a_glRwdv7IMap16o8GuS4oSHSExDKgS-ZJ1i95SY_4JDfnZGwSqhtS2bzfKYysJEvW0jRCvS6lB-sg6kQvfRH9xDQo8Ki5BDRKTiO5Kw97R4Nrh0_qXyWAidDXj/w400-h311/wg_packet_rx_flow.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.16] data message rx flow</div></div><div><span style="text-align: center;"><br /></span></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 위의 tx/rx flow 내용 중 대괄호([ ])로 표시된 부분은 worker function에 해당한다.</span></b></div><div><br /></div><div>Wireguard는 public key 기반으로 운용되는 hash table과 index 기반으로 운용되는 hash table 두개를 가지고 있다. hash table의 operation과 관련해서는 peerlookup.c 파일에 정의되어 있는데, 이중 아래 두개의 함수는 각각의 table로 부터 원하는 entry를 찾는데 사용하는 lookup 함수를 보여준다. 언제 public key로 lookup을 하고, 언제 index를 가지고 lookup을 하는지를 확인(이는 다른 파일에서 호출함)해 보면 이 두함수가 왜 필요한지를 바로 알 수 있을 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh7QhRzWjJNKHTmuH1s2i4gGNvBxtFVt8Gk40uetSlcTtbex_8pXdYPVs2KO4MkpkjLZrO3w3JwQNKdYhhijx02LZuPo1Bj06KuKNcBhpHwWVbi8N1ayBlUvqXVm4e8ZCWs0uz-8A4d2b-/s660/wg_publickey_hash_table.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="378" data-original-width="660" height="229" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhh7QhRzWjJNKHTmuH1s2i4gGNvBxtFVt8Gk40uetSlcTtbex_8pXdYPVs2KO4MkpkjLZrO3w3JwQNKdYhhijx02LZuPo1Bj06KuKNcBhpHwWVbi8N1ayBlUvqXVm4e8ZCWs0uz-8A4d2b-/w400-h229/wg_publickey_hash_table.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.17] wg_pubkey_hashtable_lookup( ) 함수 - <span style="text-align: left;"><b>peerlookup.c</b></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwHl46mvoyUnvIE8lpvEfle6YXiAuNS9zCABcsatulhLE8_TtWB_k5Nh7OvMtrMfVxBOOkR083e7RY1Au7sD4wGL3e2uVBYnpaJkSKhf2gwdf6O0OHWFlxKzOR9yl-wOMKGbGUcsEJMZH3/s655/wg_index_hashtable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="495" data-original-width="655" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwHl46mvoyUnvIE8lpvEfle6YXiAuNS9zCABcsatulhLE8_TtWB_k5Nh7OvMtrMfVxBOOkR083e7RY1Au7sD4wGL3e2uVBYnpaJkSKhf2gwdf6O0OHWFlxKzOR9yl-wOMKGbGUcsEJMZH3/w400-h303/wg_index_hashtable.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.18] <span style="text-align: left;">wg_index_hashtable_lookup(</span> ) 함수 - <b style="text-align: left;">peerlookup.c</b></div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 wireguard는 망 변경으로 peer의 ip 주소가 변경되더라도 tunnel이 유지되는 특징이 있다. 이것이 가능한 이유는 index 기반으로 peer hash table이 운용되기 때문이다. 1장에서 Receiver index가 message format에 있었다는 사실을 상기해 보라. 이 Receiver index가 index hash table에서 사용되는 index 값이다.</span></b><span style="color: #ff00fe;"> </span></div><div><br /></div><div>이상으로 (만족스럽지는 못하지만) 아주 간략하게 나마 WireGuard kernel code를 분석해 보았다. 코드량이 많지 않으니, 부족한 부분은 독자 여러분이 직접 분석해 보시기 바란다.</div><div><br /></div><div><span style="background-color: #fcff01;">최근(2023년 2월)에 wireguard kernel code를 좀 더 분석해 보았다. 😎</span></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html">https://slowbootkernelhacks.blogspot.com/2023/02/nanopi-r4s-pq-wireguard-vpn-router.html</a></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#3d85c6" size="6">5. WireGuard VPN 활용 예(Use Cases)</font></b></div><div>이렇게 좋은 WireGuard VPN을 (일반적인 VPN 용도 말고) 어디에 활용하면 좋을까 ?</div><div><br /></div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.1) 이동중인 차량 내부에 설치한 IP Camera가 보내온 실시간 영상을 원거리에서 안전하게 보고 싶다면 ?</span></b></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC2tMv4GeIU9M_X1S933-Vjm5kRzWiPMZW4K9u7qKcRENu8BjuuztYwiImo2970x7aTaOqBfgSGGpLsC9uKkUN7l_gKJfNCe0nSdDrUsCeon-36Wv2fHKWXKmEnUGcWoWhppVNt-O_nabJ/s1126/endsec1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="586" data-original-width="1126" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhC2tMv4GeIU9M_X1S933-Vjm5kRzWiPMZW4K9u7qKcRENu8BjuuztYwiImo2970x7aTaOqBfgSGGpLsC9uKkUN7l_gKJfNCe0nSdDrUsCeon-36Wv2fHKWXKmEnUGcWoWhppVNt-O_nabJ/w400-h209/endsec1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.1] Video Surveillance(왼쪽 노란 box <=> 오른쪽 빨간 box)</div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 달리는 차를 예로 들었지만, 가정에 설치한 IP camera를 외부에서 Smart Phone으로 확인해 보는 것도 가능하다.</span></b></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.2) 산업 현장의 장비를 원격으로 제어하고 싶다면 ?</span></b></b></div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdxLzen8INdQKcKBFCnqTgK6mPsURhZNXmS4qiw4U2yaGGwAQpE9GTEPjczUpE1cgImmG9JSfzZyE7tUGN5ceKATdX52GONEZ6fqzv2AzbAwkJ2zwbDIru5lQAJ04gKAQ7B-JfZa9jV_PZ/s1169/endsec2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="1169" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdxLzen8INdQKcKBFCnqTgK6mPsURhZNXmS4qiw4U2yaGGwAQpE9GTEPjczUpE1cgImmG9JSfzZyE7tUGN5ceKATdX52GONEZ6fqzv2AzbAwkJ2zwbDIru5lQAJ04gKAQ7B-JfZa9jV_PZ/w400-h191/endsec2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.2] Industrial IoT 통신 보안(왼쪽의 검정 box <=> cloud, cloud <=> notebook/phone)</div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 산업 현장의 장치는 RS485, CAN, Ethernet, Wi-Fi, BLE, ZigBee 등 다양한 connectivity 조건을 요구한다.</span></b></div><div><br /></div><div><br /></div><div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.3) 이동중인 차량에서 보내온 데이타(Coldchain)를 안전하게 받아 분석하고 싶다면 ?</span></b></b></div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4zE8N0pcWthWLkh5OS_-inFqqaaLQ7h-n2KxHErtax-uZarTDvPuYsyqJ3v_DahH-nO0A0b5tIsQU1mvKYXqlIUK5Ge_CTN6-anVdxx24cvpOpchTq4wufZjbyZxxUTk7I_Ubiw8I7Rup/s1155/endsec3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="560" data-original-width="1155" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4zE8N0pcWthWLkh5OS_-inFqqaaLQ7h-n2KxHErtax-uZarTDvPuYsyqJ3v_DahH-nO0A0b5tIsQU1mvKYXqlIUK5Ge_CTN6-anVdxx24cvpOpchTq4wufZjbyZxxUTk7I_Ubiw8I7Rup/w400-h194/endsec3.png" width="400" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 5.3] Coldchain 환경(왼쪽 흰색 box <=> cloud, cloud <=> notebook/phone)</div><div><br /></div></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 WireGuard는 IP 주소를 기반으로 tunnel을 유지하는 것이 아니라, Public key를 기반으로 peer를 인식하기 때문에 LTE 기지국이 바뀌더라도 tunnel이 끊기지 않고 안정적으로 유지된다.</span></b></div><div><br /></div><div><br /></div><div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.4) 방화벽/공유기에 영향을 받지 않고 Online Game을 자유롭게 하고 싶다면 ?</span></b></b></div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUzNqPh3wGOksn2hW8uJH6SfNhpg_qxEVNw0X4xK0wDQOkynzBvrK36uhtQQrhpm-6XwGidmYzWDfMeWdcmGoTvs2Q9zrA5U5Bv3X5OGX6b0pBQSeq5grA9yEa4ojeMoWH72yPw5M1iJY4/s941/endsec4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="941" height="238" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUzNqPh3wGOksn2hW8uJH6SfNhpg_qxEVNw0X4xK0wDQOkynzBvrK36uhtQQrhpm-6XwGidmYzWDfMeWdcmGoTvs2Q9zrA5U5Bv3X5OGX6b0pBQSeq5grA9yEa4ojeMoWH72yPw5M1iJY4/w400-h238/endsec4.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.4] P2P 통신 - online gaming</div><div><br /></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 이러한 상황은 Game말고도 다양하게 존재한다.</span></b></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><br /></div><div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.5) POS 결제 정보를 안전하게 전달하고 싶다면 ?</span></b></b></div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiblUySaFZmo7O0nQGU59OiVQCcJznm3H5oxpifAsqRkglw8pP54998XuGfECbeO-_0NaulsG70DHEz-WrJWJ28p7U_efTQX8K11iVFIPOSY-rrl1r9stMAmH5vjGGZjKw6coh6FeJZdqoT/s1004/endsec5.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="449" data-original-width="1004" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiblUySaFZmo7O0nQGU59OiVQCcJznm3H5oxpifAsqRkglw8pP54998XuGfECbeO-_0NaulsG70DHEz-WrJWJ28p7U_efTQX8K11iVFIPOSY-rrl1r9stMAmH5vjGGZjKw6coh6FeJZdqoT/w400-h179/endsec5.png" width="400" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 5.5] POS 결제 정보 보호</div><div><br /></div></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 물론 POS의 경우 이미 자체 방식으로 결제 데이타를 암호화해서 전달하고 있는 것으로 알고 있다. 하지만, WireGuard를 이용한다면 한단계 더 안전한 통신 보안이 가능할 것으로 믿는다.</span></b></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;"><br /></span></b></div><div><b style="text-align: center;"><b style="text-align: left;"><span style="color: #38761d;">1.6) 달리는 기차 위에서 안정적으로 사내망에 접속하고 싶다면 ?</span></b></b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsuUcVK9ODHS2aWMHHMzc7r1ydnpRHNhgYGtwivIgDf-Jlnu-P7Uor5gVZVDqTWQfjlE-XjtuH8HDTTHFHldtKHvwfjTP7jAGmBpmmuODF_UUUnxYo_ZNgW83oOVcDCTY8EHj-f7om1hzq/s1214/endsec6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="548" data-original-width="1214" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsuUcVK9ODHS2aWMHHMzc7r1ydnpRHNhgYGtwivIgDf-Jlnu-P7Uor5gVZVDqTWQfjlE-XjtuH8HDTTHFHldtKHvwfjTP7jAGmBpmmuODF_UUUnxYo_ZNgW83oOVcDCTY8EHj-f7om1hzq/w400-h180/endsec6.png" width="400" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 5.6] LTE 기지국이 변경되어도 Tunnel이 유지(왼쪽 흰색 box <=> 오른쪽 검정 box)</div><div><br /></div></div><div><div><b style="color: #ff00fe; text-align: center;"><span style="background-color: white; font-size: 14.85px; font-weight: 400; text-align: left;">📌 WireGuard는 IP 주소를 기반으로 tunnel을 유지하는 것이 아니라, Public key를 기반으로 peer를 인식하기 때문에 LTE 기지국이 바뀌더라도 tunnel이 끊기지 않고 안정적으로 유지된다.</span></b></div></div><div>__________________________________</div><div><br /></div><div>이상과 같이 WireGuard VPN의 가능성은 실로 무궁무진하다고 말할 수 있겠다. 어떤가 ~ WireGuard를 사용할 준비가 되었는가 ? 😀</div><div><br /></div><div><br /></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/spnhacks/blob/master/IoTSec_Products10.pdf"><b><span style="font-size: medium;">vIoTSec - Virtual IoT Security Platform</span></b></a></div><div><br /></div><div><br /></div><div><div><div><b><font color="#3d85c6" size="6">6. References</font></b></div></div><div>[1] <span style="color: #0b5394;">https://www.wireguard.com/papers/wireguard.pdf</span></div><div>[2]<span style="color: #0b5394;"> </span><span>WireGuard - Fast, Modern, Secure VPN Tunnel, Jason A. Donenfeld</span></div><div>[3] <span style="color: #990000;">Master’s Thesis - Analysis of the WireGuard protocol, Peter Wu</span></div><div>[4] Tiny WireGuard Tweak, Jacob Appelbaum, Chloe Martindale, and Peter Wu</div><div>[5] 스토리로 이해하는 암호화 알고리즘, 김수민, 로드북</div><div>[6] <a href="https://github.com/ChunghanYi/spnhacks/blob/master/IoTSec_Products3.pdf">vIoTSec - Virtual IoT Security Platform</a>, Slowboot</div><div>[7] <a href="https://github.com/ChunghanYi/spnhacks/blob/master/misc/Crypto_Algorithms2.pdf" style="text-align: center;">https://github.com/ChunghanYi/spnhacks/blob/master/misc/Crypto_Algorithms2.pdf</a>, Slowboot</div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#38761d">SlowBoot</font></b></div></div><div><b><font color="#38761d"><br /></font></b></div></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com2tag:blogger.com,1999:blog-6346200245600677355.post-10922688691921644752020-09-25T13:52:00.001+09:002020-09-26T15:17:29.167+09:00ESPRESSObin Ultra 보드와 MACCHIATObin 보드의 Switch & Ethernet Device Driver 분석(3)<p>이번 시간(세번째 시간)에는 지난 시간에 이어, <a href="https://macchiatobin.net/">MACCHIATObin 보드</a> 상에서 <a href="https://www.ntop.org/products/n2n/">n2n - Layer 2 peer to peer VPN</a>을 구동시키는 방법을 소개해 보고자 한다.</p><div class="separator" style="clear: both; text-align: center;"><b><span style="color: #e69138; font-size: large;"> n2n </span></b></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv7SAhwDMWc6jGw-aKppJSVCZu_lszPJOw4Odvvpgp6G5fLd7_9tjbS-xrpZ4W4oc3WHatbsauZwBwSiH1Bjn8RU0rJ1cMmtdezAec7zqEsO7TznIKXjxC-SFDrF0LsQOO21l0R3cRauDi/s414/mcbin_doubleshot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="296" data-original-width="414" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv7SAhwDMWc6jGw-aKppJSVCZu_lszPJOw4Odvvpgp6G5fLd7_9tjbS-xrpZ4W4oc3WHatbsauZwBwSiH1Bjn8RU0rJ1cMmtdezAec7zqEsO7TznIKXjxC-SFDrF0LsQOO21l0R3cRauDi/w146-h138/mcbin_doubleshot.png" width="146" /></a> <img border="0" data-original-height="280" data-original-width="266" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo9x_6yQT9qiPjxK5inpQBF1Tnq3Ky5CQr2ta8XuAXWF78BLfuOF4cfkimx57R6KULc6OrzaOpHZ6Ec1-Ky8Mod1b4Cyfvdcve2RV_uPEPFnOfVDexmA-RTtPkETHV13zSAVfZynfswstd/w115-h128/10-109278_transparent-vpn-png-vpn-lock-png-download.png" width="115" /> <img border="0" data-original-height="225" data-original-width="225" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgERdCNEVQMSTGL1mcBbNBfGvt3tIHClO9HCErxtqilM4xp9uMwsGR09dpnzN6Wbm-xjyFxqX8WGnrZevHdBqHG7FtvlrzS2fdVltbOVyiVdEoDVMBCNmVYyHVTVdZTKovlLSP7_iM2JqYi/w133-h133/mango.jpeg" style="text-align: left;" width="133" /></div><br /></div><div><br /></div><div><b><span style="font-size: medium;">목차</span></b></div><div><i>1. Docker 환경 설정</i></div><div><i>2. ESPRESSObin Ultra 보드 소개</i></div><div><i>3. ESPRESSObin Ultra 보드의 Switching Device Driver 분석</i></div><div><i>4. MACCHIATObin 보드 소개</i></div><div><i>5. </i><i>MACCHIATObin 보드의 </i><i>Ethernet Device Driver 분석</i></div><div><i>6. 응용편1: </i><span style="color: #444444;"><i>MACCHIATObin 보드를 </i><i>SoftEther VPN Gateway로 만들기</i></span></div><div><b><i>7. 응용편2: </i><i style="color: #444444;">MACCHIATObin 보드를 P2P VPN Gateway로 만들기</i></b></div><div><i>8. References</i></div><div><br /></div><div><br /></div><div><div><br /></div><div><b><font color="#3d85c6" size="6">7. 응용편2: MACCHIATObin 보드를 P2P VPN Gateway로 만들기</font></b></div><div>이번 장에서는 Layer 2 Peer to Peer VPN project 중 하나인 n2n을 MACCHIATObin 보드에서 동작시키는 과정을 소개해 보고자 한다.</div></div><div style="text-align: center;"><br /></div><div><span style="color: #38761d; font-size: medium;"><b>7.1) n2n project 소개</b></span></div><div><a href="https://www.ntop.org/">ntop project</a> 중의 하나인 n2n은 아래와 같은 특징을 갖는 P2P VPN이다.</div><div style="text-align: center;"><a href="goog_1815857175"><br /></a></div><div style="text-align: center;"><a href="https://www.ntop.org/products/n2n/">https://www.ntop.org/products/n2n/</a></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>a) NAT 장비 안쪽에 있는 두 peer(host or user)가 NAT 장비에 영향을 받지 않고 서로 완벽하게 통신하도록 만들어 준다. 즉, NAT 장비에서 port forwarding or DMZ 설정을 전혀 해 줄 필요가 없다. </div><div> <i> => 또한 port forwarding/DMZ 등으로도 연결 안되는 문제까지 해결해 준다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAV2dIXT6Nn3_XwKKJx3z6f08L_KN4I7SNXRLCnyL1OPLwTkIDZqme-72r5we9_NjtdGQeAR72n5vgQ9LzdBkNhyn8ARSJKF4iU_zjrqq4E4V89wp0YfzYMjmkjYpjKLE6mZskXoORpTSq/s1000/n2n_nat_and_home.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="456" data-original-width="1000" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAV2dIXT6Nn3_XwKKJx3z6f08L_KN4I7SNXRLCnyL1OPLwTkIDZqme-72r5we9_NjtdGQeAR72n5vgQ9LzdBkNhyn8ARSJKF4iU_zjrqq4E4V89wp0YfzYMjmkjYpjKLE6mZskXoORpTSq/s320/n2n_nat_and_home.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.1] NAT and home <b>[출처: 참고 문헌 12]</b></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 NAT가 사용되는 환경은 가정에 설치된 공유기, 회사에 설치된 Firewall, LTE망과 Internet을 연결해 주는 CGN(Carrier Grade NAT, Firewall), Smart Phone USB Tethering 등 다양하다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 IPv4 환경이 IPv6로 모두 전환되기 전까지는 NAT가 어쩔 수 없이 존재한다. 따라서 n2n과 같은 solution이 필요할 수밖에 없다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>b) edge(peer에 설치)와 supernode(public ip를 갖는 중앙의 서버)라는 2개의 daemon으로 구성되어 있다.</div><div><i> => edge가 설치되면, 이를 사용하는 application의 코드를 전혀 수정할 필요가 없다. 즉, application transparency를 보장한다.</i></div><div><i> => MQTT, HTTP 등의 IoT protocol을 사용하는 application에 대해 코드 수정 없이 사용이 가능하다.</i></div><div><i><br /></i></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoZ_H0h82a5rXkWxYKysPfu20Z3x-DW-8m_CKhP-Ol59bbSGPGTl5SemDlCFs8Z4RTi8UrvmzeipBkQxXAw75GRlhblFzZD8tLqVButOYk_v_XeK62MZYYhOrnTfzsJe9wNGgVOnlQkRkD/s417/n2n_arch1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="285" data-original-width="417" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoZ_H0h82a5rXkWxYKysPfu20Z3x-DW-8m_CKhP-Ol59bbSGPGTl5SemDlCFs8Z4RTi8UrvmzeipBkQxXAw75GRlhblFzZD8tLqVButOYk_v_XeK62MZYYhOrnTfzsJe9wNGgVOnlQkRkD/s320/n2n_arch1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.2] n2n의 구조2(edge와 supernode로 구성) <b>[출처: 참고 문헌 11]</b></div></div><div><br /></div><div>c) Full cone NAT에 대해서는 hole punching도 지원하며, symmetric NAT가 있는 경우(hole punching이 불가한 경우)에는 supernode를 통한 relay가 지원된다.</div><div><i> => Smart Phone <=> Smart Phone 간의 1:1 direct 통신도 가능하다.</i></div><div><i><br /></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4ot2HC4vATYQWfLAeaXa3d8ijfBiNLQ_KRdEpBsvUmzVa3ivn9PeBKyNinUCVwfEeTLU3BNl37gc9i3IffDiHV88wjdqa6voknILKQpUJix0DhmaZpKBMhi8OI_xJFpHoLDtXmFToiUcW/s537/n2n_arch3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="227" data-original-width="537" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4ot2HC4vATYQWfLAeaXa3d8ijfBiNLQ_KRdEpBsvUmzVa3ivn9PeBKyNinUCVwfEeTLU3BNl37gc9i3IffDiHV88wjdqa6voknILKQpUJix0DhmaZpKBMhi8OI_xJFpHoLDtXmFToiUcW/s320/n2n_arch3.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.3] n2n의 구조1(edge와 supernode로 구성) <b>[출처: 참고 문헌 11]</b></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 NAT hole punching & relay 기법과 관련해서는 아래 site를 참조하기 바란다.</span></div><div style="text-align: center;"><a href="https://www.netmanias.com/ko/post/blog/6263/nat-network-protocol-p2p/p2p-nat-nat-traversal-technic-rfc-5128-part-2-udp-hole-punching">https://www.netmanias.com/ko/post/blog/6263/nat-network-protocol-p2p/p2p-nat-nat-traversal-technic-rfc-5128-part-2-udp-hole-punching</a></div><div><br /></div><div>d) 하나의 peer는 복수개의 다른 peer와 각각 서로 다른 vpn tunnel을 통해 통신할 수 있다.</div><div><i> => community 명을 통해 각각의 tunnel을 구분해 줄 수 있다.</i></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3r2FfHZ3ek6tCCml4v5lb3nzLvXo5FT6QcX9OXDOHcebtv0k4ZE6TLyMtdvrNZtIzf-hrtj5MjYTju5LF0xI9K_enJl6CzYGdz_dOo2KFfOh1DnRgmoQzQH7rT7vmgVWj-3YIwIEbFOXB/s885/n2n_community.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="653" data-original-width="885" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3r2FfHZ3ek6tCCml4v5lb3nzLvXo5FT6QcX9OXDOHcebtv0k4ZE6TLyMtdvrNZtIzf-hrtj5MjYTju5LF0xI9K_enJl6CzYGdz_dOo2KFfOh1DnRgmoQzQH7rT7vmgVWj-3YIwIEbFOXB/s320/n2n_community.PNG" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.4] n2n의 그룹간 통신</div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 supernode는 edge에 할당된 network name(=community name), mac 주소(사설 주소), public NATed ip:port, private unNATed ip:port를 유지/관리한다.</span></div><div><br /></div><div>e) 두 peer는 암호화된 tunnel을 통해 ethernet frame을 통째로 암호화한 후 전달할 수 있다.</div><div><i> => ethernet frame을 전달할 수 있으므로, multicast, broadcast packet도 전달 가능하다.</i></div><div><i> => 이는 broadcast packet을 사용하는 dhcp와 multicast DNS 등이 가능하다는 얘기가 된다.</i></div><div><i> => 단, multicast의 경우는 -E option을 주어야 수신이 가능하다(default: drop).</i></div><div><br /></div><div>f) 두 peer는 tunnel을 만들기 위해 tap(linux 기준) device를 이용하며, tap 기반 network interface에는 사설 ip 주소를 할당해 준다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_qXUsNRRzxuDGYxBxxG4M6G30EjZmKRV-ZVAMbg90JzhnopZZKrAwox-KiVbSu_rM04nKtFy9Uh9NZefpBm77DSEge5GHgGj1agqlx1t1lNLxrHAwZ1gj87QGICYUnr5lvJzZtdQsKN1r/s470/n2n_arch2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="268" data-original-width="470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_qXUsNRRzxuDGYxBxxG4M6G30EjZmKRV-ZVAMbg90JzhnopZZKrAwox-KiVbSu_rM04nKtFy9Uh9NZefpBm77DSEge5GHgGj1agqlx1t1lNLxrHAwZ1gj87QGICYUnr5lvJzZtdQsKN1r/s320/n2n_arch2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.5] n2n의 구조3 - tap device를 통한 ethernet frame 전달 <b>[출처: 참고 문헌 11]</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3grPZ9Asie_1dDfpenrHu66-UkY0tKBdGDjXWR001ffUn0M1W-hsI789HXj1NrjJgyHeqRW32EGctSdjAU-OxAw00gsFgIxJFxXvhTfhS1IOZ8Tv40m7mD9GpPvs2ESKMKnRdOngcabuf/s282/openvpn_arch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="179" data-original-width="282" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3grPZ9Asie_1dDfpenrHu66-UkY0tKBdGDjXWR001ffUn0M1W-hsI789HXj1NrjJgyHeqRW32EGctSdjAU-OxAw00gsFgIxJFxXvhTfhS1IOZ8Tv40m7mD9GpPvs2ESKMKnRdOngcabuf/s0/openvpn_arch.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.6] OpenVPN의 동작 방식 - n2n도 동일한 방식으로 동작함.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 위의 그림에서 tun0를 tap0로, OpenVPN을 edge로 변경한 것이 n2n이라고 보면 된다. 물론, 중앙에 별도의 supernode가 있어야 하지만 ...</span></div><div><br /></div><div>g) 암호화 알고리즘으로는 twofish, aes, chacha20, speck 등을 지원한다(단, 최신 버젼 2.9 기준임)</div><div><i> => 이 부분은 key 교환 방식과 더불어 최근에 한창 개발 중에 있다.</i></div><div><i> => IKE 등을 지원하려는 것 같은데, 아직까지는 key 교환 관련하여 기능이 신통치 못한 것 같다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoY8q6z0COvHlUkQk63Q7ADqdv3Hm5ykNjTX_sMX1QruVJk3A9U4RwaeRnFvPsThyphenhyphen2xirXa_T30TcAMm4FeFg9GIeoSS3Je8dIkWEJ68N_ZC2Md49yNrOrAbQGjmYk7SqODboC4l0YWPk_/s963/n2n_crypto.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="236" data-original-width="963" height="157" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoY8q6z0COvHlUkQk63Q7ADqdv3Hm5ykNjTX_sMX1QruVJk3A9U4RwaeRnFvPsThyphenhyphen2xirXa_T30TcAMm4FeFg9GIeoSS3Je8dIkWEJ68N_ZC2Md49yNrOrAbQGjmYk7SqODboC4l0YWPk_/w640-h157/n2n_crypto.png" width="640" /></a></div><div><br /></div><div>h) 속도 문제를 해결하기 위해 다음의 두가지 압축 알고리즘도 제공한다(2.9 version 기준).</div><div><i> => lzo1x, zstd 지원 </i></div><div><br /></div><div>i) Windows, macOS, Android 버젼을 지원한다.</div><div><i> => 단, Windows, Android는 (상용 버젼 수준으로 만들려면) 약간의 개조가 필요하다.</i></div><div><br /></div><div>j) 설정이 아주 간단하고, 사용하기 매우 쉽다.</div><div><br /></div><div>k) 단점: tun/tap device를 사용하여 tunnel/암호화(그림 7.5-7.6)를 하다보니, 느릴 수 밖에 없다(OpenVPN이 느린 이유와 동일함). 더더군다나 중앙에 supernode를 통해 relay를 해야 하는 경우에는 더 느려질 수 밖에 없다.</div><div><i> <span style="color: #b45f06;"> => 그럼에도 불구하고, 사용할만한 가치가 있어 보인다.</span></i></div><div><i><span style="color: #b45f06;"> => (좀 느리지만) NAT 장비에 영향을 받지 않고 game을 하고자 할 경우 적합.</span></i></div><div><i><span style="color: #b45f06;"> => 역시 NAT 장비의 설정 변경 없이 client -> server(예: ssh, ftp ..) 연결에 적합.</span></i></div><div><i><span style="color: #b45f06;"> => 24시간 운용 서비스 보다는 특정 시점에 연결하여 사용하는 경우에 적합할 듯 보임.</span></i></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 아래 내용은 scp를 이용하여 1Gbit/s 환경에서 n2n의 속도를 측정한 결과이다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div style="text-align: center;"><n2n performance - scp를 이용하여 테스트> <b>[출처: 참고 문헌 12]</b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLEfquzZoM8hBSLfDPMYkk95DLfSLsPPhTdTn6KPCppLuRCC8Uoj5WSY0nqOKAAXc8RGABIk0aUJuqv-cCpaYSKUbnNoHvOEEj9xXi0chcPKDEHTdZc3kXovPvKwxIrZN2YV4WleLVALOP/s692/n2n_performance.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="261" data-original-width="692" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLEfquzZoM8hBSLfDPMYkk95DLfSLsPPhTdTn6KPCppLuRCC8Uoj5WSY0nqOKAAXc8RGABIk0aUJuqv-cCpaYSKUbnNoHvOEEj9xXi0chcPKDEHTdZc3kXovPvKwxIrZN2YV4WleLVALOP/s320/n2n_performance.png" width="320" /></a></div><div><br /></div><div>n2n 관련 보다 자세한 사항은 아래 n2n 공식 home page의 내용을 참고하기 바란다.</div><div style="text-align: center;"><a href="https://www.ntop.org/products/n2n/">https://www.ntop.org/products/n2n/</a></div><div style="text-align: center;"><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 참고로 n2n은 Hamachi와 유사하게 동작하는 program이다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><br /></div><div><div><span style="color: #38761d; font-size: medium;"><b>7.2) ARM64용으로 n2n build하기</b></span></div><div>그럼, 지금부터는 arm64 환경에서 동작 가능하도록 n2n를 cross-compile해 보도록 하겠다. 6장과 동일하게 docker(ubuntu 16.04) 환경에서 build를 진행해 보기로 하자.</div></div><div><br /></div><div><b style="background-color: #fff2cc;"><Docker ubuntu 16.04></b></div><div><div>root@23dc5a9270fd:/# su - chyi</div><div>$ <b>export PATH=/home/chyi/workspace/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin:$PATH</b></div><div><i> => arm64용 toolchain path를 지정한다.</i></div><div>$ <b>export CROSS=aarch64-linux-gnu-</b></div><div><br /></div><div>$ <b>cd ~/workspace/vpn/n2n-2.8</b></div><div><i> => 미리 download 받아 둔, n2n-2.8 directory로 이동하자.</i></div><div><i> => 이 글을 쓰는 현재 n2n-2.8이 stable version이다.</i></div><div><br /></div><div>$ <b>./autogen.sh</b></div><div><i> => autoreconf가 없다는 에러가 발생한다면 아래 package를 설치해 주자.</i></div><div><div><span style="color: #666666;"># </span><b><span style="color: #0b5394;">apt-get install autoconf</span></b></div><div><br /></div></div><div>$ <b>./configure --build x86_64-pc-linux-gnu --host aarch64-linux-gnu</b></div><div>$ <b>make clean</b></div><div>$ <b>CC="$CROSS"gcc AR="$CROSS"ar RANLIB="$CROSS"ranlib make</b></div></div><div><br /></div><div><div><div>chyi@23dc5a9270fd:~/workspace/vpn/n2n-2.8$ <b>file edge</b></div><div><b> </b><i> => 정상적으로 cross-compile이 되었다면 아래 처럼 출력될 것이다.</i></div><div><span style="color: #3d85c6; font-size: x-small;">edge: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=ca3f341915a34f6fdd980a5020a44bfd66371898, not stripped</span></div><div><br /></div><div>chyi@23dc5a9270fd:~/workspace/vpn/n2n-2.8$ <b>file supernode</b></div><div><span style="color: #3d85c6; font-size: x-small;">supernode: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=22157b0e54fa825d255f963cd23356f58f5d0e6e, not stripped</span></div></div><div><br /></div></div><div>chyi@23dc5a9270fd:~/workspace/vpn/n2n-2.8$ <b>ls -l</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYz19VGlDIx-XHDUuhZvFtiP13eVl_atYT-ztPgd1gEJXsixlC-45xPEhMTTiFGyC5zydX819BgF3i9AHzZioF8Pe5DzJ38XpMhrOUkrv1FpY-qUc8nI8CGb_54iTO9lCAOQJ0uMr0OR0Z/s791/n2n_build_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="791" data-original-width="736" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYz19VGlDIx-XHDUuhZvFtiP13eVl_atYT-ztPgd1gEJXsixlC-45xPEhMTTiFGyC5zydX819BgF3i9AHzZioF8Pe5DzJ38XpMhrOUkrv1FpY-qUc8nI8CGb_54iTO9lCAOQJ0uMr0OR0Z/s320/n2n_build_output.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.7] n2n source code 및 build 결과</div><div><div><br /></div></div><div>간단하게 build에 성공하였으니, target board로 올려 동작 테스트를 해 보기로 하자.</div><div><br /></div><div><b><span style="color: #38761d; font-size: medium;">7.3) n2n 동작 시험 1</span></b></div><div>이 절에서 시험할 네트워크 환경은 다음과 같다.</div><div><br /></div><div><div><b style="background-color: #d9ead3;"><Testbed 1></b></div><div style="text-align: center;">Linux PC A(<b><span style="color: #0b5394;">192.168.1.49/24</span></b>, n2n edge1: <b><span style="color: #990000;">10.1.2.1</span></b>) => LTE Router => Internet </div><div style="text-align: center;">Linux PC B(<b><span style="color: #0b5394;">192.168.2.100/24</span></b>) => MACCIATObin(<b><span style="color: #0b5394;">192.168.2.1/24</span></b>, n2n edge2:<b><span style="color: #990000;">10.1.2.2</span></b>) => Repeater => AP => Internet</div></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>외부에 서버를 운영할 환경이 안되므로, supernode는 ntop에서 운영하는 supernode.ntop.org를 활용하기로 한다. 만일 이를 직접 운영하고자 한다면 아래와 같이 간단하게 실행해주면 된다.</div><div><br /></div><div><span style="background-color: #d0e0e3;"><b><Public ip를 가진 서버></b></span></div><div>$<b> sudo ./supdernode -l <port></b></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><span style="font-size: 14.85px;">📌 AWS EC2 1년 무료 버젼을 사용하면 간단한 서버를 운영할 수 있긴하다.</span></span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><span style="color: black; font-size: medium;">supernode가 준비되었으니, edge binary를 target board로 복사한 후, 아래 명령을 실행해 주도록 하자.</span></span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><span style="color: black; font-size: medium;"><br /></span></span></div><div><b style="background-color: #d0e0e3;"><Target board: <span style="color: #b45f06;">edge2</span>></b></div><div>root@localhost:/home/chyi/workspace# <b>./edge -c mynetwork -k mysecretpass -a 10.1.2.2 -r -l supernode.ntop.org:7777 -A2 -z1 -f</b></div><div><i><span style="color: #0b5394;"> => -c : community 명을 mynetwork으로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -k : shared 암호키를 mysecretpass로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => vpn ip를 10.1.2.2로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -r : n2n virtual lan을 통한 ip forwarding을 enable 시켜준다.</span></i></div><div><i><span style="color: #0b5394;"> => -l : supernode ip:port를 ntop에서 운영하는 supernode.ntop.org:7777를 입력하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -A2: twofish 암호 알고리즘으로 설정한다.</span></i></div><div><i><span style="color: #0b5394;"> => -z1: lzo1x 압축 알고리즘을 사용하도록 설정한다.</span></i></div><div><i><span style="color: #0b5394;"> => -f: foreground로 동작하도록 한다.</span></i></div><div><i><span style="color: #0b5394;"> => -d option을 생략한 관계로 edge0라는 tap interface가 자동으로 생성된다.</span></i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTMgsirhYvN2dEUkwfGxDfjprFMsrwGan66h6AIQuPCGpDW6W2Mk291IPfPXHEqGe3K8nPWYRQ6zPtCt5G7o2aryuMU4ElrBqis5HR65L7KYUWElG_quspsqEU1qcrSa8tcRiOHsHERP-x/s923/n2n_mcbin_edge2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="923" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTMgsirhYvN2dEUkwfGxDfjprFMsrwGan66h6AIQuPCGpDW6W2Mk291IPfPXHEqGe3K8nPWYRQ6zPtCt5G7o2aryuMU4ElrBqis5HR65L7KYUWElG_quspsqEU1qcrSa8tcRiOHsHERP-x/w400-h284/n2n_mcbin_edge2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.8] MACCHIATObin에서 edge(edge2)를 실행한 모습</div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 참고로 암호 알고리즘을 위한 option은 다음과 같다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"> -A2: Twofish(CTS mode), -A3: AES(CBC mode), -A4: ChaCha20(CTR mode), -A5: SPECK(CTR mode)</span></div><br /><div><div>root@localhost:/home/chyi/workspace# <b>sysctl -w net.ipv4.ip_forward=1</b></div><div><i> => ip forwarding을 1로 설정한다.</i></div></div><div><br /></div><div>root@localhost:~# <b>iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE</b></div><div><i> => MACCHIATObin 내부의 PC가 internet에 접속할 수 있도록 masquerading 설정을 해 준다.</i></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 edge -h 명령을 실행하면 사용 가능한 자세한 option을 확인할 수 있다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgODLWhWjKytBdoXxcx99pVHR2qmOSn8Xe0YoErr1XGIukrHMSD4OUJUKWWF089hudvra5A8Zm9cZasFNTTNZ1XJk_29NiZG-3CMHK2_BQVHMistYAqa6UrVgj_CxUe5r93zeD6hbCNOBWr/s931/edge_help.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="922" data-original-width="931" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgODLWhWjKytBdoXxcx99pVHR2qmOSn8Xe0YoErr1XGIukrHMSD4OUJUKWWF089hudvra5A8Zm9cZasFNTTNZ1XJk_29NiZG-3CMHK2_BQVHMistYAqa6UrVgj_CxUe5r93zeD6hbCNOBWr/w400-h396/edge_help.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.9] edge에서 사용 가능한 option 확인</div></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><br /></div><div><b style="background-color: #d0e0e3;"><Linux PC A: <span style="color: #b45f06;">edge1</span>></b></div><div>$ <b>./edge -c mynetwork -k mysecretpass -a 10.1.2.1 -l supernode.ntop.org:7777 -A2 -z1 -f</b></div><div><div><i><span style="color: #0b5394;"> => -c : community 명을 mynetwork으로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -k : shared 암호키를 mysecretpass로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => vpn ip를 10.1.2.1로 지정하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -l : supernode ip:port를 ntop에서 운영하는 supernode.ntop.org:7777를 입력하였다.</span></i></div><div><i><span style="color: #0b5394;"> => -A2: twofish 암호 알고리즘으로 설정한다.</span></i></div><div><i><span style="color: #0b5394;"> => -z1: lzo1x 압축 알고리즘을 사용하도록 설정한다.</span></i></div><div><i><span style="color: #0b5394;"> => -f: foreground로 동작하도록 한다.</span></i></div><div><i><span style="color: #0b5394;"> => -d option을 생략한 관계로 edge0라는 tap interface가 자동으로 생성된다.</span></i></div></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 Linux PC A는 gateway가 아니므로 -r option을 사용할 필요가 없다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-XS30SvYHOguJrTsqkZukG9IbLutRT5z_gQA73tIVZypOcbLLoftHkvCnJV1LNA752FDrK1RMPOFV3fPsvK7nZfCjNmxF0QvPpYAHG3iI8nP-07PJqizGWL34fUO_pmktRhGZxTwKKMo7/s1021/n2n_edge1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="564" data-original-width="1021" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-XS30SvYHOguJrTsqkZukG9IbLutRT5z_gQA73tIVZypOcbLLoftHkvCnJV1LNA752FDrK1RMPOFV3fPsvK7nZfCjNmxF0QvPpYAHG3iI8nP-07PJqizGWL34fUO_pmktRhGZxTwKKMo7/w400-h221/n2n_edge1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.10] Linux PC edge(edge1)를 실행한 모습</div><div><br /></div><div>$ <b>sudo ip route add 192.168.2.0/24 via 10.1.2.2</b></div><div><i> => Linux PC A(edge1)에서 MACCHITObin 내부의 Linux PC B로 routing이 가능하도록 하기 위해 위의 rule을 추가해 준다.</i></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 192.168.2.0/24 네트워크로 가기 위해서는 10.1.2.2(반대편 tunnel ip)로 보내야 한다는 뜻임.</span></div><div>_______________________________</div><div><br /></div><div>n2n의 모든 설정이 끝났으니, VPN이 정상적으로 동작하는지를 ping을 통해 확인해 보도록 하자.</div><div><br /></div><div><b style="background-color: #ead1dc;"><Linux PC A></b></div><div>chyi@earth:~$ <b>ping 10.1.2.2</b></div><div><i> => Linux PC A에서 edge2 vpn ip로 ping</i></div><div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=869 ttl=63 time=1126 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=870 ttl=63 time=129 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=871 ttl=63 time=234 ms</span></div></div><div><br /></div><div><div>chyi@earth:~$ <b>ping 192.168.2.100</b></div><div></div></div><div><div><i> => Linux PC A 에서 Linux PC B로 ping</i></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=863 ttl=63 time=261 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=864 ttl=63 time=459 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=865 ttl=63 time=452 ms</span></div></div><div><br /></div><div><b style="background-color: #ead1dc;"><Linux PC B></b></div><div><div>chyi@mars:~$ <b>ping 10.1.2.1</b></div><div><i> => Linux PC B 에서 edge1 vpn ip로 ping</i></div><div><span style="font-size: x-small;">PING 10.1.2.1 (10.1.2.1) 56(84) bytes of data.</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=1 ttl=63 time=680 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=2 ttl=63 time=709 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=3 ttl=63 time=950 ms</span></div></div><div><br /></div><div><b style="background-color: #ead1dc;"><MACCHIATObin target board></b></div><div><div>root@localhost:~# <b>ping 10.1.2.1</b></div><div> => target board에서 <i>edge1 vpn ip로 ping</i></div><div><span style="font-size: x-small;">PING 10.1.2.1 (10.1.2.1) 56(84) bytes of data.</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=1 ttl=64 time=691 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=2 ttl=64 time=43.8 ms</span></div><div><span style="font-size: x-small;">64 bytes from 10.1.2.1: icmp_seq=3 ttl=64 time=362 ms</span></div></div><div><br /></div><div>OK, 모두 정상 동작한다. 😃</div><div><br /></div><div><b style="background-color: #ffe599;"><여기서 잠깐 !></b><br /><i> => n2n과 openssl version에 관하여 ...</i></div><div>n2n은 AES, ChaCha20 등의 암호 알고리즘을 위해 openssl 1.1을 사용한다. 근데, Ubuntu 16.04에는 1.0.2 version이 latest version으로 설치되어 있다. 따라서 openssl 1.1.0 버젼으로 upgrade해 주어야 한다.</div><div><br /></div><div><div><b style="background-color: #d9ead3;"><Docker Ubuntu 16.04></b></div><div>chyi@23dc5a9270fd:~$ <b>openssl version</b></div><div>OpenSSL 1.0.2g 1 Mar 2016</div></div><div><br /></div><div>root@657d7cc2d58e:/home/chyi/workspace/download# <b>wget https://www.openssl.org/source/openssl-1.1.1b.tar.gz</b></div><div>root@657d7cc2d58e:/home/chyi/workspace/download# <b>tar xvzf ./openssl-1.1.1b.tar.gz; cd openssl-1.1.1b</b></div><div><br /></div><div>root@657d7cc2d58e:/home/chyi/workspace/download/openssl-1.1.1b# <b>./config</b></div><div>root@657d7cc2d58e:/home/chyi/workspace/download/openssl-1.1.1b# <b>make</b></div><div>root@657d7cc2d58e:/home/chyi/workspace/download/openssl-1.1.1b# <b>make install</b></div><div><br /></div><div>root@657d7cc2d58e:/home/chyi/workspace/download/openssl-1.1.1b# <b>export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH</b></div><div>root@localhost:/home/chyi/workspace# <b>openssl version</b></div><div>OpenSSL 1.1.1b 26 Feb 2019</div><div><br /></div><div>이 상태에서 n2n을 다시 build해 주면 된다.</div><div>____________________________________</div><div><br /></div><div><div><b><span style="color: #38761d; font-size: medium;">7.4) n2n 동작 시험 2</span></b></div></div><div>이번에는 OpenWrt를 기반으로 하는 <a href="https://www.gl-inet.com/products/gl-mt300n-v2/">Gl.iNet MT300N-V2(이하 MangoBox로 칭하겠음)</a>도 시험 네트워크에 포함시켜 보도록 하겠다.</div><div><div><br /></div><div><div><b><Testbed2: a <=> b간의 vpn></b></div><div style="text-align: center;">a) Linux PC A(<b><span style="color: #0b5394;">192.168.8.156/24)</span></b> => MangoBox(n2n edge1: <b><span style="color: #990000;">10.1.2.1</span></b>) => LTE Router => Internet </div><div style="text-align: center;">b) Linux PC B(<b><span style="color: #0b5394;">192.168.2.100/24</span></b>) => MACCIATObin(n2n edge2: <b><span style="color: #990000;">10.1.2.2</span></b>) => Repeater => AP => Internet</div></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><b>10.1.2.1 <==> 10.1.2.2</b></div><div style="text-align: center;"><b><span style="color: #990000;">192.168.8.156(Linux PC A) <==> 192.168.2.100(Linux PC B)</span></b></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFcrF2GoL8AjVumqstRrmhTmSAko73BqOwn1rKYekB4vDHupg_Ktita0P2jIFtzAzR22DZauPzJ1J574GRdzZVjkCIESuSZuFooGkuLWjehO-VGVyeNdB_yf-vhxNw1G9f9zWzZ-5u-Z3R/s364/mango.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="310" data-original-width="364" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFcrF2GoL8AjVumqstRrmhTmSAko73BqOwn1rKYekB4vDHupg_Ktita0P2jIFtzAzR22DZauPzJ1J574GRdzZVjkCIESuSZuFooGkuLWjehO-VGVyeNdB_yf-vhxNw1G9f9zWzZ-5u-Z3R/w232-h198/mango.png" width="232" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.11] Gl.iNet MT300N-V2(MangoBox)</div><div><br /></div><div>그럼, 지금부터는 아래 site의 내용을 참조하여 <span style="text-align: center;">MangoBox의 개발 환경(openwrt)을 준비해 보도록 하겠다.</span></div></div><div><span style="text-align: center;"><br /></span></div><div style="text-align: center;"><a href="https://github.com/gl-inet/openwrt">https://github.com/gl-inet/openwrt</a></div><div><br /></div><div><b style="background-color: #d0e0e3;"><Docker ubuntu 18.04></b></div><div><div><i> => 앞서와 마찬가지로 Docker 상에 설치된 ubuntu 18.04 위에 openwrt를 설치하도록 하자.</i></div><div># <b>apt-get update</b></div><div># <b>apt-get install build-essential subversion libncurses5-dev zlib1g-dev gawk gcc-multilib flex git-core gettext libssl-dev</b></div><div># <b>apt-get install unzip time</b></div><div><i> => openwrt를 위해 필요한 package를 설치해 준다.</i></div><div><br /></div><div>chyi@62ca0b4ddbc2:~/gl.inet$ <b>git clone https://github.com/gl-inet/openwrt.git openwrt</b></div><div>chyi@62ca0b4ddbc2:~/gl.inet$ <b>cd openwrt/</b></div><div>chyi@62ca0b4ddbc2:~/gl.inet$ <b>./scripts/feeds update -a</b></div><div>chyi@62ca0b4ddbc2:~/gl.inet$ <b>./scripts/feeds install -a</b></div><div><br /></div><div>chyi@62ca0b4ddbc2:~/gl.inet$ <b>make menuconfig</b></div><div><i> => target board에 맞게 설정 변경을 해준다.</i></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSuqf3pWDDqnAVgSGPFK5tAtt940IUhgmT-sZYljKaM3MGi9uHeIVCgz9I0ffijye9VZn2m6MrujFZr0TBhC0oX1y76MDzqHNpcn_5mjTu8PVOrJeJEQRPD0SPsAAzP4nanKSpZbfNcixb/s917/mango_openwrt_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="645" data-original-width="917" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSuqf3pWDDqnAVgSGPFK5tAtt940IUhgmT-sZYljKaM3MGi9uHeIVCgz9I0ffijye9VZn2m6MrujFZr0TBhC0oX1y76MDzqHNpcn_5mjTu8PVOrJeJEQRPD0SPsAAzP4nanKSpZbfNcixb/s320/mango_openwrt_menuconfig.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.12] MangoBox를 위해 target board 설정 변경</div><div><br /></div><div>chyi@62ca0b4ddbc2:~/gl.inet/openwrt$ <b>make V=s -j5</b></div><div><br /></div><div>OpenWrt가 build되었으니, 이제는 n2n을 build할 차례이다. 먼저 아래 site를 참조하여 openwrt에 설치할 n2n package 파일을 준비한다.</div><div><br /></div><div style="text-align: center;"><a href="https://github.com/MuJJus/openwrt-n2n">https://github.com/MuJJus/openwrt-n2n</a></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 위의 site 내용이 예전 n2n version을 기준으로 한 것이라, 몇가지 문제가 있다. 따라서 아래와 같이 Makefile을 적절히 수정해 주도록 하자.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQu0wC-h2-x2gHNsHuJViQ4B_i-YtVUnzFBl5HbrQRMqe_dzH0iY_EqCLuEG7dLK7ZH7_aY7cIqq2dme9PFENO7IJcW9rN9psy12G2pWmV9FpGqVMpq0FTvrrZu1OJlc6-WeF2OX06i8t/s777/n2n_openwrt_Makefile.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="777" data-original-width="777" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQu0wC-h2-x2gHNsHuJViQ4B_i-YtVUnzFBl5HbrQRMqe_dzH0iY_EqCLuEG7dLK7ZH7_aY7cIqq2dme9PFENO7IJcW9rN9psy12G2pWmV9FpGqVMpq0FTvrrZu1OJlc6-WeF2OX06i8t/w400-h400/n2n_openwrt_Makefile.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.13] n2n package를 위한 Makefile - 수정 버젼</div><div><div><br /></div><div>수정된 n2n package file을 아래와 같이 package/network/services/n2n 디렉토리에 복사한다.</div><div><br /></div><div>chyi@535261426f3a:~/gl.inet/openwrt/package/network/services/n2n$ ls -la</div><div><span style="color: #0b5394; font-size: x-small;">total 56</span></div><div><span style="color: #0b5394; font-size: x-small;">drwxrwxr-x 1 chyi chyi 4096 Sep 24 07:52 .</span></div><div><span style="color: #0b5394; font-size: x-small;">drwxrwxr-x 1 chyi chyi 4096 Sep 23 12:28 ..</span></div><div><span style="color: #0b5394; font-size: x-small;">-rw-rw-r-- 1 chyi chyi 32472 Sep 24 02:46 LICENSE</span></div><div><span style="color: #0b5394; font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1995 Sep 24 07:49 Makefile</span></div><div><span style="color: #0b5394; font-size: x-small;">drwxrwxr-x 2 chyi chyi 4096 Sep 23 12:24 files</span></div></div><div><br /></div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>make menuconfig</b></div><div><i> => 이후 menuconfig 하여, n2n를 선택해 준다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0-h51KsCgwb13l5hbFhGelabo10kPuAIdRi3pjJmSCvyTt3Ht3uTYIYcWQL158ZBlC0Nne-mC0pKjQl3X2rib1rvOCZHbjsF_bWUvu79HwF1SKNLw3AyZRT1wtQ21OexXfTNHxru4iWzS/s925/n2n_openwrt_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="760" data-original-width="925" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0-h51KsCgwb13l5hbFhGelabo10kPuAIdRi3pjJmSCvyTt3Ht3uTYIYcWQL158ZBlC0Nne-mC0pKjQl3X2rib1rvOCZHbjsF_bWUvu79HwF1SKNLw3AyZRT1wtQ21OexXfTNHxru4iWzS/s320/n2n_openwrt_menuconfig.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.14] n2n-edge, supernode 선택 화면</div><div><br /></div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>make package/network/services/n2n/configure</b></div><div><i> => n2n 최신 버젼에서는 autogen.sh 후 configure를 해 주어야 한다.</i></div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>make package/network/services/n2n/compile -j1 V=s</b></div><div><i> => build를 진행한다.</i></div><div><i><br /></i></div><div>성공적으로 build가 진행되었으니, edge, supernode binary 및 ipk 파일이 어디에 생성되었는지 찾아보도록 하자.</div><div><br /></div><div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>find . -name "edge" -print</b></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/.pkgdir/n2n-edge/usr/sbin/edge</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/edge</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/ipkg-mipsel_24kc/n2n-edge/usr/sbin/edge</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/packages/openwrt/etc/init.d/edge</span></div><div><span style="color: #0b5394; font-size: x-small;">./staging_dir/target-mipsel_24kc_musl/root-ramips/usr/sbin/edge</span></div><div><br /></div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>find . -name "supernode" -print</b></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/.pkgdir/n2n-supernode/usr/sbin/supernode</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/supernode</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/ipkg-mipsel_24kc/n2n-supernode/usr/sbin/supernode</span></div><div><span style="color: #0b5394; font-size: x-small;">./build_dir/target-mipsel_24kc_musl/n2n-/n2n-2.8/packages/openwrt/etc/init.d/supernode</span></div><div><span style="color: #0b5394; font-size: x-small;">./staging_dir/target-mipsel_24kc_musl/root-ramips/usr/sbin/supernode</span></div></div><div><br /></div><div><div>chyi@535261426f3a:~/gl.inet/openwrt$ <b>find . -name "n2n*ipk" -print</b></div><div><span style="color: #741b47; font-size: x-small;">./bin/packages/mipsel_24kc/base/n2n-edge_2.8-1_mipsel_24kc.ipk</span></div><div><span style="color: #741b47; font-size: x-small;">./bin/packages/mipsel_24kc/base/n2n-supernode_2.8-1_mipsel_24kc.ipk</span></div></div><div><br /></div><div>다음으로 할 일은 앞서 생성한 두개의 ipk 파일을 target board에 설치하는 것이다.</div><div><div><br /></div></div><div><b style="background-color: #d9ead3;"><MangoBox></b></div><div>root@mango:~#<b> opkg update</b></div><div>root@mango:~# <b>opkg install /tmp/n2n-edge_2.8-1_misel_24kc.ipk</b></div><div>root@mango:~# <b>opkg install /tmp/n2n-supernode_2.8-1_misel_24kc.ipk</b></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 설치 후, edge를 실행하면 openssl 관련하여 error가 발생할 수 있다. 이는 openssl version이 불일치해서 생기는 문제로 openssl version을 맞추는 작업을 해주어야 한다.</span></div><div><br /></div><div>edge가 정상 동작하는 것을 확인한 후에는, 아래와 같이 uci 명령을 사용하여 추가 firewall 설정을 해 주어야 한다. 즉, n2n을 위한 zone을 하나 만들고, n2n <=> lan, n2n <=> wan 간에 packet forwarding이 되도록 하는 firewall rule을 추가해 주어야 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5YRgKDeMUYWFXAGlf4sp1OSr3XZrmXGRrfAO8qoDwawNya2l7exmOSPlYRV7evahmXNCpkiVr1PlXIBmaPCuqmJsbcGwxNatNNKpOb-xF5pbC8QaioVvQ-BYNSBbA13Myn_DzK8NG2x-K/s558/mango_uci_sh.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="558" data-original-width="464" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5YRgKDeMUYWFXAGlf4sp1OSr3XZrmXGRrfAO8qoDwawNya2l7exmOSPlYRV7evahmXNCpkiVr1PlXIBmaPCuqmJsbcGwxNatNNKpOb-xF5pbC8QaioVvQ-BYNSBbA13Myn_DzK8NG2x-K/w333-h400/mango_uci_sh.png" width="333" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.15] uci 명령을 사용하여 firewall 규칙 설정 변경하기</div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 위의 과정을 생략하면 firewall에 의해 막혀 n2n(edge)이 제대로 동작하지 못하게 되므로 반드시 설정해 주도록 한다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>자, 그럼 모든 준비가 끝났으니, 본격적으로 edge 명령 설정 단계로 들어가 보자.</div><div><br /></div><div><b style="background-color: #d9ead3;"><MangoBox></b></div><div>root@mango:~/workspace# <b>./edge -c mynetwork -k mysecretpass -a 10.1.2.1 <span style="color: #990000;">-r</span> -l supernode.ntop.org:7777 -A2 -z1 -f <span style="color: #b45f06;">-n 192.168.2.0/24:10.1.2.2</span></b></div><div><b><br /></b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIzAzqkzOPkZ_j-FnWW9nvvN4qHSNUeBN3e849wRMIe7MuHfNRk5_ChJyPlbz8lTO22sV7iAEnHhVw508Q8XpWC0nfK-0QFcm5APLE3GNEnPrj5wyHR4b7lnh5bnc9XOkZrMN-8u7wo0Rj/s818/mango_edge_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="395" data-original-width="818" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIzAzqkzOPkZ_j-FnWW9nvvN4qHSNUeBN3e849wRMIe7MuHfNRk5_ChJyPlbz8lTO22sV7iAEnHhVw508Q8XpWC0nfK-0QFcm5APLE3GNEnPrj5wyHR4b7lnh5bnc9XOkZrMN-8u7wo0Rj/w400-h194/mango_edge_run.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.16] MangoBox에서 edge를 실행한 모습</div></div><div><b><br /></b></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 위의 -n option이 의미하는 것은 192.168.2.0/24 network으로 패킷을 내보내기 위해서는 10.1.2.2 gateway로 전달해야 한다는 뜻이다. 위 명령을 실행하고 나면 아래와 같은 routing table 항목(4번째 line)이 자동으로 생성되게 된다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJI612HMIIY6BlPnVasHg8IGJqjV0Y01vZsFghirvHwY-QNyy-sbfSiNolce8cbJLL71R156-LYyP6Fv6Yibk7A_BkQKuRbWAvyGG3IE6oTuUpayaE77twTEl1UYokIuRdliyDd9nmFZye/s727/mango_routing.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="134" data-original-width="727" height="74" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJI612HMIIY6BlPnVasHg8IGJqjV0Y01vZsFghirvHwY-QNyy-sbfSiNolce8cbJLL71R156-LYyP6Fv6Yibk7A_BkQKuRbWAvyGG3IE6oTuUpayaE77twTEl1UYokIuRdliyDd9nmFZye/w400-h74/mango_routing.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.17] MangoBox의 routing table(4번째 line 주목)</div></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>다음으로 MACCHIATObin에서도 edge 설정을 해 주도록 하자.</div><div><br /></div><div><b style="background-color: #d9ead3;"><MACCHIATObin board></b></div><div>root@localhost:/home/chyi/workspace# <b>./edge -c mynetwork -k mysecretpass -a 10.1.2.2<span style="color: #990000;"> -r </span>-l supernode.ntop.org:7777 -A2 -z1 -f <span style="color: #b45f06;">-n 192.168.8.0/24:10.1.2.1</span></b></div><div><br /></div><div>모든 설정이 끝났으니 이 상태에서 Linux PC B(MACCHIATObin 내부망 PC)로 부터 Linux PC A(MangoBox 내부망 PC)로 ping을 시도해 보자. </div><div><br /></div><div style="text-align: center;"><b>192.168.2.100(Linux PC B) => 192.168.8.156(Linux PC A)</b></div><div><b style="text-align: center;"><span style="color: #990000;"><br /></span></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLUhEDX9DuJtVXKl2g3wzRYuOX6JXNiqNWAva5LiuRSD1G2Cpxx2_UFeAbkjw7qaFP1AvoXzabPYpqUc23QD7yihBsfRojBjyjXW6e1lmYDDQgQs2tBZLPPle3kNVXjknkwptPiSG2B9hU/s611/n2n_ping_to_mango_internal.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="210" data-original-width="611" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLUhEDX9DuJtVXKl2g3wzRYuOX6JXNiqNWAva5LiuRSD1G2Cpxx2_UFeAbkjw7qaFP1AvoXzabPYpqUc23QD7yihBsfRojBjyjXW6e1lmYDDQgQs2tBZLPPle3kNVXjknkwptPiSG2B9hU/w400-h138/n2n_ping_to_mango_internal.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.18] 192.168.2.100(Linux PC B) => 192.168.8.156(Linux PC A) ping 모습</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">이번에는 반대 방향으로도 해 보자.</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div><b>192.168.8.156(Linux PC A) => </b><b>192.168.2.100(Linux PC B)</b></div><div><b><br /></b></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirvyytXCMLJyhz89pGc-jaLnmkT-vCXW-1YP-cVUnWfcofkG3ZaJi0-K3fpZetpsfhadL-w_ol6qFZiSZGRFnva0JDi65ede64e9iEKFp4gKzX1Vc90TSlsq2CoKJxwa5uDkUszvqupVTR/s590/mango_ping_OK.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="277" data-original-width="590" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirvyytXCMLJyhz89pGc-jaLnmkT-vCXW-1YP-cVUnWfcofkG3ZaJi0-K3fpZetpsfhadL-w_ol6qFZiSZGRFnva0JDi65ede64e9iEKFp4gKzX1Vc90TSlsq2CoKJxwa5uDkUszvqupVTR/w400-h188/mango_ping_OK.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.19] 192.168.8.156(Linux PC A) => 192.168.2.100(Linux PC B) ping 모습</div><div><br /></div><div>OK, 둘다 모두 정상이다. 😏</div>_______________________<div><br /><div><span style="color: #351c75;"><b>이상으로 ntop n2n을 가지고 MACCHIATObin board & MangoBox를 P2P VPN Gateway로 만드는 과정을 간략히 살펴 보았다.</b></span></div><div><span style="color: #351c75;"><b>아직 안전한 암호 key 교환 방법(예: IKE, ECDH) 등 넘어야 할 산이 좀 남아 있긴 하지만, p2p VPN 영역에서 n2n이 나름의 역할을 할 것으로 기대하며, 이번 글을 마치고자 한다.</b></span><span style="color: #38761d;"> </span>🎈</div><div><br /></div><div><br /></div><div><div><div><b><font color="#3d85c6" size="6">8. References</font></b></div><div>[1] <a href="http://espressobin.net/espressobin-ultra-build-instruction/">http://espressobin.net/espressobin-ultra-build-instruction/</a> </div><div>[2] ESPRESSObin ULTRA- Quick Start Guide -Rev 03</div><div>[3] <span style="color: #990000;">Ethernet switch support in the Linux kernel</span>, Alexandre Belloni, Bootlin</div></div><div>[4] <span style="color: #990000;">From the Ethernet MAC to the link partner</span>, Maxime Chevallier, Antoine Ténart, Bootlin</div><div>[5] <a href="https://docplayer.net/50750816-Distributed-switch-architecture-a-k-a-dsa.html">Distributed Switch Architecture, A.K.A DSA, Andrew Lunn, Vivien Didelot, Florian Fainelli</a></div><div>[6] marvell-link-street-88E6341-product-brief.pdf</div><div>[7] http://wiki.macchiatobin.net/tiki-index.php?page=BSP+HowTo</div><div>[8] https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04</div><div>[9] http://pyrasis.com/Docker/Docker-HOWTO#ps</div><div>[10] https://www.stereolabs.com/docs/docker/building-arm-container-on-x86/</div><div>[11] N2N: A Layer Two Peer-to-Peer VPN, Luca Deri and Richard Andrews</div><div>[12] Creating Network Overlays with IoT Devices using N2N, Emanuele Faranda</div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#38761d">SlowBoot</font></b></div></div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com2tag:blogger.com,1999:blog-6346200245600677355.post-52145540430847138762020-09-20T17:28:00.001+09:002020-09-20T17:28:08.364+09:00ESPRESSObin Ultra 보드와 MACCHIATObin 보드의 Switch & Ethernet Device Driver 분석(2)<p>이번 시간에는 지난 시간에 이어, Marvell chip을 사용하는 보드 중 두번째인 <a href="https://macchiatobin.net/">MACCHIATObin 보드</a>에 관한 이야기(network 중심)를 해 보고자 한다.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUbLlfrPrfEnxLeFxsG4MFTXTX15IA5H6nHzsD-Gfe-qcAD9_f0sbLutKgZQXcgVftDYxarF5jN7BIWct4XlCdZaKDYupDftlia20HAWnl4G0yep6FHoaIJwaDTp5TpL_GvFYqXQtRFh8l/s225/softethervpn_logo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUbLlfrPrfEnxLeFxsG4MFTXTX15IA5H6nHzsD-Gfe-qcAD9_f0sbLutKgZQXcgVftDYxarF5jN7BIWct4XlCdZaKDYupDftlia20HAWnl4G0yep6FHoaIJwaDTp5TpL_GvFYqXQtRFh8l/w120-h120/softethervpn_logo.png" width="120" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi08uH-uCtshCdNCEwOx2msTC4RXAw2NwifgXUR2WdTYJPMunLBEtxnMT4V-3TjSlhTMiqh7TizgkObvntZCH4q0tWjY8HY4PLwX-jhl9kFPgRYYswc-Dt9aR0-8FPddBZQ9Moe1aAX4p6n/s225/docker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" height="113" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi08uH-uCtshCdNCEwOx2msTC4RXAw2NwifgXUR2WdTYJPMunLBEtxnMT4V-3TjSlhTMiqh7TizgkObvntZCH4q0tWjY8HY4PLwX-jhl9kFPgRYYswc-Dt9aR0-8FPddBZQ9Moe1aAX4p6n/w109-h113/docker.png" width="109" /></a><br /> </div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJ6Xgbu_jaZ_J93HLA3OASY2TgR12rZwwxDnj1bQGH_1X9jH9KYivVBKlx227SWiCXPUj9deZpjqeQhyphenhyphenBDULDPv4qZzwZMc8FE4kMLTa4hwAPEYZOo_nqRf8d9i25NfTD5V2crv6bWbe6/s248/macchiatobin_board.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="201" data-original-width="248" height="139" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJ6Xgbu_jaZ_J93HLA3OASY2TgR12rZwwxDnj1bQGH_1X9jH9KYivVBKlx227SWiCXPUj9deZpjqeQhyphenhyphenBDULDPv4qZzwZMc8FE4kMLTa4hwAPEYZOo_nqRf8d9i25NfTD5V2crv6bWbe6/w171-h139/macchiatobin_board.png" width="171" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div><b><span style="font-size: medium;">목차</span></b></div><div><i>1. Docker 환경 설정</i></div><div><i>2. ESPRESSObin Ultra 보드 소개</i></div><div><i>3. ESPRESSObin Ultra 보드의 Switching Device Driver 분석</i></div><div><i><b>4. MACCHIATObin 보드 소개</b></i></div><div><b><i>5. </i><i>MACCHIATObin 보드의 </i><i>Ethernet Device Driver 분석</i></b></div><div><b><i>6. 응용편: </i></b><span style="color: #444444;"><b><i>MACCHIATObin 보드를 </i></b><b><i>SoftEther VPN Gateway로 만들기</i></b></span></div><div><i>7. References</i></div><div><br /></div><div><br /></div><div><div><div><br /></div><div><b><font color="#3d85c6" size="6">4. MACCHIATObin 보드 소개</font></b></div><div>MACCHIATObin은 <b>Marvell ARMADA 8040</b>(88F8040, Quad core Cortex-A72, 2GHz) processor(<span style="color: #990000;">ARMv8 고성능 CPU + PPv2라는 network processor로 구성</span>)를 사용하고, 10Gb Ethernet(Copper or SFP) 2개/2.5Gb Ethernet(SFP) 1개, 1Gb Ethernet(Copper)를 장착한 <span style="color: #3d85c6;">(고성능 network 장비로 사용 가능한)</span> community board이다. <span style="color: #3d85c6;">2년 전 쯤에 한 대를 구매해 두었었는데, 이제와서 꺼내 보게 되었다</span> 😓</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUM0PcvkBhNbXK_agDZ4PEyy05iX2mZmTXFhmmw3hp33FxsApKl3tBKp3vi2lKQyfU94mr3u1rGKUsm2k5sUfSXMiY6Y7VsBeMIQNWCVEG7Q0fE2SkfCaWS9zKmH-dN4y-bCH5jhfQP81x/s609/mcbin_spec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="220" data-original-width="609" height="181" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUM0PcvkBhNbXK_agDZ4PEyy05iX2mZmTXFhmmw3hp33FxsApKl3tBKp3vi2lKQyfU94mr3u1rGKUsm2k5sUfSXMiY6Y7VsBeMIQNWCVEG7Q0fE2SkfCaWS9zKmH-dN4y-bCH5jhfQP81x/w500-h181/mcbin_spec.png" width="500" /></a></div><div><br /></div><div><br /></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 MACCIATObin은 network interface가 가히 환상적이라고 말할 수 있다.</span></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div><b><font color="#38761d" size="4">4.1) MACCHIATObin 보드 개요</font></b></div><div>MACCHIATObin은 아래 그림과 같이 Single Shot과 Double Shot 두가지 모델이 있는데, 이 중 보다 스펙이 좋은 Double Shot을 가지고 내용 전개를 하도록 하겠다.</div><div><br /></div><div style="text-align: center;"><a href="http://macchiatobin.net/">http://macchiatobin.net/</a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxpOwOEmiYrzJTPCk6CYPDrQ3V9Ig_ghci5kNtZ_kZ_6ictG5oME7xZ1fZH2aDk_4ChIkC8gM81GUEVb6RBo5LGiRgDPzOGvb6z8RjuHrtyjxkMmnomP3g8NEkIp_VNTxl0EVFjFcjmfrK/s909/macchiatobin_boards.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="411" data-original-width="909" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxpOwOEmiYrzJTPCk6CYPDrQ3V9Ig_ghci5kNtZ_kZ_6ictG5oME7xZ1fZH2aDk_4ChIkC8gM81GUEVb6RBo5LGiRgDPzOGvb6z8RjuHrtyjxkMmnomP3g8NEkIp_VNTxl0EVFjFcjmfrK/w500-h226/macchiatobin_boards.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.1] MACCHIATOBin 보드(1) </span></div><div class="separator" style="clear: both; text-align: center;"><b><span style="text-align: left;">[출처: </span><a href="http://macchiatobin.net/">http://macchiatobin.net</a>]</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4vxVSLDE14WC_OzjJLZFirsQLs376DQ0t_tNHe5STPU5msaC3GN_z7NTRsMcWNJzOtD_ebt47Dtl1rI40iGd06szidRceO_JeBFsomqQeoTQk3xmCZd4kQswkX7VZjt47rkEiP1vGRLbr/s870/mcbin_specs.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="870" data-original-width="829" height="500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4vxVSLDE14WC_OzjJLZFirsQLs376DQ0t_tNHe5STPU5msaC3GN_z7NTRsMcWNJzOtD_ebt47Dtl1rI40iGd06szidRceO_JeBFsomqQeoTQk3xmCZd4kQswkX7VZjt47rkEiP1vGRLbr/w476-h500/mcbin_specs.png" width="476" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.2] MACCHIATOBin 보드(2) - 스펙</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixrajyZh5tnevJhLolHzdCmiQf7mpoIgpQ83xCpp8MLk7SsJV_KAxOUvSwLACix7Rw-DyEycmRml1lDTYP013vN47XBDrihLhBJJ-2Hb-rQJwcgT-QJEICyXhdSIxO7c5Ggw07cShDpuv4/s1024/MacchiatoBin_V2.1-1024x724.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="724" data-original-width="1024" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixrajyZh5tnevJhLolHzdCmiQf7mpoIgpQ83xCpp8MLk7SsJV_KAxOUvSwLACix7Rw-DyEycmRml1lDTYP013vN47XBDrihLhBJJ-2Hb-rQJwcgT-QJEICyXhdSIxO7c5Ggw07cShDpuv4/w400-h283/MacchiatoBin_V2.1-1024x724.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.3] MACCHIATOBin 보드(2) - Double Shot h/w 블록도</span></div><div><div class="separator" style="clear: both; text-align: center;"><b><span style="text-align: left;">[출처: </span><a href="http://macchiatobin.net/">http://macchiatobin.net</a>]</b></div></div><div><br /></div><div><b><font color="#38761d" size="4">4.2) Docker 환경에서 MACCHIATObin 코드 build하기</font></b></div><div>지금부터는 MACCHIATObin code를 build하기 위해 docker 상에 Ubuntu 16.04를 설치하고, 다시 그 위에 OpenWrt 17.10 설치해 보도록 하겠다.</div><div><br /></div><div style="text-align: center;"><a href="http://wiki.macchiatobin.net/tiki-index.php?page=Build+from+source+-+OpenWrt">http://wiki.macchiatobin.net/tiki-index.php?page=Build+from+source+-+OpenWrt</a></div><div><br /></div><div>$ <b>vi Dockerfile_ubuntu1604</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWWjU3lwMPzYVTptRIL1ScTbySsopMJxBc5RsQIQswjHXOx3ieLga3JGf1WrVTc2focHHxdcHiArPj9U03ojvW7I_MEtru06daVX-H4yCvjo0o0VlfDuGqXb6__AB0peSbLfh6tZ-rrG34/s646/dockerfile_u1604.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="646" data-original-width="429" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWWjU3lwMPzYVTptRIL1ScTbySsopMJxBc5RsQIQswjHXOx3ieLga3JGf1WrVTc2focHHxdcHiArPj9U03ojvW7I_MEtru06daVX-H4yCvjo0o0VlfDuGqXb6__AB0peSbLfh6tZ-rrG34/w266-h400/dockerfile_u1604.png" width="266" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.4] Ubuntu 16.04 설치용 Dockerfile</span></div><div><br /></div><div>$ <b>docker build -f <span style="color: #b45f06;">Dockerfile_ubuntu1604</span> -t <span style="color: #0b5394;">u1604</span> .</b></div><div> <i> => docker image를 만들어 보자.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWImL6Y1uGVc3A5UPRk-pB7tElxil2vtxXAZU4S_D-jfENRv-gBJ6JLy-Mli3DRLWvfP-MN5dH5X0vHWKeQuS4fQsI6J_qkJwvm0xgkqTxWCo4lfBUgEc0fjOMXItTj7VFiW9IDXwIatFb/s766/docker_build_u1604.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="766" data-original-width="745" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWImL6Y1uGVc3A5UPRk-pB7tElxil2vtxXAZU4S_D-jfENRv-gBJ6JLy-Mli3DRLWvfP-MN5dH5X0vHWKeQuS4fQsI6J_qkJwvm0xgkqTxWCo4lfBUgEc0fjOMXItTj7VFiW9IDXwIatFb/s320/docker_build_u1604.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.5] Ubuntu 16.04 설치용 docker image 생성 모습(1)</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA2w47HvVXO9AS5FV4pbSqmJUVMjj-KqjiD2OGc-cZ4ipuZUYn2tiE-i4Rgi_koz3_RGkSYpjRcyvfrX6yMP1MYZYsRL3focq3boAHZYFpYwDysnU3F2CDCzq-G4BphzaL7iJqurWIkdIQ/s968/docker_images_u1604.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="169" data-original-width="968" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA2w47HvVXO9AS5FV4pbSqmJUVMjj-KqjiD2OGc-cZ4ipuZUYn2tiE-i4Rgi_koz3_RGkSYpjRcyvfrX6yMP1MYZYsRL3focq3boAHZYFpYwDysnU3F2CDCzq-G4BphzaL7iJqurWIkdIQ/w500-h88/docker_images_u1604.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.6] Ubuntu 16.04 설치용 docker image 생성 모습(2)</span></div><div><br /></div><div><div>$ <b>docker run -i -t --name <span style="color: #3d85c6;">mcbin1604</span> <span style="color: #b45f06;">u1604</span> /bin/bash</b></div><div>root@9c114a442454:/# <b>uname -a</b></div><div><span style="font-size: x-small;">Linux 9c114a442454 5.4.0-45-generic #49~18.04.2-Ubuntu SMP Wed Aug 26 16:29:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux</span></div><div>root@9c114a442454:/# <b>cat /etc/issue</b></div><div><span style="font-size: x-small;">Ubuntu 16.04.7 LTS \n \l</span></div></div><div><br /></div><div>root@9c114a442454:/# su - chyi</div><div>chyi@9c114a442454:~/$ mkdir workspace; cd workspace</div><div>📌 <span style="color: #ff00fe;">1 ~ 2장에서 설명한 내용과 동일한 내용은 반복해서 언급하지 않도록 하겠다.</span></div><div><br /></div><div>chyi@9c114a442454:~/workspace$ <b>git clone https://github.com/MarvellEmbeddedProcessors/openwrt-kernel.git -b openwrt_17.10_release</b></div><div><i> => kernel source를 먼저 내려 받도록 한다. openwrt build 시 이 kernel 코드를 활용하기 위해서 이다.</i></div><div><br /></div><div>chyi@9c114a442454:~/workspace$ <b>git clone https://github.com/MarvellEmbeddedProcessors/openwrt-dd.git -b openwrt_17.10_release</b></div><div><i> => openwrt 17.10 version을 내려 받는다.</i></div><div><br /></div><div><div>chyi@9c114a442454:~/workspace$ cd openwrt-dd/</div><div>chyi@9c114a442454:~/workspace/openwrt-dd$ <b>ls -la</b></div><div><span style="font-size: x-small;">total 104</span></div><div><span style="font-size: x-small;">drwxrwxr-x 11 chyi chyi 4096 Sep 9 11:35 .</span></div><div><span style="font-size: x-small;">drwxrwxr-x 3 chyi chyi 4096 Sep 9 11:34 ..</span></div><div><span style="font-size: x-small;">drwxrwxr-x 8 chyi chyi 4096 Sep 9 11:35 .git</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 8 Sep 9 11:35 .gitattributes</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 224 Sep 9 11:35 .gitignore</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 179 Sep 9 11:35 BSDmakefile</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 576 Sep 9 11:35 Config.in</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 17992 Sep 9 11:35 LICENSE</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 2670 Sep 9 11:35 Makefile</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 1272 Sep 9 11:35 README</span></div><div><span style="font-size: x-small;">drwxrwxr-x 2 chyi chyi 4096 Sep 9 11:35 config</span></div><div><span style="font-size: x-small;">drwxrwxr-x 2 chyi chyi 4096 Sep 9 11:35 docs</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 457 Sep 9 11:35 feeds.conf.default</span></div><div><span style="font-size: x-small;">drwxrwxr-x 3 chyi chyi 4096 Sep 9 11:35 include</span></div><div><span style="font-size: x-small;">drwxrwxr-x 11 chyi chyi 4096 Sep 9 11:35 package</span></div><div><span style="font-size: x-small;">-rw-rw-r-- 1 chyi chyi 12237 Sep 9 11:35 rules.mk</span></div><div><span style="font-size: x-small;">drwxrwxr-x 4 chyi chyi 4096 Sep 9 11:35 scripts</span></div><div><span style="font-size: x-small;">drwxrwxr-x 6 chyi chyi 4096 Sep 9 11:35 target</span></div><div><span style="font-size: x-small;">drwxrwxr-x 12 chyi chyi 4096 Sep 9 11:35 toolchain</span></div><div><span style="font-size: x-small;">drwxrwxr-x 58 chyi chyi 4096 Sep 9 11:35 tools</span></div></div><div><br /></div><div>chyi@9c114a442454:~/workspace/openwrt-dd$ <b>./scripts/feeds update -a</b></div><div>chyi@9c114a442454:~/workspace/openwrt-dd$ <b>./scripts/feeds install -a</b></div><div>chyi@9c114a442454:~/workspace/openwrt-dd$ <b>make menuconfig</b></div><div><i> => 아래 내용을 참조하여 적절히 config를 조정하도록 한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp4pEQ0qOMCoUvcX3moxvtb3fqFXdWYRKLriOZgJzJdioFVUfWqT7rTd16IN-6IeuYweAiHCSEUMHHH6KlcLLbixzoO3JltW1L8sXsH8FGk_X-y6qZOElvXkid6wD_yqwvr3rNy6FwSACP/s497/mcbin_openwrt_menuconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="235" data-original-width="497" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp4pEQ0qOMCoUvcX3moxvtb3fqFXdWYRKLriOZgJzJdioFVUfWqT7rTd16IN-6IeuYweAiHCSEUMHHH6KlcLLbixzoO3JltW1L8sXsH8FGk_X-y6qZOElvXkid6wD_yqwvr3rNy6FwSACP/w400-h189/mcbin_openwrt_menuconfig.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijS_yH3keaMFa5gcp6HAWD_nv1XvL3uJaT4kl4RXPL6N2zs1W3mE19mU415PwfTuLO5E9ll6-mEgq2QClnV48LbaDj4u-jmGA5p0aY7BG7e_x19Hml3jsFW_GkzToqywjXtDl-i5LPfDGC/s935/mcbin_openwrt_menuconfig2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="718" data-original-width="935" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijS_yH3keaMFa5gcp6HAWD_nv1XvL3uJaT4kl4RXPL6N2zs1W3mE19mU415PwfTuLO5E9ll6-mEgq2QClnV48LbaDj4u-jmGA5p0aY7BG7e_x19Hml3jsFW_GkzToqywjXtDl-i5LPfDGC/s320/mcbin_openwrt_menuconfig2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.7] openwrt menuconfig 모습</span></div><br /><div>chyi@88e6a5c10d5f:~/workspace/openwrt-dd$ <b>make -j4</b></div><div><i> => build를 시작한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5TJ85CqXu2h9iT0iVSBfwRHf2OnPj4MA0tCdVuSQqUhnplkHHVmbq25trg9pkeO3IWzcJwazOifg6Z_Bm_dv4AtmXgNBKDxmkESgYH5VzAbIQ2PNbnRfn2hbMXqfupYx3KXPjI-QSFkp1/s899/mcbin_openwrt_bin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="382" data-original-width="899" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5TJ85CqXu2h9iT0iVSBfwRHf2OnPj4MA0tCdVuSQqUhnplkHHVmbq25trg9pkeO3IWzcJwazOifg6Z_Bm_dv4AtmXgNBKDxmkESgYH5VzAbIQ2PNbnRfn2hbMXqfupYx3KXPjI-QSFkp1/w400-h170/mcbin_openwrt_bin.png" width="400" /></a></div><div style="text-align: center;">[그림 4.8] openwrt build 결과물</div><div><br /></div><div>chyi@88e6a5c10d5f:~/workspace/openwrt-dd$ <b>exit</b></div><div>root@9c114a442454:/# <b>exit</b></div><div><br /></div><div><div>$ <b>docker commit -a "chunghan <chunghan.yi@gmail.com>" -m "add openwrt codes" mcbin1604 u1604</b></div><div><i> => 지금까지 작업한 내용을 commit 하자.</i></div><div><br /></div><div><br /></div><div><b><font color="#38761d" size="4">4.3) Target board에서 돌려 보기 </font></b></div><div>이 절에서는 아래 site의 내용을 참조하여 MACCHIATObin 보드를 부팅해 보도록 하겠다.</div></div><div><br /></div><div style="text-align: center;"><a href="http://wiki.macchiatobin.net/tiki-index.php?page=Boot+from+removable+storage+-+OpenWrt">http://wiki.macchiatobin.net/tiki-index.php?page=Boot+from+removable+storage+-+OpenWrt</a></div><div><br /></div><div>부팅 가능한 microSD를 만드는 방법은 생략하였다. 관련해서는 위의 site 내용을 참조하기 바란다.</div><div><br /></div><div><b style="background-color: #ffe599;"><Target board></b></div><div><div>Marvell>> <b>setenv image_name boot/openwrt-armada-a8k-MACHIATOBin-Image</b></div><div>Marvell>> <b>setenv fdt_name boot/armada-8040-mcbin.dtb</b></div></div><div><br /></div><div>Marvell>> <b>setenv bootmmc 'mmc dev 1; ext4load mmc 1:1 $kernel_addr $image_name;ext4load mmc 1:1 $fdt_addr $fdt_name;setenv bootargs $console root=/dev/mmcblk1p1 rw rootwait; booti $kernel_addr - $fdt_addr'</b></div><div><br /></div><div>Marvell>> <b>saveenv</b></div><div>Marvell>> <b>reset</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW0zQJyL5SzSz5a7CuORZcnRraXa91FJFMAl8wn5725CJLhxEdvLXMQ9I79eCGjr5cxV5j88YIzhpaW9k-iItAq9TBCKYpuUBdMmyy-plaKKRmABsfb-s415NS4Io3EZcMBP1zoD6a1pMn/s939/mcbin_booting.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="758" data-original-width="939" height="323" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW0zQJyL5SzSz5a7CuORZcnRraXa91FJFMAl8wn5725CJLhxEdvLXMQ9I79eCGjr5cxV5j88YIzhpaW9k-iItAq9TBCKYpuUBdMmyy-plaKKRmABsfb-s415NS4Io3EZcMBP1zoD6a1pMn/w400-h323/mcbin_booting.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.9] MACCHIATObin 보드 부팅 모습(1) - minicom 115200 8N1</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvsZeK7AbtrS8PWQi2WH3KU8F8GTnBjwbeJlEzvz5ZoGxgD6DY7LjNuJON6zoeUTVOqShMMBgDPaz6T_z24AvaLEXOmDZ2m4b3jILqNP3YJDz962BOLIKSCDPAvJ6yLwh3k5rDBfoKRAp7/s760/mcbin_openwrt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="760" data-original-width="737" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvsZeK7AbtrS8PWQi2WH3KU8F8GTnBjwbeJlEzvz5ZoGxgD6DY7LjNuJON6zoeUTVOqShMMBgDPaz6T_z24AvaLEXOmDZ2m4b3jILqNP3YJDz962BOLIKSCDPAvJ6yLwh3k5rDBfoKRAp7/s320/mcbin_openwrt.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.10] MACCHIATObin 보드 부팅 모습(2)</div><div><br /></div><div>아래 그림은 MACCHIATObin의 port가 u-boot 및 linux에서 인식되는 내용을 보여준다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQi6X8mVxDyTBAf0yUBlARN4FQrD753SXqbIMgvuEjHvOpTMJzESzsZ73XT2s7w4W-QJWg4jPvLx7Zt_2LCvFUWqqZd00mLHtyJUO1Bs2GVyuPatIUKP4rWh97y5xCDCjydojbbAkl5jpb/s1394/ethernet+port+-+uboot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="373" data-original-width="1394" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQi6X8mVxDyTBAf0yUBlARN4FQrD753SXqbIMgvuEjHvOpTMJzESzsZ73XT2s7w4W-QJWg4jPvLx7Zt_2LCvFUWqqZd00mLHtyJUO1Bs2GVyuPatIUKP4rWh97y5xCDCjydojbbAkl5jpb/w500-h135/ethernet+port+-+uboot.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.11] MACCHIATObin 보드 Ethernet Port 구성</div><div class="separator" style="clear: both; text-align: center;">(egiga0 => eth0, egiga1 => eth1, egiga2 => eth2)</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJyHnAHXLbkiAxQ9yjjwofJGG1D1HHv7jSmU_Vgf5fAs7x6gwy8gKqnVg9gJEaQ2z6EkxNH8f-8zc7_h7RYUMTQamZExJ_nuFQq8F6gPYrriUFZ4ZYWjMZ0sN63qOh0b-RLiKarkIbPf0R/s518/mcbin_etc_config_netework.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="518" data-original-width="457" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJyHnAHXLbkiAxQ9yjjwofJGG1D1HHv7jSmU_Vgf5fAs7x6gwy8gKqnVg9gJEaQ2z6EkxNH8f-8zc7_h7RYUMTQamZExJ_nuFQq8F6gPYrriUFZ4ZYWjMZ0sN63qOh0b-RLiKarkIbPf0R/s320/mcbin_etc_config_netework.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.12] /etc/config/network 설정 내용 - LAN(bridge): eth0, eth1, eth3, WAN: eth2</div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xNx75E90m0W76eVB_WlnV7SmA67uSq_xxpwTW2Qfwlt0Ey0GdD72vVyn2zOlHGcMU0z05Dv-jH1LIJc8HmhA37giGPKOEMZf8x1BeQJmyAuUApKmARRPh3ojjZfhaCQqo_9Mwk-TW4MZ/s2048/20200914_134824.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1536" data-original-width="2048" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2xNx75E90m0W76eVB_WlnV7SmA67uSq_xxpwTW2Qfwlt0Ey0GdD72vVyn2zOlHGcMU0z05Dv-jH1LIJc8HmhA37giGPKOEMZf8x1BeQJmyAuUApKmARRPh3ojjZfhaCQqo_9Mwk-TW4MZ/s320/20200914_134824.jpg" width="320" /></a></div><div class="separator" style="clear: both;">[그림 4.13] 동작 중인 MACCHIATObin 보드(LAN: 검정색 선, WAN: 파란색 선)</div></div><div><br /></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 팬이 하나 달려 있어, 오래 틀어 놓으니 좀 시끄럽다.</span></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 10G Ethernet을 위해서는 Cat6A 이상의 UTP cable을 사용해야 한다.</span></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVaT2mD7M9Uo0xfvfuxTbD4LXZNpC_fzg-32mV7eLRUevh-2Hejg7dGkcq5VyhfAnjFX6ARxPPRL-wvnPboukYrJ9CuaLoz6gD27A6XHgbx-X_kkJ39KUVqFPPX9ThEdLXfMeViSpL8cXC/s746/mcbin_netstat_nr.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="340" data-original-width="746" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVaT2mD7M9Uo0xfvfuxTbD4LXZNpC_fzg-32mV7eLRUevh-2Hejg7dGkcq5VyhfAnjFX6ARxPPRL-wvnPboukYrJ9CuaLoz6gD27A6XHgbx-X_kkJ39KUVqFPPX9ThEdLXfMeViSpL8cXC/w400-h183/mcbin_netstat_nr.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.14] 동작 중인 MACCHIATObin 보드 - routing table</div><div><br /></div><div>OK, 이 상태에서 인터넷을 연결해 보니, 정상 동작한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghhW4SWbrvxf3p1ly_5SYoHRx3e9FPqhUhyphenhyphen0feF9rgjBLO53ASV5IwonnxXOq5J-7cgTI5IYoSGCko9HfO09PL3EvGKC3R5dH6SwEibeBK-5hiv2hD9F7jczuW58DmSJY9heVFchaMmRjk/s735/mcbin_ps.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="735" data-original-width="724" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghhW4SWbrvxf3p1ly_5SYoHRx3e9FPqhUhyphenhyphen0feF9rgjBLO53ASV5IwonnxXOq5J-7cgTI5IYoSGCko9HfO09PL3EvGKC3R5dH6SwEibeBK-5hiv2hD9F7jczuW58DmSJY9heVFchaMmRjk/s320/mcbin_ps.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.15] 동작 중인 MACCHIATObin 보드 - ps 명령 실행 모습</div><div><br /></div><div>이상으로 MACCHIATObin 보드에 OpenWrt 17.10을 올리고, 간단히 network 동작 테스트를 진행해 보았다. </div><div><br /></div></div><div><br /></div><div><div><div><b><font color="#3d85c6" size="6">5. MACCHIATObin 보드의 Ethernet Device Driver 분석</font></b></div><div>이 장의 내용은 [참고문헌 4]에서 영감을 받아 작성하였다.</div><div><br /></div><div style="text-align: center;"><span style="color: #674ea7;"><i><a href="https://www.youtube.com/watch?v=K962S9gTBVM" target="_blank">From the Ethernet MAC to the link partner, Maxime Chevallier, Antoine Ténart, Bootlin</a></i></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDAGkeCxYiEuLf8REKJzpscgqjhT4d_PvTQrnL8efgbC6neEIUdd4hb37J3pabZ0eUbcY26x6MJmiZhsCkxZFFxErXSMKsOtQz_3VYX2UZlIcPXq460ZtiSzWoXo2zCAjV2oVYlPJDb5GE/s1069/mac_phy_mdio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="186" data-original-width="1069" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDAGkeCxYiEuLf8REKJzpscgqjhT4d_PvTQrnL8efgbC6neEIUdd4hb37J3pabZ0eUbcY26x6MJmiZhsCkxZFFxErXSMKsOtQz_3VYX2UZlIcPXq460ZtiSzWoXo2zCAjV2oVYlPJDb5GE/w500-h88/mac_phy_mdio.png" width="500" /></a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCJB5KneHuMJQgRygexsSS7-MS3gmeecdEjm8ZgtFsog9yFt6J-gxfZPlcFO9DznfnQTi5TD-JS4L7qbzih1jhtAcoKZhh-HtayXUQ_RZRsidUshgiUEudqBowoDF9Ngv6oJbHQOjNJANT/s590/mac_to_phy.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="590" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCJB5KneHuMJQgRygexsSS7-MS3gmeecdEjm8ZgtFsog9yFt6J-gxfZPlcFO9DznfnQTi5TD-JS4L7qbzih1jhtAcoKZhh-HtayXUQ_RZRsidUshgiUEudqBowoDF9Ngv6oJbHQOjNJANT/s320/mac_to_phy.png" width="320" /></a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiktCFLhS5ImvIZlEf9ufekFDdXj77OElzoWrurUKppyCjs1_FtEHvq317PqkaeUYVw5tvO1x8sY4x2Nc0V49iIAU6QQ2n0wuMIRshSmGMV7LtuXhI0N30emFGqm2FPdXxoyA4i3dl0Mm29/s806/mdio_bus.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="279" data-original-width="806" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiktCFLhS5ImvIZlEf9ufekFDdXj77OElzoWrurUKppyCjs1_FtEHvq317PqkaeUYVw5tvO1x8sY4x2Nc0V49iIAU6QQ2n0wuMIRshSmGMV7LtuXhI0N30emFGqm2FPdXxoyA4i3dl0Mm29/s320/mdio_bus.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.1] Ethernet Link Layer 개념도 </span><b style="text-align: left;">[출처: 참고문헌 4]</b></div><div><br /></div><div><br /></div><div><b><font color="#38761d" size="4">5.1) MACCHIATObin의 네트워크 인터페이스 </font></b></div><div>아래 그림은 MACCHIATObin 보드의 Ethernet 구성 요소를 전체적으로 보여주고 있다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimzIhsfl5zc3yUscDDQ7EiUyCF-B8R68sDRu8tXpFHsdEKXiwpUbdec7ULVpArZr4cFHbq5McuWYA5fVsSUcM50BhxHdxp4u0wjsaoeQeHnNrS_e-5or4-9KJghzKxyVP1ZpHvaB_5Qxb3/s527/mcbin_ethernet_components.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="359" data-original-width="527" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimzIhsfl5zc3yUscDDQ7EiUyCF-B8R68sDRu8tXpFHsdEKXiwpUbdec7ULVpArZr4cFHbq5McuWYA5fVsSUcM50BhxHdxp4u0wjsaoeQeHnNrS_e-5or4-9KJghzKxyVP1ZpHvaB_5Qxb3/w500-h341/mcbin_ethernet_components.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.2] MACCHIATObin 보드 MAC/PHY 구성도 </span><b style="text-align: left;">[출처: 참고문헌 4]</b></div><div><br /></div></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 SFP는 small form-factor pluggable transceiver를 뜻한다. SFP는 주로 광 케이블을 연결할 때 많이 사용되지만, copper cable을 연결하는 용도로도 사용될 수 있다.</span></div><div><br /></div><div>먼저 eth2(그림 4.11 기준 가장 왼쪽, 위의 그림 5.2 기준 가장 아래쪽) 1G interface는 아래와 같이 가장 일반적인 MAC(PPv2.2)과 PHY(88E1512) 연결 형태로 구성되어 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPzFGb14ddAlO8_9YWtQ1MHiju1eQcsz3KXmhwUpX3ea_MJEjHet7n2JtMnGqjWthKNZA5Pgsnj2S3v8O2vfMvzQ7_NWAOwNpbROzIwXCJGfU4XL7hKMzSu1FhSKHcfoxKohCCz8R0mJiN/s1039/mcbin_eth2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="177" data-original-width="1039" height="69" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPzFGb14ddAlO8_9YWtQ1MHiju1eQcsz3KXmhwUpX3ea_MJEjHet7n2JtMnGqjWthKNZA5Pgsnj2S3v8O2vfMvzQ7_NWAOwNpbROzIwXCJGfU4XL7hKMzSu1FhSKHcfoxKohCCz8R0mJiN/w400-h69/mcbin_eth2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.3] MACCHIATObin 보드 eth2 1G Interface </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 4]</b></div><div><br /></div><div>다음으로 eth0, eth1 10G interface(그림 4.11 기준 가운데 두쌍 - SFP+ and Copper -)는 다음과 같이 MAC(PPv2.2)와 PHY(88X3310) 연결 형태로 구성되어 있다. SFP+의 경우는 내부에 i2c device가 포함되어 있어 i2c controller(SoC 내부)와 연결되어 있다(SFP+에 대한 레지스터 설정은 i2c를 통해 이루어짐).</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBB4zvIRushir6YnqeW4RZrMLJ1sUifpfS6asg1ZPO-UYOa_U6Kf39rpm9i0xP0Y_PgeLPCBd5HDogHYiYIy3kLRUJHwkllkiqe7vmlBotg2vlPYqsANi4baFHPxyw0M1IkDHYiAzCSDHw/s1029/mcbin_10G_links.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="281" data-original-width="1029" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBB4zvIRushir6YnqeW4RZrMLJ1sUifpfS6asg1ZPO-UYOa_U6Kf39rpm9i0xP0Y_PgeLPCBd5HDogHYiYIy3kLRUJHwkllkiqe7vmlBotg2vlPYqsANi4baFHPxyw0M1IkDHYiAzCSDHw/w400-h109/mcbin_10G_links.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.4] MACCHIATObin 보드 eth0/1 10G Interface </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 4]</b></div><div><b><br /></b></div><div>마지막으로 eth3(그림 4.11 기준 맨 우측 포트)은 2.5G interface를 지원하며, 중간에 별도의 PHY를 거치지 않고 곧바로 MAC(PPv2.2)과 연결되어 있다(즉, MAC to MAC 통신을 한다는 뜻). 경우에 따라서는 SFP+ 내에 PHY가 있는 경우도 있는데, 이 경우는 일반적인 MAC to PHY 통신으로 이어지게 된다.</div><div><b><br /></b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitQeFAFpejGJgbjSeL8wk6NETwJ_mbf_D4f1Nid3AVPT_EMWSdrZfewTcJIiD1BDth-QVt6fR-aPB3uH58acRppLwG1OvCHzaFPuxcXARKLl2DxGshO4qJi10osOxwwirNM98Wt1_IzcpQ/s1026/mcbin_eth3_2_5G.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="1026" height="90" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitQeFAFpejGJgbjSeL8wk6NETwJ_mbf_D4f1Nid3AVPT_EMWSdrZfewTcJIiD1BDth-QVt6fR-aPB3uH58acRppLwG1OvCHzaFPuxcXARKLl2DxGshO4qJi10osOxwwirNM98Wt1_IzcpQ/w400-h90/mcbin_eth3_2_5G.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><b style="text-align: left;"><span style="font-weight: 400;">[그림 5.5] MACCHIATObin 보드 eth3 2.5G MAC to MAC Interface </span><b>[</b></b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 4]</b></div></div><div><br /></div><div><span style="font-size: medium;"><b><font color="#38761d">5.2) </font></b><b><font color="#38761d">MACCHIATObin의 Ethernet Device Driver 분석</font></b></span></div><div>이런, 4.2~4.3 절에서 설치한 linux kernel(4.4.52)에는 [참고문헌 4]에서 말하는 kernel code가 보이질 않는다. 이 내용은 <span style="color: #674ea7;">오히려 1장에서 설치한 linux kernel(4.19.62)에 보인다.</span></div><div><br /></div><div><b><device tree></b></div><div>arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts</div><div><span style="color: #990000;"><TBD></span></div><div><span style="color: #990000;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ3ZS77m_6lGEIagWueS_nPjiNEwebyvhvA6pd0afax_ogpWjJELM1Jxyzvb_6Z3G5Pz0j1EbrpAKR8KeW63FSdn5JibXewvUz_iUXqietf-E6OdGszbZFpvvMLhDT6LXqiTMVq9KBvis1/s645/armada8040_mcbin_dts.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="645" data-original-width="568" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ3ZS77m_6lGEIagWueS_nPjiNEwebyvhvA6pd0afax_ogpWjJELM1Jxyzvb_6Z3G5Pz0j1EbrpAKR8KeW63FSdn5JibXewvUz_iUXqietf-E6OdGszbZFpvvMLhDT6LXqiTMVq9KBvis1/w353-h400/armada8040_mcbin_dts.png" width="353" /></a></div><div class="separator" style="clear: both; text-align: center;"><b style="text-align: left;"><span style="font-weight: 400;">[그림 5.6] </span></b><span style="text-align: left;">armada-8040-mcbin.dts 내용 중 일부 발췌</span></div><div><br /></div><div><b><device drivers></b></div><div><span style="color: #6aa84f;"><Ethernet MAC controller></span></div><div><div>drivers/net/ethernet/marvell/mvpp2/*</div><div>drivers/net/ethernet/marvell/mvmdio.c</div><div><br /></div><div><span style="color: #6aa84f;"><PHY driver></span></div><div>drivers/net/phy/marvell.c</div><div>drivers/net/phy/marvell10g.c</div></div><div><span style="color: #990000;"><TBD></span></div><div><br /></div><div><b><span style="color: #990000;">Device Tree 및 device driver(ethernet MAC & PHY 관련)에 대한 분석은 추후 다시 하기로 하자.</span></b></div><div><br /></div><div><span style="background-color: #ffe599;"><b><여기서 잠깐 !></b></span></div><div><span><i> => MUSDK와 ODP를 이용한 고속 패킷 처리 방법에 관하여 ...</i></span><br /></div><div><div><br /></div><div>Marvell User-Space SDK(a.k.a MUSDK)와 ODP(Open Data Plane)를 사용하면 고속 패킷 처리(linux kernel을 경유한 slow path가 아니라 PPv2.2를 이용한 fastpath)가 가능하다고 한다. 이 내용 자체도 하나의 커다른 주제가 될 듯한데, 자세한 사항은 아래 site를 참고하도록 하자.</div><div style="text-align: center;"><br /></div><div style="text-align: center;"><a href="http://wiki.macchiatobin.net/tiki-index.php?page=ODP-MUSDK+User+Guide">http://wiki.macchiatobin.net/tiki-index.php?page=ODP-MUSDK+User+Guide</a></div></div><div><br /></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoNdDvmcotGhboDBAvQabTcbOIsFw8gvC67HUelisR-IG7Gb02QrpwIu6St0R2GXbrsZ9Vf4Pya_EoWzVh_UuLivE1GU_ohBTgvT_YTUPRcqkoSViD1-F5mCNMMvKa8BJ7-RUmDtpM-cWe/s666/musdk_sys.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="440" data-original-width="666" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoNdDvmcotGhboDBAvQabTcbOIsFw8gvC67HUelisR-IG7Gb02QrpwIu6St0R2GXbrsZ9Vf4Pya_EoWzVh_UuLivE1GU_ohBTgvT_YTUPRcqkoSViD1-F5mCNMMvKa8BJ7-RUmDtpM-cWe/w400-h264/musdk_sys.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.7] MUSDK를 이용하여 PPv2 활용하기</span></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGeiKa6aii3XrZzanxSLkUyMXzSsfi_Vr6r2-d_ZDvRgoo4x5wQFGnZ37-FJam9CIozBi5i8_3iY82aRUbv-yPXrOZg3x5PXFKXMaJ5B4XWYeJLMy8QBHM6Al8JbJRXpQbwpSMuvg7PiKU/s768/odp-overview-768x275.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="275" data-original-width="768" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGeiKa6aii3XrZzanxSLkUyMXzSsfi_Vr6r2-d_ZDvRgoo4x5wQFGnZ37-FJam9CIozBi5i8_3iY82aRUbv-yPXrOZg3x5PXFKXMaJ5B4XWYeJLMy8QBHM6Al8JbJRXpQbwpSMuvg7PiKU/w400-h144/odp-overview-768x275.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.8] ODP를 이용하여 PPv2 활용하기</span></div><div><br /></div><div><span style="background-color: #ffe599;">이 장의 내용은 (아쉬움이 많이 남는 관계로) 추후 시간을 내어 좀 더 상세히 분석해 보아야 할 것 같다.</span> 😂</div><div><br /></div><div><br /></div></div><div><div><div><b><span style="color: #3d85c6;"><font size="6">6. 응용편: </font><font size="6">MACCHIATObin 보드를 SoftEther VPN Gateway로 만들기</font></span></b></div><div>이 장에서는 MACCHIATObin 보드를 VPN Gateway(SoftEther VPN 기반)로 만드는 과정을 소개하고자 한다. <a href="https://www.softether.org">SoftEther VPN</a>과 관련해서는 아래 blog post를 통해 이미 한 차례 소개한 바 있다.</div></div><div><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/05/glinet-mv1000-softether-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/05/glinet-mv1000-softether-vpn.html</a></div><div><br /></div><div>위의 내용을 보면 알겠지만, SoftEther VPN을 cross-compile하는 과정은 연관 library가 많은 관계로 생각처럼 간단하지가 않다. x86_64 환경 처럼 arm64 개발 환경이 준비되어 있다면, cross-compile 없이 native compile 과정만으로도 원하는 결과를 얻을 수 있을텐데, 주변에서 arm64를 기반으로한 PC를 구하는 것은 매우 어렵다. 그렇다면 어떻게 해야 할까 ? </div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 (비용은 좀 들겠지만) arm64를 지원하는 AWS EC2(or Google Cloud, Azure)를 활용하는 것도 하나의 방법이 될 수는 있다.</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>지금부터는 이 물음에 대한 대답으로,<span style="color: #b45f06;"><u> docker와 QEMU의 도움을 받아 x86 환경에서 arm64 개발 환경을 꾸미고, 그 위에서 SoftEther VPN을 build하는 방법</u></span>을 소개하고자 한다. 물론 build가 성공한 후에는 target board 상에 올려 정상 동작하는지를 직접 확인해 볼 생각이다.</div></div><div><br /></div><div><br /></div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv6OvOqQLPZ2zobUVjmqghjP_mHpJ_tjj566IglTMeQiuF5Y6xQThf_fAm0zxShltALerFW5dNyRS6cZXrEVlWaahItrlk_i_kuaiOLzlOTQN2maAH_5AhyphenhyphenAM4jdSxmu0dU1roIFAVPAZi/s700/emulation_workflow2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="304" data-original-width="700" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv6OvOqQLPZ2zobUVjmqghjP_mHpJ_tjj566IglTMeQiuF5Y6xQThf_fAm0zxShltALerFW5dNyRS6cZXrEVlWaahItrlk_i_kuaiOLzlOTQN2maAH_5AhyphenhyphenAM4jdSxmu0dU1roIFAVPAZi/w400-h174/emulation_workflow2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.1] x86 위에 ARM emulation 환경 구축 <b>[출처 - 참고문헌 10]</b></span></div><div style="text-align: center;"><br /></div><div style="text-align: justify;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; text-align: left;">📌 물론 PINE64, ESPRESSObin 등 arm64 보드를 준비하고 그 위에서 직접 compile하는 방법도 하나의 대안이 될 수 있다. 하지만, 필요할 때마나 개발 보드를 하나씩 준비할 수는 없는 노릇이다.</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><span style="font-size: medium;"><b><font color="#38761d">6.1) </font></b><span style="color: #38761d;"><b><span>arm64v8(ubuntu 16.04)에서 </span></b><b><font>SoftEther VPN build하기</font></b></span></span></div><div style="text-align: center;"><div style="text-align: left;">지금부터는 arm64 emulation 환경을 만들고, 그 위에서 SoftEther VPN를 build해 보도록 하자.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b style="background-color: #a2c4c9;"><x86_64 Desktop PC></b></div><div style="text-align: left;">$ <b>sudo apt-get install qemu binfmt-support qemu-user-static</b></div><div style="text-align: left;"><div><i> => qemu, binfmt 등을 설치한다.</i></div><div>$ <b>docker run --rm --privileged multiarch/qemu-user-static --reset -p yes</b></div><div><i> => multi architecture를 지원하는 qemu container를 실행하자.</i></div><div><span style="font-size: small;">Unable to find image 'multiarch/qemu-user-static:latest' locally</span></div><div><span style="font-size: x-small;">latest: Pulling from multiarch/qemu-user-static</span></div><div><span style="font-size: x-small;">61c5ed1cbdf8: Pull complete </span></div><div><span style="font-size: x-small;">6957fb4d1698: Pull complete </span></div><div><span style="font-size: x-small;">ed8a5179ae11: Pull complete </span></div><div><span style="font-size: x-small;">1ec39da9c97d: Pull complete </span></div><div><span style="font-size: x-small;">2901bd4ab058: Pull complete </span></div><div><span style="font-size: x-small;">Digest: sha256:28ebe2e48220ae8fd5d04bb2c847293b24d7fbfad84f0b970246e0a4efd48ad6</span></div><div><span style="font-size: x-small;">Status: Downloaded newer image for multiarch/qemu-user-static:latest</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-armeb-static as binfmt interpreter for armeb</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-sparc-static as binfmt interpreter for sparc</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-sparc32plus-static as binfmt interpreter for sparc32plus</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-sparc64-static as binfmt interpreter for sparc64</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-ppc-static as binfmt interpreter for ppc</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-ppc64-static as binfmt interpreter for ppc64</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-ppc64le-static as binfmt interpreter for ppc64le</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-m68k-static as binfmt interpreter for m68k</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mips-static as binfmt interpreter for mips</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mipsel-static as binfmt interpreter for mipsel</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mipsn32-static as binfmt interpreter for mipsn32</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mipsn32el-static as binfmt interpreter for mipsn32el</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mips64-static as binfmt interpreter for mips64</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-mips64el-static as binfmt interpreter for mips64el</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-sh4-static as binfmt interpreter for sh4</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-sh4eb-static as binfmt interpreter for sh4eb</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-s390x-static as binfmt interpreter for s390x</span></div><div><span style="font-size: x-small;">Setting /usr/bin/<span style="color: #990000;">qemu-aarch64-static</span> as binfmt interpreter for <span style="color: #990000;">aarch64 <=== 이걸 지원한다 !</span></span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-aarch64_be-static as binfmt interpreter for aarch64_be</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-hppa-static as binfmt interpreter for hppa</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-riscv32-static as binfmt interpreter for riscv32</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-riscv64-static as binfmt interpreter for riscv64</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-xtensa-static as binfmt interpreter for xtensa</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-xtensaeb-static as binfmt interpreter for xtensaeb</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-microblaze-static as binfmt interpreter for microblaze</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-microblazeel-static as binfmt interpreter for microblazeel</span></div><div><span style="font-size: x-small;">Setting /usr/bin/qemu-or1k-static as binfmt interpreter for or1k</span></div><div><br /></div><div><div>$ <b>docker run -i -t --name arm64 <span style="color: #bf9000;">arm64v8/ubuntu:16.04</span> /bin/bash</b></div><div><i> => arm64v8 용 ubuntu 16.04를 실행(container)하자.</i></div><div>root@b2940a44a2ca:/# uname -a</div><div><span style="color: #a64d79; font-size: x-small;"><div>Linux 88ab315a52ad 5.4.0-47-generic #51~18.04.1-Ubuntu SMP Sat Sep 5 14:35:50 UTC 2020 aarch64 aarch64 aarch64 GNU/Linux</div><div>root@88ab315a52ad:/# cat /etc/issue</div><div>Ubuntu 16.04.7 LTS \n \l</div></span></div><div><br /></div><div>root@b2940a44a2ca:/# <b>apt-get update</b></div></div><div>root@b2940a44a2ca:/# <b>apt -y install cmake gcc g++ libncurses5-dev libreadline-dev libssl-dev make zlib1g-dev</b></div><div><i> => SoftEther VPN build에 필요한 몇가지 package를 설치한다. 추가로 필요한 패키지가 있다면, 적절히 설치해 주면 된다.</i></div><div><br /></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 예상대로 docker + QEMU 구조이다 보니, 전체적으로 느린 느낌이다.</span></div><div><br /></div><div><b style="background-color: #a2c4c9;"><SoftEther VPN build></b></div><div><i> => SoftEther VPN s/w와 관련해서는 아래 site 내용을 참조하자.</i></div><div><br /></div><div style="text-align: center;"><a href="https://github.com/SoftEtherVPN/SoftEtherVPN/blob/master/src/BUILD_UNIX.md">https://github.com/SoftEtherVPN/SoftEtherVPN/blob/master/src/BUILD_UNIX.md</a></div><div><br /></div><div>root@b2940a44a2ca:/# mkdir ~/workspace; cd workspace</div><div>root@b2940a44a2ca:/# <b>git clone https://github.com/SoftEtherVPN/SoftEtherVPN.git</b></div><div>root@b2940a44a2ca:/# <b>cd SoftEtherVPN</b></div><div>root@b2940a44a2ca:/# <b>git submodule init && git submodule update</b></div><div>root@b2940a44a2ca:/# <b>./configure</b></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 SoftEther VPN build를 위해서는 cmake 3.7 이상이 필요한데, Ubuntu 16.04는 3.6.1을 사용하고 있어 update해 주었다(자세한 과정은 생략).</span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;"><br /></span></div><div>root@b2940a44a2ca:/# <b>make -C build</b></div><div>root@b2940a44a2ca:/# <b>make -C build install</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYiJDv7LpbBRimqeC7m5s25hXG0pLt9xdKxI1GAcjRruNA19_SjDPK743QK0WMupJxGeaqeCO3gGZNFDI4UZn7D6CIjwRqOTFuhIegmGF7A2ffH7LLs8LeePeZHyzYVxV1o4oU2ENbFsti/s544/softether_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="451" data-original-width="544" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYiJDv7LpbBRimqeC7m5s25hXG0pLt9xdKxI1GAcjRruNA19_SjDPK743QK0WMupJxGeaqeCO3gGZNFDI4UZn7D6CIjwRqOTFuhIegmGF7A2ffH7LLs8LeePeZHyzYVxV1o4oU2ENbFsti/w400-h331/softether_output.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.2] softether vpn build 결과물</span></div><div><br /></div><div><div>root@b2940a44a2ca:/# <b>tar cvzf sebin.tar.gz /usr/local/lib/lib*.so /usr/local/libexec/softether/</b></div><div><i> => build 결과물을 tar.gz 파일로 묶어 보자.</i></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/bin/tar: Removing leading `/' from member names</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/lib/libcedar.so</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/bin/tar: Removing leading `/' from hard link targets</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/lib/libmayaqua.so</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnclient/</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnclient/vpnclient</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnclient/hamcore.se2</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpncmd/</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpncmd/hamcore.se2</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpncmd/vpncmd</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnserver/</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnserver/hamcore.se2</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnserver/vpnserver</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnbridge/</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnbridge/hamcore.se2</span></div><div><span style="color: #b6d7a8; font-size: x-small;">/usr/local/libexec/softether/vpnbridge/vpnbridge</span></div></div><div><br /></div><div>SoftEther VPN에 대한 build가 이루어졌으니, 이제부터는 build 결과 파일을 target board에 올린 후, vpnserver를 구동시켜 볼 차례이다. 편의상 지금부터는 (4장에서 설치한) OpenWrt 대신 Ubuntu 16.04를 사용하도록 하겠다.</div></div><div style="text-align: justify;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px; text-align: left;">📌 물론 OpenWrt에서도 SoftEther VPN을 구동시킬 수 있다. 이와 관련해서는 아래 site 내용이 도움이 될 것 같다.</span></div><div style="text-align: center;"><span style="background-color: white; font-size: 14.85px; text-align: left;"><span style="color: #ff00fe;"><a href="https://wordpress.tirlins.com/2015/03/setting-up-softether-vpn-on-openwrt/">https://wordpress.tirlins.com/2015/03/setting-up-softether-vpn-on-openwrt/</a></span></span></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px; text-align: left;"><br /></span></div><div style="text-align: justify;"><b style="text-align: left;"><font color="#38761d" size="4">6.2) MACCHIATObin 보드에 Ubuntu 16.04 설치 후, SoftEther VPN vpncmd 실행하기</font></b></div></div><div>Ubuntu 16.04 설치와 관련해서는 MACCHIATObin wiki page에 상세히 소개되어 있다. 따라서 아래 site의 내용을 반드시 읽어보기 바란다. 여기에서는 꼭 필요한 내용을 중심으로 간략히 정리하고 넘어가도록 하겠다.</div><div><br /></div><div> <a href="http://wiki.macchiatobin.net/tiki-index.php?page=Creating+Ubuntu+filesystem">http://wiki.macchiatobin.net/tiki-index.php?page=Creating+Ubuntu+filesystem</a></div><div> <a href="http://wiki.macchiatobin.net/tiki-index.php?page=Boot+from+removable+storage+-+Ubuntu">http://wiki.macchiatobin.net/tiki-index.php?page=Boot+from+removable+storage+-+Ubuntu</a></div><div><br /></div><div><b style="background-color: #76a5af;"><Desktop PC></b></div><div>$ <b>gunzip -c ./ubuntu-xenial-mcbin_u-boot_sd.img_.gz | sudo dd of=/dev/sdb</b></div><div><div><span style="font-size: x-small;">7577600+0 레코드 들어옴</span></div><div><span style="font-size: x-small;">7577600+0 레코드 나감</span></div><div><span style="font-size: x-small;">3879731200 bytes (3.9 GB, 3.6 GiB) copied, 1773.49 s, 2.2 MB/s</span></div></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 시간이 매우 오래 걸릴 수 있으니 주의하기 바란다.</span></div><div><br /></div><div><b style="background-color: #76a5af;"><Target board></b></div><div>Marvell>> <b>setenv bootmmc 'mmc dev 0; ext4load mmc 1:2 $kernel_addr $image_name;ext4load mmc 1:2 $fdt_addr $fdt_name;setenv bootargs $console root=/dev/mmcblk1p2 rw rootwait; booti $kernel_addr - $fdt_addr'</b></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 부트로더의 몇가지 설정을 변경해 준다. 자세한 사항은 위의 wiki page를 참조하도록 하자.</span></div><div><b><br /></b></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJg92gBnK2oZrn6vi9BcKxcvWjWZsvSHZzK0ONgX0nN7-bErDmy913ZZNrW4y_WtKJxYg4ZrFM6LFJfSPdZU7owjs75RJjvFkNx-XcKPzbhIkNYerH6oht4-WWGKs2flQgUI4MzgardHGJ/s833/mcbin_ubuntu1604.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="666" data-original-width="833" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJg92gBnK2oZrn6vi9BcKxcvWjWZsvSHZzK0ONgX0nN7-bErDmy913ZZNrW4y_WtKJxYg4ZrFM6LFJfSPdZU7owjs75RJjvFkNx-XcKPzbhIkNYerH6oht4-WWGKs2flQgUI4MzgardHGJ/w400-h320/mcbin_ubuntu1604.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.3] Ubuntu 16.04 부팅 모습</span></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div><div><i>Ubuntu 16.04.3 LTS localhost.localdomain ttyS0</i></div><div><i><br /></i></div><div><i>localhost login: <span style="color: #e69138;">root</span></i></div><div style="font-weight: bold;"><br /></div></div><div>root@localhost:~# <b>apt-get update</b></div><div>root@localhost:~# <b>apt-get install libncurses5-dev</b></div><div><div>root@localhost:~# <b>apt-get install libreadline-dev</b></div><div>root@localhost:~# <b>apt-get install libssl-dev</b></div><div>root@localhost:~# <b>apt-get install zlib1g-dev</b></div></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 SoftEther VPN 실행을 위해 필요한 몇가지 library를 설치해 주자. 설치가 불가한 경우에는 위의 library 파일을 docker 환경(6.1 절)에서 가져올 수도 있겠다.</span></div><div><br /></div><div><div>root@localhost:~# <b>su - chyi</b></div><div><i> => user chyi를 사전에 추가하였다.</i></div><div>chyi@localhost:~$ mkdir workspace; cd workspace</div></div><div><br /></div><div><b style="background-color: #76a5af;"><Desktop PC></b></div><div><div>chyi@mars:/var/lib/tftpboot$ <b>scp sebin.tar.gz chyi@192.168.2.1:~/workspace</b></div><div>chyi@192.168.1.1's password: </div><div><span style="font-size: x-small;">sebin.tar.gz 100% 14MB 63.6MB/s 00:00</span></div></div><div><br /></div><div><b style="background-color: #76a5af;"><Target board></b></div><div><div>chyi@localhost:~/workspace$ <b>tar xvzf sebin.tar.gz </b></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/lib/libcedar.so</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/lib/libmayaqua.so</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnclient/</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnclient/vpnclient</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnclient/hamcore.se2</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpncmd/</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpncmd/hamcore.se2</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpncmd/vpncmd</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnserver/</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnserver/hamcore.se2</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnserver/vpnserver</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnbridge/</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnbridge/hamcore.se2</span></div><div><span style="color: #3d85c6; font-size: x-small;">usr/local/libexec/softether/vpnbridge/vpnbridge</span></div></div><div><br /></div><div>chyi@localhost:~/workspace$ <b>export LD_LIBRARY_PATH=/home/chyi/workspace/usr/local/lib:$LD_LIBRARY_PATH</b></div><div>chyi@localhost:~/workspace$ <b>cd usr/local/libexec/softether/vpncmd</b></div><div><i> => OK, vpncmd가 동작한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggLgO9bZs_hqOWz6lUn_rSyHUSvRBHNQ1-3MHNGPweV3y_xLMuaCheUIv7xjwPf4aCvJOqq06qaXIJYkUOuUK4l3zwMnJXGK_8-o35ky65B5KGkplYtBliuRf2ztQHZ-RwfiMgD17p7ZkM/s901/mcbin_vpncmd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="310" data-original-width="901" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggLgO9bZs_hqOWz6lUn_rSyHUSvRBHNQ1-3MHNGPweV3y_xLMuaCheUIv7xjwPf4aCvJOqq06qaXIJYkUOuUK4l3zwMnJXGK_8-o35ky65B5KGkplYtBliuRf2ztQHZ-RwfiMgD17p7ZkM/w400-h138/mcbin_vpncmd.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.4] softether vpncmd 실행 모습</span></div><div><br /></div><div><b><font color="#38761d" size="4">6.3) SoftEther VPN 연결 시험하기</font></b></div><div><div>이 절에서는 MACCHATObin 보드에 VPN server를 설치하고, (인터넷 반대편에 있는) Windows10 PC에 VPN Client를 설치한 후, 이를 서로 연결하는 시험을 진행해 보도록 하겠다. 시험용 Testbed는 다음과 같다.</div></div><div><br /></div><div><b style="background-color: #b6d7a8;"><Testbed></b></div><div style="text-align: center;"><span style="color: #a64d79;">PC(<b>VPN Client</b>) => LTE Router <=== Internet ===> KT AP <= Small AP(repeater mode) <= MACCHATObin(<b>VPN Server</b>) <= Linux PC</span></div><div><br /></div><div><div>VPN server 구동에 앞서, MACCHIATObin을 gateway로 만들기 위해 kernel의 Netfilter 기능을 enable하는 작업을 먼저 진행해야 한다. </div><div><br /></div><div>Kernel code download & build 방법은 역시 아래 page에 잘 정리되어 있으니 이를 참조하도록 한다.</div><div><br /></div><div style="text-align: center;"><a href="http://wiki.macchiatobin.net/tiki-index.php?page=Build+from+source+-+Kernel">http://wiki.macchiatobin.net/tiki-index.php?page=Build+from+source+-+Kernel</a></div><div><br /></div></div><div><div>$ <b>export PATH=/home/chyi/workspace/mcbin/toolchain/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin:$PATH</b></div><div><br /></div><div>$ <b>git clone https://github.com/MarvellEmbeddedProcessors/linux-marvell .</b></div><div>$ <b>git checkout linux-4.4.52-armada-17.10</b></div><div>$ <b>git branch</b></div><div><span style="font-size: x-small;"> linux-3.10.70-15t1</span></div><div><span style="font-size: x-small;">* linux-4.4.52-armada-17.10</span></div><div><br /></div><div>$ <b>export ARCH=arm64</b></div><div>$ <b>export CROSS_COMPILE=aarch64-linux-gnu-</b></div><div>$ <b>make mvebu_v8_lsp_defconfig</b></div><div>$ <b>make menuconfig</b></div><div><i> => Netfilter 관련 설정은 꽤나 다양하니, 내용을 일일히 살펴본 후 적절히 enable시켜 주도록 한다(상세 내용 생략).</i></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhceQku7v9ygofK9Zo_81CWQqkCBxL0Af2Cy_dxb6tNSFC0X6W0BW6kDQlwDg_iGi54G0sP5O3V_K-rjjvtA3VeXdm7RUtGc6n92FIejDoC16nxyDUYRYXp5pcTulGBgXmxjpGtXwYo9Aee/s923/mcbin_netfilter_enable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="593" data-original-width="923" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhceQku7v9ygofK9Zo_81CWQqkCBxL0Af2Cy_dxb6tNSFC0X6W0BW6kDQlwDg_iGi54G0sP5O3V_K-rjjvtA3VeXdm7RUtGc6n92FIejDoC16nxyDUYRYXp5pcTulGBgXmxjpGtXwYo9Aee/w400-h258/mcbin_netfilter_enable.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.5] Netfilter enable하기</span></div><br /><div>$ <b>make -j4</b></div><div><br /></div><div>Kernel compile이 완료되었으니, arch/arm64/boot/Image 파일을 target board에 올린 후, 부팅을 시도해 보자.</div><div><br /></div><div><b style="background-color: #76a5af;"><Target board></b></div><div>root@localhost:~# <b>echo 1 > /proc/sys/net/ipv4/ip_forward</b></div><div>root@localhost:~# <b>iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE</b></div><div><i> => 시스템 부팅 후에는 ip_forwarding을 1로 설정하고, masquerading NAT rule을 하나 추가해 준다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRLPzi1bZMTurZck8AyqPK3TrcW6a8qKdaA7czvOdfMJfnEaGR50L0k4JvpvI57qqLtNjr7omgvXGiyYha4gWoyofiNokH6AAXrNjP3rlk_xsuPBUA-J5YXFTsdDUPSGpCjJdPrw4YqGv6/s756/mcbin_masquerade.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="756" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRLPzi1bZMTurZck8AyqPK3TrcW6a8qKdaA7czvOdfMJfnEaGR50L0k4JvpvI57qqLtNjr7omgvXGiyYha4gWoyofiNokH6AAXrNjP3rlk_xsuPBUA-J5YXFTsdDUPSGpCjJdPrw4YqGv6/w400-h141/mcbin_masquerade.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.6] iptables masquerading rule 설정</span></div><br /><div>OK, 이 상태에서 정상적으로 인터넷 접속이 되는 것을 확인했다면, 이제 부터는 vpnserver & vpncmd 설정을 시작할 준비할 차례다.</div><div><br /></div><div><b style="background-color: #76a5af;"><Target board></b></div><div><div># <b>export LD_LIBRARY_PATH=/home/chyi/workspace/usr/local/lib:$LD_LIBRARY_PATH</b></div><div># cd usr/local/libexec/softether/vpnserver/</div><div># <b>./vpnserver start</b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj5k1obyke8bcHt2iVozI-I1Dn7L-eQY3YiPhdnUm1KLSLkPuqFt5kE69kvAluHDNNsXnDdQHmQFXayH24fra9a_A5JWJZTSag8tHspl64UM2FjDGC_0siSzaiUPNtKYiY1CVPXFQkoFui/s933/mcbin_vpnserver.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="137" data-original-width="933" height="59" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj5k1obyke8bcHt2iVozI-I1Dn7L-eQY3YiPhdnUm1KLSLkPuqFt5kE69kvAluHDNNsXnDdQHmQFXayH24fra9a_A5JWJZTSag8tHspl64UM2FjDGC_0siSzaiUPNtKYiY1CVPXFQkoFui/w400-h59/mcbin_vpnserver.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.7] vpnserver 실행 모습</span></div><div><br /></div><div># cd ../vpncmd</div><div>#<b> ./vpncmd</b></div><div><i> => 여기서는 VPN Server admin password만을 설정하도록 한다. 나머지 복잡한 설정은 VPN Server manager를 통해 진행할 것이다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHkuo0x8wiUQAX-KXj5iQ9S18Vj_-BqNJ5i0Bxi5WUIZl6EN1mmuTkSuJn6Zx8M4nINIu_eIuGUXCJcvekVB3k13ILIUM78e-WIZJ8W_FUjgMDQ70u9HKovDLz5pF8GTzdSjyUwDziORC-/s898/mcbin_vpncmd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="776" data-original-width="898" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHkuo0x8wiUQAX-KXj5iQ9S18Vj_-BqNJ5i0Bxi5WUIZl6EN1mmuTkSuJn6Zx8M4nINIu_eIuGUXCJcvekVB3k13ILIUM78e-WIZJ8W_FUjgMDQ70u9HKovDLz5pF8GTzdSjyUwDziORC-/w400-h346/mcbin_vpncmd.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.8] vpncmd 실행 후 VPN Server admin password 지정 모습</span></div><div><br /></div><div><div>다음으로 VPN Server Manager를 이용하여 VPN Server에 대한 상세 설정을 진행한다(자세한 설정 과정은 생략).</div><div style="text-align: center;"><b>Windows 10 PC(VPN Server Manager) ==> MACCHIATObin board(LAN port)</b></div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 </span><span style="color: #ff00fe;">VPN Server Manager & VPN Client Manager 상세 설정 방법은 아래 site에 자세히 정리해 두었으니, 이를 참조하도록 하자(같은 내용을 반복해서 설명하지는 않겠음^^).</span></div><div><div><br /></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/spnhacks/blob/master/telecommuting_spn_solution/2ip_L2SPN_Setup_Guide12.pdf">https://github.com/ChunghanYi/spnhacks/blob/master/telecommuting_spn_solution/2ip_L2SPN_Setup_Guide12.pdf</a></div></div><div style="text-align: center;"><br /></div></div><div style="text-align: left;">VPN Server 설정이 끝난 후에는 아래와 같이 bridge 및 dhcp server 설정을 진행하도록 하자.</div><div style="text-align: left;"><br /></div><div><b style="background-color: #76a5af;"><Target board></b></div><div><i> => 먼저 bridge 설정을 해 준다. bridge 설정 대상은 eth0와 tap_vpn(<span style="color: #3d85c6;">VPN server 설정시 생성되는 tap 기반 interface</span>)이다.</i></div><div>root@localhost:~# <b>ifconfig eth0 0.0.0.0</b></div><div><div>root@localhost:~# <b>brctl addbr br0</b></div><div>root@localhost:~# <b>brctl addif br0 eth0</b></div><div>root@localhost:~# <b><span style="color: #b45f06;">brctl addif br0 tap_vpn</span></b></div><div><i><span style="color: #990000;"> => 얘는 VPN Server Manager에서 설정해 주어야만 생성이 된다.</span></i></div><div>root@localhost:~# <b>ifconfig br0 192.168.2.1 netmask 255.255.255.0 up</b></div><div>root@localhost:~# <b>brctl show</b></div><div>bridge name bridge id STP enabled interfaces</div><div>br0 8000.005182112200 no eth0</div><div> tap_vpn</div></div><div><br /></div><div>다음으로 br0 interface(LAN interface)를 대상으로 dhcp server를 구동시켜 주어야 한다. </div><div><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 </span><span style="color: #ff00fe;"><span>dhcp server가 없으면</span>, vpn client가 vpn server에 연결한 후, ip 주소 & default gw 설정을 못하게 되어 vpn 연결이 완성되지 못하는 문제가 발생한다.</span></div><div><br /></div><div>root@localhost:~# <b>apt-get install isc-dhcp-server</b></div><div>root@localhost:~# <b>vi /etc/dhcp/dhcpd.conf </b></div><div><i> => 기존 내용을 모두 지우고, 아래 정보를 입력하도록 한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9eL99fptwdJjlWj3oJrLBCryJ4Nn2qNJin4EDTEkjs1zNJoRj14uT01KexU5N-CfrAJQGU5useAm1ePqNdBYHNrZDO-dTbH52cwrFvHsCujjnulYeoNrnlD9E1tZxX4u0azoiFs1Toyuj/s404/mcbin_br0_dhcpd_conf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9eL99fptwdJjlWj3oJrLBCryJ4Nn2qNJin4EDTEkjs1zNJoRj14uT01KexU5N-CfrAJQGU5useAm1ePqNdBYHNrZDO-dTbH52cwrFvHsCujjnulYeoNrnlD9E1tZxX4u0azoiFs1Toyuj/s320/mcbin_br0_dhcpd_conf.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.9] /etc/dhcp/</span><span style="text-align: left;">dhcpd.conf 수정 내용</span></div><div>root@localhost:~# <b>vi /etc/default/isc-dhcp-server</b></div><div><i> => 아래와 같이 br0 interface 정보를 추가한다.</i></div><div>...</div><div>INTERFACES="<b><span style="color: #b45f06;">br0</span></b>"</div><div>~</div><div>root@localhost:~# <b>systemctl restart isc-dhcp-server</b></div><div><i> => dhcp server를 재구동시킨다.</i></div><div><br /></div><div>지금까지 설정한 내용(vi 편집 내용 제외)을 하나의 shell script로 정리해 보면 다음과 같다. 부팅시 이 파일이 실행되도록 만들어 주면 편리할 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqUnzK_8rIkRzea2w-pWEQQKsi_LadbC-RRmMeZRMlrCImeER8LNpRfzkflvPCULdqtpr_dRCJghSVbGFTfqkOdZVewbd2BOX69IDByUSjQ979WoBiHlfexAzYJrcSoFsFT3xICETR8zr2/s685/mcbin_netsh.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="347" data-original-width="685" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqUnzK_8rIkRzea2w-pWEQQKsi_LadbC-RRmMeZRMlrCImeER8LNpRfzkflvPCULdqtpr_dRCJghSVbGFTfqkOdZVewbd2BOX69IDByUSjQ979WoBiHlfexAzYJrcSoFsFT3xICETR8zr2/w400-h203/mcbin_netsh.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.10] MACCHIATObin network 설정 내용 정리</span></div><div style="text-align: center;"><br /></div><div>자, 모든 것(VPN Server 설정)이 준비되었으니, VPN Client(Windows 10)에서 VPN Client Manager를 통해 vpn 연결을 시도해 보기로 하자(VPN client manager 설정 화면에 대한 설명은 생략).</div><div><br /></div><div style="text-align: justify;"><b style="text-align: center;"> Windows 10 PC(<span style="color: #e69138;">VPN Client Manager</span>) => 인터넷 => MACCHIATObin board(WAN port)</b></div><div style="text-align: justify;"><br /></div><div><span style="text-align: center;">VPN 연결이 성공한 후 ip 정보를 확인해 보니, 마치 VPN Gateway 내부에 위치한 것 처럼</span> ip: 192.168.2.101이고, default gateway: 192.168.2.1 임을 알 수 있다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg54ord7A_H8MWdBt6AFhWHOK7WdDdNB1YqySx9-9EwKgBHZnWxphHqn_IeCOK0IhQ_J6Hrs1r81DinBESbhiU0tm4xm8C-P9tbFeJQ_bfi-P9IDhwquEPOqOWWGtLHWEUY9zgdzEgxcwfI/s1223/mcbin_vpn_client2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="826" data-original-width="1223" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg54ord7A_H8MWdBt6AFhWHOK7WdDdNB1YqySx9-9EwKgBHZnWxphHqn_IeCOK0IhQ_J6Hrs1r81DinBESbhiU0tm4xm8C-P9tbFeJQ_bfi-P9IDhwquEPOqOWWGtLHWEUY9zgdzEgxcwfI/w400-h270/mcbin_vpn_client2.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.11] VPN 연결 후, VPN Client ip 주소 할당 내용 확인</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;">C:\> <b>ping www.google.co.kr</b></div><div class="separator" style="clear: both; text-align: left;"><i> => OK, ping도 정상이다.</i></div><div><br /></div><div><span style="text-align: justify;">C:\> <b>ssh chyi@192.168.2.1</b></span></div><div><span style="text-align: justify;"><i> => Target board로 ssh login도 가능하다.</i></span></div><div><span style="text-align: justify;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid6U-p7FIre2TqSIVVj7CT6Wp_gso9UvyqyHFw9gVOtoTQr76K-DhxoXUSalnjVfjrHVq6VGDZ7LOhTKa3xSTmB0ZeI93Oex2XHC_MsojRnBdZ1sIy6brGAV0QF7T4qf7iMm9mKI4I0tT4/s983/mcbin_vpn_client4.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="939" data-original-width="983" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid6U-p7FIre2TqSIVVj7CT6Wp_gso9UvyqyHFw9gVOtoTQr76K-DhxoXUSalnjVfjrHVq6VGDZ7LOhTKa3xSTmB0ZeI93Oex2XHC_MsojRnBdZ1sIy6brGAV0QF7T4qf7iMm9mKI4I0tT4/s320/mcbin_vpn_client4.PNG" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.12] VPN Client PC에서 VPN Server에 ssh login 모습 </span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><span style="background-color: white; color: #ff00fe; font-size: 14.85px;">📌 SoftEther VPN(a.k.a SSL VPN)은 Ethernet Frame을 통째로 tunnel에 넣어 전달하기 때문에, (VPN Client가 설치된 PC 입장에서 볼 때) 마치 긴 LAN cable을 VPN Gateway의 LAN port에 연결한 듯한 착각을 일으키게 하는 특징(장점)이 있다. 쉽게 말해 집에 있지만 사무실 망에 연결되어 있는 것과 동일한 효과를 내게 해준다.</span></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">끝으로 아래 그림은 VPN client PC에서 (VPN server를 경유하여) internet 접속(web browser)을 할 경우의 최대 CPU 사용량(max: 50% 육박)을 보여주고 있다. 50%는 최악의 상황인 듯 보이며, (편차가 있기는 하지만) 대략 20 ~ 30% 정도의 CPU 점유율을 보여준다(생각보다 좀 많이 먹는 느낌이다).</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFOAvcjLIYHHc_eBX1Qo9swdMR-xr8cQSPGdVCRbW6m3WIidKJ1DGMRb3qa3MPdHo-t0BVaSJV_mmfFwMLPDQWsY13MplouiV0KHTBz1XYoOTHtHrfriaFjWZq4UA8TO23s5F08VyjGtB4/s905/mcbin_softether_top2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="782" data-original-width="905" height="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFOAvcjLIYHHc_eBX1Qo9swdMR-xr8cQSPGdVCRbW6m3WIidKJ1DGMRb3qa3MPdHo-t0BVaSJV_mmfFwMLPDQWsY13MplouiV0KHTBz1XYoOTHtHrfriaFjWZq4UA8TO23s5F08VyjGtB4/w400-h346/mcbin_softether_top2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.13] VPN Server의 CPU 점유율 </span></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">이상으로 MACCHIATObin 보드에 SoftEther VPN server를 올리고, VPN Client로 접속(Remote access)하는 시험을 해 보았다. 실험 결과, <span style="color: #0b5394;">성능 좋은 Intel CPU 보다는 못하지만, MACCHIATObin을 SoftEther VPN Gateway로 사용하지 못할 이유는 없어 보인다^^.</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div>______________________________</div><div><br /></div><div>지금까지 MACCHIATObin 보드를 가지고, 이런 저런 시험을 진행해 보았다. 제목에서 보듯이 이번 blog post의 원래 의도는 5장(Ethernet device driver 분석)을 상세히 소개하는 것이었으나, 내용 정리를 하다보니 docker와 SoftEther VPN(6장)에 관한 내용으로 설명이 편중된 느낌이다.</div><div><br /></div><div>언제나 그렇듯 미흡한 부분은 추후 좀 더 보충할 것을 기약하며 이번 글을 마치도록 하겠다. 이 글이 어느 누군가에게 조금이라도 도움이 되었으면 하는 바램을 가져본다. 😋</div><div><br /></div></div><div><div><br /></div></div><div><br /></div><div><b><font color="#3d85c6" size="6">7. References</font></b></div><div>[1] <a href="http://espressobin.net/espressobin-ultra-build-instruction/">http://espressobin.net/espressobin-ultra-build-instruction/</a> </div><div>[2] ESPRESSObin ULTRA- Quick Start Guide -Rev 03</div><div>[3] <span style="color: #990000;">Ethernet switch support in the Linux kernel</span>, Alexandre Belloni, Bootlin</div></div><div>[4] <span style="color: #990000;">From the Ethernet MAC to the link partner</span>, Maxime Chevallier, Antoine Ténart, Bootlin</div><div>[5] <a href="https://docplayer.net/50750816-Distributed-switch-architecture-a-k-a-dsa.html">Distributed Switch Architecture, A.K.A DSA, Andrew Lunn, Vivien Didelot, Florian Fainelli</a></div><div>[6] marvell-link-street-88E6341-product-brief.pdf</div><div>[7] http://wiki.macchiatobin.net/tiki-index.php?page=BSP+HowTo</div><div>[8] https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04</div><div>[9] http://pyrasis.com/Docker/Docker-HOWTO#ps</div><div>[10] https://www.stereolabs.com/docs/docker/building-arm-container-on-x86/</div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#38761d">SlowBoot</font></b></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com1tag:blogger.com,1999:blog-6346200245600677355.post-61892053152822107812020-09-12T18:03:00.005+09:002020-09-20T17:29:12.542+09:00ESPRESSObin Ultra 보드와 MACCHIATObin 보드의 Switch & Ethernet Device Driver 분석이번 blog post 부터는 앞으로 몇차례에 걸쳐 Marvell chip을 사용하는 <a href="http://espressobin.net/">ESPRESSObin Ultra 보드</a>와 <a href="https://macchiatobin.net/">MACCHIATObin 보드</a>에 관한 이야기(네트워크 관련)를 해 보고자 한다. 😎 이번에 소개하는 보드는 본 blog의 취지(?)하고는 맞지 않게 좀 비싼 보드들이다. 🏂<div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1w6jh95igM3gAVSlcWX2SzNBbutJCWwFh2ieFRykGENWB-7ZkiAq-6sJbp6sbXLwaVQplKS2Eae9sMNeNJeTEqlzPGq5IQJLUhL1U5A1KbDWz3dyGjloF-117f1iN3LhY6dqiz5MngiP/s272/espressobin_ultra.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="185" data-original-width="272" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir1w6jh95igM3gAVSlcWX2SzNBbutJCWwFh2ieFRykGENWB-7ZkiAq-6sJbp6sbXLwaVQplKS2Eae9sMNeNJeTEqlzPGq5IQJLUhL1U5A1KbDWz3dyGjloF-117f1iN3LhY6dqiz5MngiP/w160-h109/espressobin_ultra.jpeg" width="160" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJ6Xgbu_jaZ_J93HLA3OASY2TgR12rZwwxDnj1bQGH_1X9jH9KYivVBKlx227SWiCXPUj9deZpjqeQhyphenhyphenBDULDPv4qZzwZMc8FE4kMLTa4hwAPEYZOo_nqRf8d9i25NfTD5V2crv6bWbe6/s248/macchiatobin_board.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="201" data-original-width="248" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJJ6Xgbu_jaZ_J93HLA3OASY2TgR12rZwwxDnj1bQGH_1X9jH9KYivVBKlx227SWiCXPUj9deZpjqeQhyphenhyphenBDULDPv4qZzwZMc8FE4kMLTa4hwAPEYZOo_nqRf8d9i25NfTD5V2crv6bWbe6/w198-h161/macchiatobin_board.png" width="198" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVgL4HG5x2_SM9ifj5SVyYxpS6gUPnGj1Qq1j9rLp_3feJ_Wm4IgR_o5znQJzHaH1m6hrfSQcTaXUoGCxGA5ThUM3wxxIv01osA8go0vM60Je_cXaJwWTFI9Z0BVi42pCPpJx1NMUuydk/s225/docker.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVgL4HG5x2_SM9ifj5SVyYxpS6gUPnGj1Qq1j9rLp_3feJ_Wm4IgR_o5znQJzHaH1m6hrfSQcTaXUoGCxGA5ThUM3wxxIv01osA8go0vM60Je_cXaJwWTFI9Z0BVi42pCPpJx1NMUuydk/w144-h144/docker.png" width="144" /></a></div><div><br /></div><div><b><span style="font-size: medium;">목차</span></b></div><div><i><b>1. Docker 환경 설정</b></i></div><div><i><b>2. ESPRESSObin Ultra 보드 소개</b></i></div><div><i><b>3. ESPRESSObin Ultra 보드의 Switching Device Driver 분석</b></i></div><div><i>4. MACCHIATObin 보드 소개</i></div><div><i>5. </i><i>MACCHIATObin 보드의 </i><i>Ethernet Device Driver 분석</i></div><div><i>6. 응용편: </i><i>MACCHIATObin 보드를 SoftEther VPN Gateway로 만들기</i></div><div><i><b>7. References</b></i></div><div><br /></div><div><br /></div><div><div><div><b><font color="#3d85c6" size="6">1. Docker 환경 설정 </font></b><b><span style="color: #b45f06;">🐋</span></b></div><div>본론에 들어가기에 앞서서, 이번 장에서는 docker를 기반으로 개발 환경을 꾸미는 과정을 먼저 소개해 보고자 한다. Docker는 개발 환경을 맞추기 어려운 경우(예: PC Ubuntu 18.04 64bit <=> 실제로 필요한 환경 Ubuntu 12.04 32bit)에 이를 효과적으로 해결하는데 도움을 준다. 물론 VMware나 VirtuaBox와 같은 가상 환경을 사용해도 좋지만, 성능 면에서 볼 때 docker가 보다 효과적이라 볼 수 있다. <span style="color: #b45f06;">Build하는데만 반나절 이상 걸리는 project(예: Android, Yocto ...)를 상상해 보라 ... VirtualBox로 build 하던 도중 resource 부족 문제로 중단되어 버린 경험이 있는 개발자라면, docker가 대안이라는 것을 쉽게 알 수 있을 것이다.</span></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><img border="0" data-original-height="482" data-original-width="900" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPxHswj6jqePCM_yr3BfzYijGb5q53j7RIxLrM1mZ8E9CemA6SmF9iR4gZp6OcLD3_UQII03b10EQmxTWMqfQHhj0o_35MrOC5jRe9SiOedjeCIyXkwItW-CBkiO_PYumlvCssMyFBVE0m/w500-h268/docker_arch.jpeg" width="500" /></div><div class="separator" style="clear: both; text-align: center;">[그림 1.1] Docker 아키텍쳐</div><div class="separator" style="clear: both; text-align: center;"><b>[출처: https://www.iconspng.com/image/48298/docker-architecture]</b></div><div><br /></div><div>Docker를 활용하는 방법에 관해서는 이미 (3년 전에) 한 차례 소개한 바가 있다.</div><div><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2017/02/how-to-build-android-sources-for-udoo.html">https://slowbootkernelhacks.blogspot.com/2017/02/how-to-build-android-sources-for-udoo.html</a></div><div><br /></div><div><b><font color="#38761d">1.1) Docker 설치</font></b></div><div>이 절에서 소개하는 내용은 (기본적으로) 아래 site 내용을 참고하였다.</div><div><br /></div><div style="text-align: left;"> <i> 1) <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04">https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04</a></i></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><i> 2) <a href="http://pyrasis.com/Docker/Docker-HOWTO#">http://pyrasis.com/Docker/Docker-HOWTO#</a></i></div><div> <i> => docker 명령어 사용법을 아주 간결하게 설명해 주고 있다. 👍💯</i></div><div><br /></div><div><br /></div><div><span style="background-color: #ffd966;"><b><Desktop PC - ubuntu 18.04></b></span></div><div>$ <b>sudo apt update</b></div><div> => <i> 먼저, package database를 update해 준다.</i></div><div><br /></div><div>$ <b>sudo apt install apt-transport-https ca-certificates curl software-properties-common</b></div><div><i> => apt가 HTTPS를 사용하여 package를 설치하기 위해 필요한 몇가지 패키지를 설치한다.</i></div><div><br /></div><div>$ <b>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</b></div><div><i> => 공식 docker repository용 GPG key를 추가한다.</i></div></div><div><br /></div><div><div>$ <b>sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"</b></div><div><i> => APT source에 docker repository를 추가한다.</i></div><div><br /></div><div>$ <b>sudo apt update</b></div><div><i> => docker repository가 추가되었으니, package database를 다시 한번 update한다.</i></div><div><br /></div><div>$ <b>apt-cache policy docker-ce</b></div><div><i> => 설치할 docker 후보를 확인해 본다(<span style="color: #666666;">이 과정은 반드시 필요한 과정은 아님</span>).</i></div><div><br /></div><div>$ <b>sudo apt install docker-ce</b></div><div><i> => 실제로 docker ce(community edition)를 설치한다.</i></div><div><br /></div><div>$ <b>sudo systemctl status docker</b></div><div><i> => 설치 후, 아래와 같은 내용이 출력된다면 정상적으로 설치가 된 것이다.</i></div><div><br /></div><div><div><span style="color: #6aa84f; font-size: x-small;">● docker.service - Docker Application Container Engine</span></div><div><span style="color: #6aa84f; font-size: x-small;"> Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)</span></div><div><span style="color: #6aa84f; font-size: x-small;"> Active: active (running) since Wed 2020-09-09 10:52:56 KST; 17s ago</span></div><div><span style="color: #6aa84f; font-size: x-small;"> Docs: https://docs.docker.com</span></div><div><span style="color: #6aa84f; font-size: x-small;"> Main PID: 22955 (dockerd)</span></div><div><span style="color: #6aa84f; font-size: x-small;"> Tasks: 11</span></div><div><span style="color: #6aa84f; font-size: x-small;"> CGroup: /system.slice/docker.service</span></div><div><span style="color: #6aa84f; font-size: x-small;"> └─22955 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock</span></div><div><span style="color: #6aa84f; font-size: x-small;"><br /></span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.135659400+09:00" level=warning msg="Your k</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.135663932+09:00" level=warning msg="Your k</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.135668335+09:00" level=warning msg="Your k</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.135766281+09:00" level=info msg="Loading c</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.352215690+09:00" level=info msg="Default b</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.387724446+09:00" level=info msg="Loading c</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.430656835+09:00" level=info msg="Docker da</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.430851347+09:00" level=info msg="Daemon ha</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars dockerd[22955]: time="2020-09-09T10:52:56.444891890+09:00" level=info msg="API liste</span></div><div><span style="color: #6aa84f; font-size: x-small;"> 9월 09 10:52:56 mars systemd[1]: Started Docker Application Container Engine.</span></div></div><div><br /></div></div><div><div>$ <b>ps aux|grep docker</b></div><div><i> => docker를 설치하면 실제로 dockerd라는 daemon이 하나 구동되게 된다.</i></div><div><span style="font-size: x-small;">root 22955 0.3 1.0 976400 82544 ? Ssl 10:52 0:00 <span style="color: #b45f06;">/usr/bin/dockerd</span> -H fd:// --containerd=/run/containerd/containerd.sock</span></div><div><span style="font-size: x-small;">chyi 23498 0.0 0.0 15720 1068 pts/1 S+ 10:53 0:00 grep --color=auto docker</span></div></div><div><br /></div><div><div>$ <b>sudo usermod -aG docker chyi</b></div><div> <i>=> sudo 없이 docker 명령을 바로 사용할 수 있도록 자신의 계정을 docker group에 추가해 주자.</i></div><div>$ <b>su - chyi</b></div></div><div><i> => 계정 전환을 하고 난 후에는 </i><i>sudo 없이 docker 명령 실행 가능해짐.</i></div><div><i> => 혹은 logout 후 다시 login하게 되면 sudo 없이 docker 명령 실행 가능해짐.</i></div><div><br /></div><div><div>chyi@mars:~$ <b>docker info</b></div><div><span style="color: #3d85c6; font-size: x-small;">Client:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Debug Mode: false</span></div><div><span style="color: #3d85c6; font-size: x-small;"><br /></span></div><div><span style="color: #3d85c6; font-size: x-small;">Server:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Containers: 2</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Running: 0</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Paused: 0</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Stopped: 2</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Images: 1</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Server Version: 19.03.12</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Storage Driver: overlay2</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Backing Filesystem: extfs</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Supports d_type: true</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Native Overlay Diff: true</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Logging Driver: json-file</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Cgroup Driver: cgroupfs</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Plugins:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Volume: local</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Network: bridge host ipvlan macvlan null overlay</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Swarm: inactive</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Runtimes: runc</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Default Runtime: runc</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Init Binary: docker-init</span></div><div><span style="color: #3d85c6; font-size: x-small;"> containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429</span></div><div><span style="color: #3d85c6; font-size: x-small;"> runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd</span></div><div><span style="color: #3d85c6; font-size: x-small;"> init version: fec3683</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Security Options:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> apparmor</span></div><div><span style="color: #3d85c6; font-size: x-small;"> seccomp</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Profile: default</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Kernel Version: 5.4.0-45-generic</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Operating System: Ubuntu 18.04.2 LTS</span></div><div><span style="color: #3d85c6; font-size: x-small;"> OSType: linux</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Architecture: x86_64</span></div><div><span style="color: #3d85c6; font-size: x-small;"> CPUs: 4</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Total Memory: 7.673GiB</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Name: mars</span></div><div><span style="color: #3d85c6; font-size: x-small;"> ID: E4YZ:D7CM:RT6Y:U673:ACHU:7C6C:2QTK:UVKV:ZZS2:KOUD:5EVW:LUZR</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Docker Root Dir: /var/lib/docker</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Debug Mode: false</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Registry: https://index.docker.io/v1/</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Labels:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Experimental: false</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Insecure Registries:</span></div><div><span style="color: #3d85c6; font-size: x-small;"> 127.0.0.0/8</span></div><div><span style="color: #3d85c6; font-size: x-small;"> Live Restore Enabled: false</span></div><div><span style="color: #3d85c6; font-size: x-small;"><br /></span></div><div><span style="color: #3d85c6; font-size: x-small;">WARNING: No swap limit support</span></div></div><div><br /></div><div><b><font color="#38761d">1.2) Docker 상에 Ubuntu 18.04 설치</font></b></div><div>Docker가 설치되었으니, 이제부터는 실제 개발 환경(Ubuntu 18.04와 Ubuntu 16.04)를 꾸며 보도록 하겠다. 이 절에서는 우선 (ESPRESSObin Ultra 보드를 위해) Ubuntu 18.04 환경을 먼저 만들어 보도록 하겠다(MACCHIATOBin 보드를 위한 Ubuntu 16.04는 4장에서 설치한다).</div><div><br /></div><div>$ cd ~/workspace</div><div>$ <b>vi Dockerfile_ubuntu1804</b></div><div><i> => 파일을 하나 열고 아래와 같은 내용을 입력하자.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbNL-qres9_GaoAm5GQtC0dazgkgQZJU_twVutyFqstuG_YESo_BzMgdnopy93kt4NmugFJaeMXJoMmhYi261rfYCQVwCVt3N7rsDwg1khwAoN33I_UqIN4tI4AABIbvAUnSIVMWsh5UrO/s571/dockerfile_u1804.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="571" data-original-width="447" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbNL-qres9_GaoAm5GQtC0dazgkgQZJU_twVutyFqstuG_YESo_BzMgdnopy93kt4NmugFJaeMXJoMmhYi261rfYCQVwCVt3N7rsDwg1khwAoN33I_UqIN4tI4AABIbvAUnSIVMWsh5UrO/s320/dockerfile_u1804.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] Dockerfile_ubuntu1804 파일 내용</div><div><br /></div><div>📌 <span style="color: #ff00fe;">ubuntu, centos, redis 등 OS나 program의 이름을 가진 이미지가 공식 이미지이다. 한편 ubuntu:18.04 처럼 뒤에 tag를 붙여 주면 해당 버젼을 내려 받게 된다. tag 자리에 latest를 적어 주면 최신 버젼을 받게 된다. 또한 32bit 버젼을 download 받고 싶다면 i386/ubuntu:12.04 이런 식으로 명시해 주면 된다.</span></div><div>📌 <span style="color: #ff00fe;">Dockerfile 대신 "docker pull ubuntu:18.04" 명령 수행 후, docker run 하여 필요한 package를 설치해도 된다.</span></div><div><span style="color: #ff00fe;">📌 Dockerfile 작성 방법과 관련해서는 아래 site를 참조하기 바란다.</span></div><div style="text-align: center;"><span style="color: #444444;"><a href="https://docs.docker.com/engine/reference/builder/">https://docs.docker.com/engine/reference/builder/</a></span></div><div><span style="color: #ff00fe;"><br /></span></div><div><div>$ <b>docker build -f <span style="color: #b45f06;">Dockerfile_ubuntu1804</span> -t u1804 .</b></div><div><i> => 앞서 작성한 Dockerfile을 토대로 docker image를 생성하도록 하자. 마지막의 '.' 을 빼먹으면 안된다.</i></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6BB5SpeuRuwWbEOrGrN14BQQqcDfeqpTj72sUWo9eHamNC2vT80SXXD9qoej6Hf0z9VDMxd8cZGR_D1lEpe7akloxC4sho1Q2aljXJrJFqUaZ5cyneE8p9OrBBkvsrDhRkadYDzugPpux/s925/docker_image_gen_succ.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="613" data-original-width="925" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6BB5SpeuRuwWbEOrGrN14BQQqcDfeqpTj72sUWo9eHamNC2vT80SXXD9qoej6Hf0z9VDMxd8cZGR_D1lEpe7akloxC4sho1Q2aljXJrJFqUaZ5cyneE8p9OrBBkvsrDhRkadYDzugPpux/w400-h265/docker_image_gen_succ.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">[그림 1.3] Dockerfile_ubuntu1804 파일을 이용하여 docker image 생성 모습</div><div><br /></div></div><div>$ <b>docker images</b></div><div><i> => 생성된 docker image를 출력해 보면 다음과 같다. 아래 내용 중 u1804가 새로 생성된 docker image이다.</i></div><div><i> => ubuntu 18.04가 ubuntu 18.04 original image이다. 참고로, 아래 내용 중에는 이전에 설치한 몇가지 이미지가 함께 출력되고 있다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrZfxTklC0uJGb4HTMGmmWokFNnffS3gTmf1wRanyiOEnXBSdzouPh4Nqkou7gZ3TXrT1mQIMZjgaxeCjI1Gf9OHGnrPKtZUuYZHcj0MTzk8Nodlge0xiXirqiWkcCxFGRz1oySqgfJjPC/s973/docker_images.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="143" data-original-width="973" height="93" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrZfxTklC0uJGb4HTMGmmWokFNnffS3gTmf1wRanyiOEnXBSdzouPh4Nqkou7gZ3TXrT1mQIMZjgaxeCjI1Gf9OHGnrPKtZUuYZHcj0MTzk8Nodlge0xiXirqiWkcCxFGRz1oySqgfJjPC/w625-h93/docker_images.png" width="625" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.4] 생성된 docker image</div><div><br /></div><div>$ <b>docker run -i -t --name <span style="color: #741b47;">esbin1804</span> u1804 <span style="color: #38761d;">/bin/bash</span></b></div><div><i> => 새로 생성한 docker image를 실행(container라고 함)해 보도록 하자.</i></div><div><br /></div><div><div>root@26de74ece3fd:/# <b>uname -a</b></div><div><span style="font-size: x-small;">Linux 26de74ece3fd 5.4.0-45-generic #49~18.04.2-Ubuntu SMP Wed Aug 26 16:29:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux</span></div></div><div><br /></div><div>(Dockerfile에 누락된) 몇가지 package를 추가로 설치해 보도록 하자.</div><div><br /></div><div>root@26de74ece3fd:/# <b>apt-get install ssh</b></div><div><i> => docker ubuntu 18.04에 ssh server를 설치한다.</i></div><div><div><br /></div><div>root@26de74ece3fd:/# <b>apt-get install vim</b></div><div><i> => vim도 설치하자.</i></div></div><div><div><br /></div><div>root@26de74ece3fd:/# <b>vi /etc/ssh/sshd_config</b></div><div><i> => ssh root login을 위해 아래 내용을 추가하자.</i></div><div>...</div><div><div><span style="color: #6aa84f;">#PermitRootLogin prohibit-password</span></div><div><span style="color: #6aa84f;">PermitRootLogin yes</span></div></div><div>...</div><div><br /></div><div><div>root@26de74ece3fd:/#<b> service ssh restart</b></div><div><i> => ssh server를 재구동시키자.</i></div></div><div><br /></div><div>root@26de74ece3fd:/# <b>apt-get install net-tools</b></div><div><i> => ifconfig 등의 명령을 위해 net-tools를 설치한다.</i></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivM4BfZ27mvoY_ijZzZduZKMoEIgHUZrSKrif7z4ZF9W83K7719jZFA67NWXo7mYpjQzDQ7JY__hgJI4YGoKpLOBS55EQjSrc4JJz1pOIutva-lH2m2gdAwKqdB2zjZ0RAogdysEpu4pfN/s649/docker_ifconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="306" data-original-width="649" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivM4BfZ27mvoY_ijZzZduZKMoEIgHUZrSKrif7z4ZF9W83K7719jZFA67NWXo7mYpjQzDQ7JY__hgJI4YGoKpLOBS55EQjSrc4JJz1pOIutva-lH2m2gdAwKqdB2zjZ0RAogdysEpu4pfN/w400-h189/docker_ifconfig.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.5] ifconfig 명령 실행 모습</div><div><br /></div><div><div>root@26de74ece3fd:/# <b>passwd</b></div><div><i> => root password를 설정하자.</i></div><div>Enter new UNIX password: </div><div>Retype new UNIX password: </div><div>passwd: password updated successfully</div></div><div><br /></div><div>_____________________</div><div>chyi@mars:~$ <b>ssh root@172.17.0.2</b></div><div><i> => 다른 terminal 창에서 ssh로 현재 동작 중인 docker container에 로긴해 본다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPEDrW-SPGT_LD8AM3fWf1NEkrxm9sC7pNpd134fkdcTRbhdWSh32PLa-4XlD9spPsMnBGoev3f8lILSL6FUXaHPeg-whr31CV-PjlzEiyUrp4UAxvxK9cciR4HH7LZUGErwtqy593vp9z/s684/docker_ssh_login.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="451" data-original-width="684" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPEDrW-SPGT_LD8AM3fWf1NEkrxm9sC7pNpd134fkdcTRbhdWSh32PLa-4XlD9spPsMnBGoev3f8lILSL6FUXaHPeg-whr31CV-PjlzEiyUrp4UAxvxK9cciR4HH7LZUGErwtqy593vp9z/s320/docker_ssh_login.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.6] ssh로 docker container에 로긴한 모습</div><div><div><br /></div><div>_____________________</div><div>다시 docker container 창으로 돌아와서 ...</div><div><br /></div><div>root@26de74ece3fd:/# adduser chyi</div><div><i> => 사용자를 하나 추가하자.</i></div><div><div><span style="color: #3d85c6; font-size: x-small;">Adding user `chyi' ...</span></div><div><span style="color: #3d85c6; font-size: x-small;">Adding new group `chyi' (1000) ...</span></div><div><span style="color: #3d85c6; font-size: x-small;">Adding new user `chyi' (1000) with group `chyi' ...</span></div><div><span style="color: #3d85c6; font-size: x-small;">Creating home directory `/home/chyi' ...</span></div><div><span style="color: #3d85c6; font-size: x-small;">Copying files from `/etc/skel' ...</span></div><div><span style="color: #3d85c6; font-size: x-small;">Enter new UNIX password: </span></div><div><span style="color: #3d85c6; font-size: x-small;">Retype new UNIX password: </span></div><div><span style="color: #3d85c6; font-size: x-small;">passwd: password updated successfully</span></div><div><span style="color: #3d85c6; font-size: x-small;">Changing the user information for chyi</span></div><div><span style="color: #3d85c6; font-size: x-small;">Enter the new value, or press ENTER for the default</span></div><div><span style="color: #3d85c6; font-size: x-small;"><span style="white-space: pre;"> </span>Full Name []: </span></div><div><span style="color: #3d85c6; font-size: x-small;"><span style="white-space: pre;"> </span>Room Number []: </span></div><div><span style="color: #3d85c6; font-size: x-small;"><span style="white-space: pre;"> </span>Work Phone []: </span></div><div><span style="color: #3d85c6; font-size: x-small;"><span style="white-space: pre;"> </span>Home Phone []: </span></div><div><span style="color: #3d85c6; font-size: x-small;"><span style="white-space: pre;"> </span>Other []: </span></div><div><span style="color: #3d85c6; font-size: x-small;">Is the information correct? [Y/n] y</span></div></div><div><br /></div><div>📌 <span style="color: #ff00fe;">사용자 계정 추가 등의 과정도 Dockerfile에 넣어주면 편리하다.</span></div><div><br /></div><div>root@26de74ece3fd:/# <b>exit</b></div><div><br /></div><div>마지막으로 docker container를 빠져 나온 후, docker container 상에서 변경한 내용(몇가지 패키지 추가 및 파일 수정)을 <b>docker image에 저장하는 작업(commit)을 진행</b>하도록 하자. 참고로, <span style="color: #990000;">이 과정을 빼먹을 경우, docker run 명령 재 수행 시, 이전에 수정했던 내용이 모두 사라져 버리게 되니, 반드시 이 과정을 해 주어야 한다.</span></div><div><br /></div><div>$ <b>docker commit -a "chunghan <chunghan.yi@gmail.com>" -m "add some packages" <span style="color: #741b47;">esbin1804</span> <span style="color: #351c75;">u1804</span></b></div><div>sha256:026516e59f658743596643446bdb86a7312a0957755586d0eab8c25685e5019f</div></div><div><br /></div><div><div><span style="color: #bf9000;"><i> ➔ 사용방법 : docker commit < 옵션 > < 컨테이너 이름 > < 이미지 이름 >:< 태그 ></i></span></div><div><i><span style="color: #bf9000;"> ➔ < 컨테이너 이름 >: 직전에 docker run -i -t --name </span><span style="color: #990000;">esbin1804</span><span style="color: #bf9000;"> u1804 /bin/bash 에서</span></i></div><div><span style="color: #bf9000;"><i>지정한 name</i></span></div><div><i><span style="color: #bf9000;"> ➔ < 이미지 이름 >:< 태그 > </span><span style="color: #666666;">(참고: : <태그>는 생략 가능함)</span></i></div></div><div><br /></div><div><div>$ <b>docker rm esbin1804</b></div><div><i> => (다시 run 하기 전에)이전 container의 이름을 지워주도록 하자. 만일 이 과정을 빼먹을 경우, 매번 새로운 이름을 작명(?)해야 하는 수고를 해 주어야 한다.</i></div><div><i> => docker ps -a 명령으로 이전에 실행했거나 현재 동작 중인 docker container를 확인할 수 있다.</i></div><div><br /></div><div>$ <b>docker run -i -t --name esbin1804 u1804 /bin/bash</b></div></div><div>root@a62c173f2d74:/#</div><div><i> => commit하기 전에 수행했던 내용이 그대로 보존되어 있으면 정상적으로 commit된 것이다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgig4EmJrj6TBaspf-hNkElxCcvlHq_5SzVpIh7P64G-y2RPPCIWVaMBaPK6DN1Pa_7fS8b62es8bOYrGoQnrIYTzJwL-pb9y6fWSItZMw-xTdmNYHOu7XGolg2X3DkoscmJOQusY5qeyWg/s703/run_1804_sh.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="118" data-original-width="703" height="85" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgig4EmJrj6TBaspf-hNkElxCcvlHq_5SzVpIh7P64G-y2RPPCIWVaMBaPK6DN1Pa_7fS8b62es8bOYrGoQnrIYTzJwL-pb9y6fWSItZMw-xTdmNYHOu7XGolg2X3DkoscmJOQusY5qeyWg/w500-h85/run_1804_sh.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.7] run_u1804.sh script 예</div><div><br /></div><div><b><font color="#38761d">1.3) Docker 관련 몇가지 Tips</font></b></div><div><b>Q1) </b>Host OS와 docker container간에 파일을 복사하고자 한다면 ?</div><div><b>A1-1)</b> docker cp 명령을 사용합니다.</div><div> $ docker cp esbin1804:/home/chyi/test/bbb.txt .</div><div><br /></div><div><b>A1-2)</b> 공유 디렉토리를 이용합니다. docker run시 아래와 같이 -v <host OS 디렉토리>:<container 디렉토리>를 주게 되면, 두 디렉토리간에 파일이 공유되게 됩니다.</div><div> $ docker run -i -t <span style="color: #a64d79;">-v /var/lib/tftpboot:/data</span> --name esbin1804 u1804 /bin/bash</div><div><br /></div><div><b>Q2)</b> Container에서 tcp 80번 port를 열고, host OS의 80번 port와 연결하려면 ?</div><div><b>A2)</b> -p 80:80 option을 주어 실행하면 됩니다. http://<Host IP>:80 하면 container에 접속할 수 있습니다.</div><div> $ docker run -i -t <span style="color: #a64d79;">-p 80:80</span> <span style="color: #444444;">-v /var/lib/tftpboot:/data </span>--name esbin1804 u1804 /bin/bash</div><div><br /></div><div><b>Q3) </b>현재 동작 중인 container와 현재까지 실행되고 있거나, 실행된 적이 있는 모든 container 목록을 보려면 ? 혹은 이들을 제거하려면 ?</div><div><b>A3) </b></div><div> $ docker ps <i># 현재 동작 중인 container 출력</i></div><div> $ docker ps -a <i># 현재까지 실행되고 있거나, 실행된 적인 있는 모든 container 목록 출력</i></div><div><br /></div><div><div> $ docker rm $(docker ps -a -q) <i># 모든 container 정보 삭제</i></div><div> $ docker rmi $(docker images -q) <i># 모든 image 제거</i></div><div>_________________________________________</div></div><div><br /></div><div>이상으로 본격적인 내용 소개에 앞서서 docker를 활용한 개발 환경 구축 방법을 소개해 보았다. Docker ! 정말로 훌륭한 녀석(?)이다. 잘 활용하면 개발에 커다란 도움을 줄 것으로 확신한다.</div><div><br /></div><div><br /></div><div><b><font color="#3d85c6" size="6">2. ESPRESSObin Ultra보드 소개</font></b></div><div>ESPRESSObin 보드와 관련해서는 <a href="https://slowbootkernelhacks.blogspot.com/2020/04/espressobin-wireguard-vpn.html">이전 blog post</a>를 통해 한 차례 소개한 바가 있다. 오늘은 최근(2019년) 새롭게 등장한 <b>ESPRESSObin Ultra</b> 보드(이하 Ultra 보드로 칭하겠음)를 소개해 보고자 한다. 사실 <span style="color: #a64d79;">7월말에 하나를 주문했는데, (9월인데) 아직도 도착을 안하고 있다 😠</span></div><div><br /></div><div><b><font color="#38761d">2.1) Ultra 보드 소개</font></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJogQa-yft52KeYArbxdF6t5LDfB6d_HKNZamL0uEOuPo6hPJHHNz56PkOLpVZ2X_7zq4dwYFJpQapwAbKkSwCaNTbbRTSull1zU2hH8gBbQsPvd9pL_X3nuNkn294lNf5sFbCKAE-fxdV/s849/esbin_ultra_board.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="489" data-original-width="849" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJogQa-yft52KeYArbxdF6t5LDfB6d_HKNZamL0uEOuPo6hPJHHNz56PkOLpVZ2X_7zq4dwYFJpQapwAbKkSwCaNTbbRTSull1zU2hH8gBbQsPvd9pL_X3nuNkn294lNf5sFbCKAE-fxdV/s320/esbin_ultra_board.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.1] ESPRESSObin Ultra 보드 - Access Point style 구성 <b>[출처: 참고문헌 2]</b></span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OqnMZ-80caZGCNgb5Mu9kBTrFNfr-QL_yotnEMXqMRmDKdQGplQlcB1ofD9kLXCbdf0es6XPVYxZHaCsAbHh7V0aRxgjakr9FLTVqLsRW1f6F-UlpKl-A177OIOFRaZ__oA2TMTTDHHm/s911/esbin_ultra_block.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="663" data-original-width="911" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8OqnMZ-80caZGCNgb5Mu9kBTrFNfr-QL_yotnEMXqMRmDKdQGplQlcB1ofD9kLXCbdf0es6XPVYxZHaCsAbHh7V0aRxgjakr9FLTVqLsRW1f6F-UlpKl-A177OIOFRaZ__oA2TMTTDHHm/w500-h364/esbin_ultra_block.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.2] ESPRESSObin Ultra 보드 H/W Block도 </span><b style="text-align: left;">[출처: 참고문헌 2]</b></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #ff00fe; text-align: left;">📌 H/W Block도 우측 하단을 보면, Marvell 88E6341 switching chip이 RGMII interface를 통해 CPU에 연결되어 있음을 알 수 있다.</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYLw58qgcdsl_JUd-t6fGmXndDl3yNxlQsZ-vtb7YgxTvzVEpnlF28eBMace5wqZLxk7uSSmPs7p3oimFLyYrI4W3spmY1Hd4PoPIjFkdwDQKSKKzwf2WRIE5kv5ojLI8zH_srIqZEkbf7/s878/espressobin_ultra_spec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="657" data-original-width="878" height="299" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYLw58qgcdsl_JUd-t6fGmXndDl3yNxlQsZ-vtb7YgxTvzVEpnlF28eBMace5wqZLxk7uSSmPs7p3oimFLyYrI4W3spmY1Hd4PoPIjFkdwDQKSKKzwf2WRIE5kv5ojLI8zH_srIqZEkbf7/w400-h299/espressobin_ultra_spec.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.3] ESPRESSObin Ultra 보드 주요 스펙</span></div></div><div><br /></div><div><b><font color="#38761d">2.2) Ultra 보드 개발 환경 설정</font></b></div><div>그럼, 먼저 Ultra board용 bootloader, kernel source를 내려 받아 build를 해 보도록 하겠다. 이 절에서 소개하는 내용은 아래 site의 내용을 기준으로 한 것이다. <span style="color: #6fa8dc;">Home page에 정식으로 내용이 올라와 있지 않은 것으로 보아, 아직도 개발 중이던지 ... 뭔가 약간의 문제가 있는 듯 보인다.</span></div><div><br /></div><div style="text-align: center;"><a href="http://espressobin.net/espressobin-ultra-build-instruction/">http://espressobin.net/espressobin-ultra-build-instruction/</a></div><div><br /></div><div><div>$ <b>docker run -i -t --name esbin1804 u1804 /bin/bash</b></div></div><div><div>root@d9419ee9c06e:/# <b>su - chyi</b></div><div><i> => 이후의 모든 작업은 </i><i>root 말고 </i><i>사용자 계정으로 진행해도록 하자. </i></div><div><br /></div><div>chyi@d9419ee9c06e:~$ <b>cd ~; mkdir workspace; cd workspace</b></div></div><div><br /></div><div><span style="background-color: #ffd966;"><b><repo로 source download하기></b></span></div><div><div>chyi@d9419ee9c06e:~/workspace$ <b>git config --global user.email "chunghan.yi@gmail.com"</b></div><div>chyi@d9419ee9c06e:~/workspace$ <b>git config --global user.name "Chunghan Yi"</b></div></div><div><i> => git을 사용하려면 반드시 이 과정을 거쳐야 한다. 이는 기본 중의 기본^^</i></div><div><br /></div><div>chyi@d9419ee9c06e:~/workspace$ <b>repo init -u https://github.com/globalscaletechnologies/manifest.git -b espressobin-ultra -m espressobin_ultra-1.0.0.xml</b></div><div><br /></div><div>chyi@d9419ee9c06e:~/workspace$<b> repo sync</b></div><div><i> => repo sync를 해야 비로소 source code download가 시작된다.</i></div><div><br /></div><div>chyi@d9419ee9c06e:~/workspace$ ls -al</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnAC-KxKyBE3JLpvM1GWzO8YkiceUh04G89EcTKdnqH0Hz_4MhrDZ8WsMNshfSh_QX2WH7NFoih__UGY10TREMcjecKcHagZLDu5Hy8TNLxTtwkMvKBDgDu_boUrgLA45CJBMRTwtlaMhyphenhyphen/s967/ultra_repo_sync.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="236" data-original-width="967" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnAC-KxKyBE3JLpvM1GWzO8YkiceUh04G89EcTKdnqH0Hz_4MhrDZ8WsMNshfSh_QX2WH7NFoih__UGY10TREMcjecKcHagZLDu5Hy8TNLxTtwkMvKBDgDu_boUrgLA45CJBMRTwtlaMhyphenhyphen/w500-h123/ultra_repo_sync.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.4] ESPRESSObin Ultra source code 목록</span></div><div><br /></div><div><span face="" style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><b><arm64 linaro toolchain 설치하기></b></span></div><div><span face="" style="background-color: white; color: #373a3c;"><div>chyi@d9419ee9c06e:~/workspace$ <b>mkdir toolchain;cd toolchain/</b></div></span></div><div><span face="" style="background-color: white; color: #373a3c;">chyi@d9419ee9c06e:~/workspace/toolchain$ <b>wget https://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz</b></span></div><div><span face="" style="background-color: white; color: #373a3c; font-size: 16px;"><i> => linaro toolchain을 내려 받는다.</i></span></div><div><span face="" style="background-color: white; color: #373a3c; font-size: 16px;"><br /></span></div><div><span style="background-color: white; color: #373a3c;">chyi@d9419ee9c06e:~/workspace/toolchain$ </span><span style="color: #373a3c;">tar -xvf ./gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz</span></div><div><span style="color: #373a3c;"><i> => 압축을 푼다.</i></span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><b><bootloader용 arm32 toolchain 설치하기></b></span></div><div><span style="color: #373a3c;"><div>root@d9419ee9c06e:~# <b>apt-get install gcc-arm-linux-gnueabi</b></div><div><i> => 근데, 이미 설치가 되어 있다.</i></div><div><span style="font-size: x-small;">Reading package lists... Done</span></div><div><span style="font-size: x-small;">Building dependency tree </span></div><div><span style="font-size: x-small;">Reading state information... Done</span></div><div><span style="font-size: x-small;">gcc-arm-linux-gnueabi is already the newest version (4:7.4.0-1ubuntu2.3).</span></div><div><span style="font-size: x-small;">0 upgraded, 0 newly installed, 0 to remove and 5 not upgraded.</span></div></span></div><div><span style="color: #373a3c;"><br /></span></div><div>📌 <span style="color: #ff00fe;">얘가 진짜 필요한게 맞는지 잘 모르겠다. 이후 진행되는 것을 보면 u-boot이 arm64용으로 build가 되는 듯한데 ... 이 부분은 추후 재 확인을 해 보도록 하겠다.</span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><b><Compile 환경 설정하기></b></span></div><div><span style="background-color: white; color: #373a3c; font-size: 16px;">$ <b>vi ~/.bashrc</b></span></div><div><span style="background-color: white; color: #373a3c; font-size: 16px;"><i> => bashrc에 아래의 환경 설정 내용을 추가해 주자.</i></span></div><div><span style="background-color: white; color: #373a3c; font-size: x-small;">...</span></div><div><span style="background-color: white;"><span style="color: #373a3c; font-size: x-small;"><div>export PATH=/home/chyi/workspace/toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin:$PATH</div><div><br /></div><div># Set the cross compiler</div><div>export CROSS_COMPILE=/home/chyi/workspace/toolchain/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-</div><div><br /></div><div># Set path for MV_DDR component</div><div>export MV_DDR_PATH=/home/chyi/workspace/mv_ddr_marvell</div><div><br /></div><div># Set U-Boot image path</div><div>export BL33=/home/chyi/workspace/u-boot-marvell/u-boot.bin</div><div><br /></div><div># Set WTP Tools path</div><div>export WTP=/home/chyi/workspace/a3700-utils-marvell</div><div>~</div></span></span></div><div><span style="background-color: white; color: #373a3c; font-size: 16px;"><br /></span></div><div><span style="background-color: white; color: #373a3c;">$ <b>source ~/.bashrc</b></span></div><div><span style="background-color: white; color: #373a3c;"><i> => 위의서 설정한 환경 변수를 적용해 준다.</i></span></div><div><span style="background-color: white; color: #373a3c;"><br /></span></div><div><span style="background-color: white; color: #373a3c;">u-boot, kernel 등을 compile하기 전에 몇가지 package를 더 설치하자. </span><span style="background-color: white;"><span style="color: #bf9000;">사실 아래 내용은 (build 과정에서 발견하여) 나중에 추가한 것이다.</span></span></div><div><span style="background-color: white; color: #373a3c; font-size: 16px;"><br /></span></div><div><span style="color: #373a3c;">root@d9419ee9c06e:~#</span><b style="color: #373a3c;"> apt-get install -y libncurses-dev</b></div><div><span style="color: #373a3c;">root@d9419ee9c06e:~#</span><b style="color: #373a3c;"> apt-get install -y bc</b></div><div><b style="color: #373a3c;"><br /></b></div><div><b style="color: #373a3c;"><br /></b></div><div><span style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><b><u-boot build하기></b></span></div><div><span style="background-color: white;"><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span></span><b><span style="color: #373a3c;">make -C ./</span><span style="background-color: white; color: #373a3c;">u-boot-marvell </span><span style="color: #373a3c;">gti_ccpe-88f3720_defconfig</span></b></div><div><span style="background-color: white;"><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ <b>make -C ./u-boot-marvell menuconfig</b></span></span></div><div><span style="background-color: white;"><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span></span><b><span style="color: #373a3c;">make </span><span style="color: #373a3c;">-C ./</span><span style="background-color: white; color: #373a3c;">u-boot-marvell </span><span style="color: #373a3c;">DEVICE_TREE=armada-3720-ccpe</span></b></div><div><br /></div><div><b style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><ATF build하기></b></div><div><span style="background-color: white; color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span><span style="color: #373a3c;"><b>make -C ./atf-marvell DEBUG=0 USE_COHERENT_MEM=0 LOG_LEVEL=20 CLOCKSPRESET=CPU_1000_DDR_800 PLAT=a3700 DDR_TOPOLOGY=5 all fip</b></span></div><div>📌 <span style="color: #ff00fe;">ATF는 ARM Trusted Firmware를 뜻한다.</span></div><div><span style="color: #ff00fe;"><br /></span></div><div><b style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><kernel build하기></b></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ <b>make -C ./linux ARCH=arm64 gti_ccpe-88f3720_defconfig</b></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ <b>make -C ./linux ARCH=arm64 menuconfig</b></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ <b>make -C ./linux ARCH=arm64 -j4</b></span></div><div><br /></div><div><b style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><통합 이미지 생성하기></b></div><div><span style="color: #373a3c;">오 ! 이런~ 전체 build(환경 설정 포함)를 해 주는 script가 이미 준비되어 있다. 얘를 이용하여 다시 build해 보자.</span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span><span style="color: #373a3c;"><b>source ./env-espressobin_ultra.sh</b></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span><span style="color: #373a3c;"><b>gtibuild bootloader</b></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span><span style="color: #373a3c;"><b>gtibuild kernel</b></span></div><div><span style="color: #373a3c;">chyi@d9419ee9c06e:~/workspace$ </span><span style="color: #373a3c;"><b>gtibuild all</b></span></div><div><span style="color: #373a3c;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj74bmMgYCMZN-M8gn_0lrOu3nkImpmQMzjfpZU8YMP-qJhLj59Q-eEF_Pmd9wC433KM6RL80FBpL85P8Xr9wl6SbuzpGYgqWIaV3QysR1HP-NLPItph0rChG7ezatldkphY3-3h5NqEnc5/s974/ultra_build_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="343" data-original-width="974" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj74bmMgYCMZN-M8gn_0lrOu3nkImpmQMzjfpZU8YMP-qJhLj59Q-eEF_Pmd9wC433KM6RL80FBpL85P8Xr9wl6SbuzpGYgqWIaV3QysR1HP-NLPItph0rChG7ezatldkphY3-3h5NqEnc5/w500-h176/ultra_build_output.png" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.5] ESPRESSObin Ultra build 결과물</span></div></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;"><br /></span></div><div><b style="background-color: #ffd966; color: #373a3c; font-size: 16px;"><Target board에 설치하기></b></div><div><span><b><span style="color: #990000;"><TBD></span> </b></span></div><div><span><span style="color: #666666;">지금까지 build한 내용은 보드가 도착하면 시도해 보도록 하자. 참고로, (앞선 build 과정에서 보이지 않았던) rootfs는 prebuilt 형태로 제공된다.</span></span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;">__________________________</span></div><div><span style="color: #373a3c;">root@d9419ee9c06e:/# <b>exit</b></span></div><div><span style="color: #373a3c;">$ <b>docker commit -a "chunghan <chunghan.yi@gmail.com>" -m "add some packages" esbin1804 u1804</b></span></div><div><span style="color: #373a3c;"><i> => 지끔까지 작업한 내용을 docker image에 반드시 저장하자.</i></span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;"><br /></span></div><div><span style="color: #373a3c;"><br /></span></div><div><b><font color="#3d85c6" size="6">3. ESPRESSObin Ultra보드의 Switching Device Driver 분석</font></b></div><div><div><div>이 장의 내용은 [참고문헌 3]에서 영감을 받아 작성하였다.</div><div><br /></div><div style="text-align: center;"><span style="color: #674ea7;"><i><a href="https://www.youtube.com/watch?v=OUTrzz1vwSE&ab_channel=TheLinuxFoundation" target="_blank">Ethernet switch support in the Linux kernel, Alexandre Belloni, Bootlin</a></i></span></div><div><br /></div><div><b><font color="#38761d">3.1) Ultra 보드 Switch device 소개</font></b></div><div>ESPRESSObin Ultra 보드는 아래 그림과 같이 Marvell 88E6341 switching chip(Topaz Switch라고도 함)을 사용한다. 이 88E6341 switch는 왼쪽으로는 CPU랑 RGMII(data 통신용) 및 MDC/MDIO(제어용)로 연결되어 있으며, 오른쪽으로는 4개의 LAN port와 1개의 WAN port(얘는 다시 SGMII interface를 통해 88E1512 Gb PHY와 연결)와 연결되어 있다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNcv1IphPsmK7GcMNpqwoG7qcd8rbw69SZ0g-LEm15z46OX8olsbUU9tMxGhBBh90rpgA6TpKGbPJSqVzzv9yDraP7xtFj2mWuWGtDEa5l9hlvigSir0vBlRkos8HMmaxo9WQGx1aOxMqU/s692/88e6341_topaz_block.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="692" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNcv1IphPsmK7GcMNpqwoG7qcd8rbw69SZ0g-LEm15z46OX8olsbUU9tMxGhBBh90rpgA6TpKGbPJSqVzzv9yDraP7xtFj2mWuWGtDEa5l9hlvigSir0vBlRkos8HMmaxo9WQGx1aOxMqU/w400-h203/88e6341_topaz_block.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.1] Marvell 88E6341 Ethernet Switch(1) </span><b style="text-align: left;">[출처: 참고문헌 2]</b></div><div><br /></div><div>아래 그림은 Marvell 88E6341 Ethernet Switch의 구성 요소를 간략히 보여주고 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBSn7lZKrWo6ZP7rKHLprfsGHya5fEo1VisqMvcc6vF-qvCdRHaEqhiMWZKD7NGg53ZNfbYIMHV3c0T7bhlWJrNTK62AlShAvRbtE0neFZnJoXi-Wnv-RoQU5AsfvPLEG86yMhjXzR2Ev/s518/marvell_88e6341.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="487" data-original-width="518" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBSn7lZKrWo6ZP7rKHLprfsGHya5fEo1VisqMvcc6vF-qvCdRHaEqhiMWZKD7NGg53ZNfbYIMHV3c0T7bhlWJrNTK62AlShAvRbtE0neFZnJoXi-Wnv-RoQU5AsfvPLEG86yMhjXzR2Ev/s320/marvell_88e6341.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.2] Marvell 88E6341 Ethernet Switch(2) </span><b style="text-align: left;">[출처: 참고문헌 6]</b></div><div><br /></div><div>한편, Linux kernel에는 위와 같은 switch device를 위한 framework(<b>switchdev</b>)이 이미 정의되어 있는데, 이와 관련해서는 아래 내용을 살펴볼 필요가 있다.</div><div><br /></div><div><div style="text-align: justify;"><i> 1) Documentation/networking/switchdev.txt</i></div><div><div style="text-align: justify;"><i> 2) net/switchdev/switchdev.c</i></div><div style="text-align: justify;"><i> 3) include/net/switchdev.h</i></div></div></div><div style="text-align: center;"><i><br /></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfbwqUtWxae66EYWg5qMSKa8yaSZ8wjHlbz8m09AqCmc3riwFvctj7ze9-te0jNrJ1JW1cefrlBkEtFUKw_xkU744HvolEaMdbRE2hgUKczcafjAXE8SHhytcZf5ng5625jVFiQPK0RJ7i/s671/linux_switchdev_framework1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="671" data-original-width="641" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfbwqUtWxae66EYWg5qMSKa8yaSZ8wjHlbz8m09AqCmc3riwFvctj7ze9-te0jNrJ1JW1cefrlBkEtFUKw_xkU744HvolEaMdbRE2hgUKczcafjAXE8SHhytcZf5ng5625jVFiQPK0RJ7i/w383-h400/linux_switchdev_framework1.png" width="383" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.3] linux kernel switch device driver model</span></div><div style="text-align: center;"><br /></div><div style="text-align: left;">대개의 경우, CPU(정확하게는 MAC)와 switching chip은 PCIe 혹은 xMII 등의 interface를 통해 data를 주고 받으며, MDC/MDIO(= SMI) or SPI 등을 통해 control이 이루어지게 된다.</div><div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: left;"><span style="color: #0000ee; text-decoration-line: underline;"><br /></span></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrO-mC-wpMyKtgR4OwcGePNnAh8FPrnSuHjZd4aDbGcejjWxxY6R4AxJSUHgLd3aS6B_ycBlIJXpH3F1iJXK8fmKZkIHvytVk5sGMyxPXyvF7REUfmDFLGP72PIJtkbY-aL2mFAMRZ7GkV/s1010/switch_concept.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="1010" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrO-mC-wpMyKtgR4OwcGePNnAh8FPrnSuHjZd4aDbGcejjWxxY6R4AxJSUHgLd3aS6B_ycBlIJXpH3F1iJXK8fmKZkIHvytVk5sGMyxPXyvF7REUfmDFLGP72PIJtkbY-aL2mFAMRZ7GkV/w400-h251/switch_concept.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.4] Ethernet Switch와 CPU의 관계도(개념도) <b>[출처: 참고문헌 3]</b></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">그런데, Marvell은 위의 switchdev framework으로는 부족하다고 판단했는지, 자신들의 switch chip을 위해 <b><span style="color: #b45f06;">DSA(Distributed Switch Architecture)</span></b>라는 새로운 switch framework을 별도로 설계하였다. 이를 그림으로 그려보면 다음과 같은데, 이는 여러 개의 switching chip을 CPU에 붙이는 경우(cascade 구성)를 고려한 것으로, 처음에는 Marvell에서 만들었으나, 이후 다른 vendor들에서도 점차로 이 framework을 사용하는 추세인 듯 하다.</div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7rAfe-FckjqpEEcoPERYLXnzpv7HkwZX8r8iItY5inGTBn8tuTZt1x9DnQ81J4fAhOJduEPhOvpDK08n0ai8xjOXHE0FJ8KT2W3QXt_90Vm2RW0s2SS3J-MAuqMHqxFkMZ3XYzc7YdNgo/s1014/dsa_switch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="547" data-original-width="1014" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7rAfe-FckjqpEEcoPERYLXnzpv7HkwZX8r8iItY5inGTBn8tuTZt1x9DnQ81J4fAhOJduEPhOvpDK08n0ai8xjOXHE0FJ8KT2W3QXt_90Vm2RW0s2SS3J-MAuqMHqxFkMZ3XYzc7YdNgo/w400-h216/dsa_switch.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.5] </span><span style="text-align: left;">DSA(Distributed Switch Architecture) 개념도 </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 3]</b></div></span></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b><font color="#38761d">3.2) Switch device driver 분석</font></b></div><div>이 절에서는 Marvell 88E6341 switching chip을 위한 device tree 및 driver(DSA driver)를 분석해 보도록 하겠다.</div><div><br /></div><div>시작에 앞서 DSA의 개념을 보다 구체적으로 이해할 필요가 있겠는데, 이를 위해서는 아래 파일을 먼저 살펴 보아야 한다.</div><div><br /></div><div style="text-align: justify;"><i> 1) Documentation/networking/dsa/dsa.txt</i></div><div><div style="text-align: justify;"><i> 2) Documentation/devicetree/bindings/net/dsa/dsa.txt</i></div></div><div style="text-align: justify;"><i> 3) Documentation/devicetree/bindings/net/dsa/marvell.txt</i></div><div style="text-align: justify;"><i> 4) Documentation/devicetree/bindings/net/ethernet.txt</i></div><div><br /></div><div>다음으로 살펴볼 내용은 device tree이다.</div><div><b><br /></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">armada-37xx.dtsi</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">|</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">v</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">armada-372x.dtsi</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">|</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">v</span></b></div><div style="text-align: center;"><b><span style="color: #0b5394;">armada-3720-ccpe.dts</span></b></div><div style="text-align: center;"><br /></div><div style="text-align: left;">(긴 말할 것 없이) 이 중 맨 아래에 있는 dts 파일 즉, arch/arm64/boot/dts/marvell/armada-3720-ccpe.dts를 mdio node를 중심으로 분석해 보면 다음과 같다.</div><div>______________________________________________________________</div><div><div><div><span style="color: #351c75;">&eth0 { </span><span style="color: #990000;">/* switch device를 cpu에 연결시켜 주는 device, 역시 앞서 정의되어 있는 eth0를 override하여 재 정의하고 있음 */</span></div><div style="color: #351c75;"> pinctrl-names = "default";</div><div style="color: #351c75;"> pinctrl-0 = <&rgmii_pins>;</div><div><span style="color: #351c75;"> phy-mode = "<b>rgmii-id</b>"; </span><span style="color: #990000;">/* switch와 연결되는 interface: RGMII */</span></div><div style="color: #351c75;"> status = "okay";</div><div style="color: #351c75;"><br /></div><div style="color: #351c75;"> fixed-link {</div><div style="color: #351c75;"> speed = <1000>;</div><div style="color: #351c75;"> full-duplex;</div><div style="color: #351c75;"> };</div><div style="color: #351c75;">};</div></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;">&mdio { </span><span style="color: #990000;"> /* DSA에서는 이런 구문이 여러개 존재할 수 있음, &mdio는 앞서 정의된 mdio를 override하여 재 정의하는 것을 뜻함. */</span></div><div><span style="color: #351c75;"> status = "okay";</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> extphy: ethernet-phy@0 {</span></div><div><span style="color: #351c75;"> reg = <1>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0: switch0@1 { </span><span style="color: #990000;"> /* switching chip을 기술해 주는 부분 */</span></div><div><span style="color: #351c75;"> compatible = "</span><span style="color: #b45f06;">marvell,mv88e6085</span><span style="color: #351c75;">"; </span><span style="color: #990000;">/* 이걸로 driver 검색 */</span></div><div><span style="color: #351c75;"> #address-cells = <1>;</span></div><div><span style="color: #351c75;"> #size-cells = <0>; </span></div><div><span style="color: #351c75;"> reg = <3>;</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> dsa,member = <0 0>; </span><span style="color: #990000;">/* cluster 0, switch 0을 의미 */</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> ports { </span><span style="color: #990000;"> /* switch에 붙어 있는 ports를 기술해 주는 부분 */</span></div><div><span style="color: #351c75;"> #address-cells = <1>;</span></div><div><span style="color: #351c75;"> #size-cells = <0>;</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port0: port@0 {</span></div><div><span style="color: #351c75;"> reg = <0>;</span></div><div><span style="color: #351c75;"> label = "<b>cpu</b>"; </span><span style="color: #990000;"> /* 0번 port를 cpu port로 사용 */</span></div><div><span style="color: #351c75;"> ethernet = <&eth0>; </span><span style="color: #990000;"> /* cpu port의 경우는 ethernet property를 추가해 줌 */</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port1: port@1 {</span></div><div><span style="color: #351c75;"> reg = <1>;</span></div><div><span style="color: #351c75;"> label = "<b>lan0</b>";</span></div><div><span style="color: #351c75;"> phy-handle = <&</span><b><span style="color: #38761d;">switch0phy1</span></b><span style="color: #351c75;">>; </span><span style="color: #38761d;"> /*<b> (A)</b> */</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port2: port@2 {</span></div><div><span style="color: #351c75;"> reg = <2>;</span></div><div><span style="color: #351c75;"> label = "<b>lan1</b>";</span></div><div><span style="color: #351c75;"> phy-handle = <&switch0phy2>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port3: port@3 {</span></div><div><span style="color: #351c75;"> reg = <3>;</span></div><div><span style="color: #351c75;"> label = "<b>lan2</b>";</span></div><div><span style="color: #351c75;"> phy-handle = <&switch0phy3>;</span></div><div><span style="color: #351c75;"> };</span></div></div><div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port4: port@4 {</span></div><div><span style="color: #351c75;"> reg = <4>;</span></div><div><span style="color: #351c75;"> label = "<b>lan3</b>";</span></div><div><span style="color: #351c75;"> phy-handle = <&switch0phy4>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> switch0port5: port@5 {</span></div><div><span style="color: #351c75;"> reg = <5>;</span></div><div><span style="color: #351c75;"> label = "<b>wan</b>";</span></div><div><span style="color: #351c75;"> phy-handle = <&extphy>;</span></div><div><span style="color: #351c75;"> phy-mode = "sgmii"; </span><span style="color: #990000;">/* wan port는 SGMII interface를 통해 외부 phy와 연결되어 있음 */</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> mdio { </span><span style="color: #990000;">/* 이름이 앞서와 겹쳐서 헷갈릴 수 있는데, 여기서의 mdio는 mdio-bus를 의미함 - 여기서의 이름은 크게 중요치 않음. */</span></div><div><span style="color: #351c75;"> #address-cells = <1>;</span></div><div><span style="color: #351c75;"> #size-cells = <0>;</span></div><div><span style="color: #351c75;"><br /></span></div><div><span style="color: #351c75;"> </span><b><span style="color: #38761d;"> switch0phy1</span></b><span style="color: #351c75;">: switch0phy1@11 { </span><span style="color: #38761d;">/* <b>(A)</b> */</span></div><div><span style="color: #351c75;"> reg = <<b>0x11</b>>; </span><span style="color: #990000;">/* mdc/mdio로 연결되는 PHY는 i2c 장치 처럼 주소를 갖는다 */</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> switch0phy2: switch0phy2@12 {</span></div><div><span style="color: #351c75;"> reg = <<b>0x12</b>>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> switch0phy3: switch0phy3@13 {</span></div><div><span style="color: #351c75;"> reg = <<b>0x13</b>>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> switch0phy4: switch0phy4@14 {</span></div><div><span style="color: #351c75;"> reg = <<b>0x14</b>>;</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;"> };</span></div><div><span style="color: #351c75;">};</span></div></div><div>______________________________________________________________</div><div><br /></div><div>이번에 살펴 볼 부분은 device driver 쪽이다. device driver를 분석할 때는 (전체를 이해하는게 어려울 수 있으니) 초기화 코드(init, probe 등)와 사용자와의 interface(sysfs, read/write/ioctl, netlink socket 등)를 중심으로 살펴볼 필요가 있다.</div><div><br /></div><div>Source 위치는 아래와 같이 grep으로 찾을 수 있다.</div><div><span>$ <span style="color: #a64d79;">grep -rl "marvell,mv88e6085" *</span></span></div><div>linux/drivers/net/dsa/mv88e6xxx/chip.c</div><div><br /></div><div>DSA driver의 전체 구조를 파악하는 것은 생각 만큼 간단하지가 않다. <b>[참고 문헌 5]</b>는 DSA의 전체 구조는 물론이고, switchdev, swconfig 등 기존에 구현되어 있는 switch 관련 framework을 전반적으로 소개해 주고 있어, 여기에 소개한다.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><span style="color: #0b5394;"><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-kwzIH28g6ON6sXPuB2sGjZrQlO6Rc-Fc0vIUebuADacHeKow5WxjdAzGBaHVS7JnOf-dO_h79Zky0fNHOOJwNI_gbePzttSfGfgQS1jXFrPWlFc52hj_IUcum5AKsoKddpWfwVqcUhvp/s456/dsa_arch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="358" data-original-width="456" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-kwzIH28g6ON6sXPuB2sGjZrQlO6Rc-Fc0vIUebuADacHeKow5WxjdAzGBaHVS7JnOf-dO_h79Zky0fNHOOJwNI_gbePzttSfGfgQS1jXFrPWlFc52hj_IUcum5AKsoKddpWfwVqcUhvp/s320/dsa_arch.png" width="320" /></a></div></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.6] </span><span style="text-align: left;"> </span><span style="text-align: left;">DSA Architecture(1) </span><b style="text-align: left;">[출처: 참고문헌 5]</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNNH9eTYA0xf52mi5cn1XZyZalSLEaA5f4jpGSrYYVRc7xbdu0pbICdH7c8pocTNUVoZgAYbQVWGmdxZGfeZ0JoDzI1jYybbQT_FwyhlnPZicVCZcQcl571nogrWmiDLJI9E9qd_5LcufZ/s542/dsa_arch2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="418" data-original-width="542" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNNH9eTYA0xf52mi5cn1XZyZalSLEaA5f4jpGSrYYVRc7xbdu0pbICdH7c8pocTNUVoZgAYbQVWGmdxZGfeZ0JoDzI1jYybbQT_FwyhlnPZicVCZcQcl571nogrWmiDLJI9E9qd_5LcufZ/s320/dsa_arch2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.7] </span><span style="text-align: left;"> </span><span style="text-align: left;">DSA </span><span style="text-align: left;">Architecture(2)</span><span style="text-align: left;"> </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 5]</b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVm9E2m7HZ2RempFogMDu0AO6vmGYI2SyBCtXWqVKs4vwER-kNST1YcXY5WoFVm1WSj6fXYJQsCCJ8tSbcdTL-1W_IsmMCSbltsS2cbXp9gCjr8FbR4sH36PqOIt0P0THWPusR-cXPQjdw/s525/dsa_arch3_switch_tags.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="525" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVm9E2m7HZ2RempFogMDu0AO6vmGYI2SyBCtXWqVKs4vwER-kNST1YcXY5WoFVm1WSj6fXYJQsCCJ8tSbcdTL-1W_IsmMCSbltsS2cbXp9gCjr8FbR4sH36PqOIt0P0THWPusR-cXPQjdw/s320/dsa_arch3_switch_tags.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.8] </span><span style="text-align: left;"> </span><span style="text-align: left;">DSA Switch Tags 처리(1) </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 5]</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit0sTyQJNNhyy5VLxav3rphQa9X9f0GbNkhoQvPt9KasoFA8NohtsBgINHLES6npyBc_FmD1TIl4jxUHJHZa4Icu870rzhxpEKAfPOZmEPbfZ5hyfvTEdJ0itSvrjS-YAG1jYRGMrSp7-k/s520/dsa_arch4_switch_tag_processing.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="411" data-original-width="520" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit0sTyQJNNhyy5VLxav3rphQa9X9f0GbNkhoQvPt9KasoFA8NohtsBgINHLES6npyBc_FmD1TIl4jxUHJHZa4Icu870rzhxpEKAfPOZmEPbfZ5hyfvTEdJ0itSvrjS-YAG1jYRGMrSp7-k/s320/dsa_arch4_switch_tag_processing.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.9] </span><span style="text-align: left;"> </span><span style="text-align: left;">DSA Switch Tags 처리(2) </span><b style="text-align: left;">[</b><b style="text-align: left;">출처: </b><b style="text-align: left;">참고문헌 5]</b></div><div><br /></div><div>이상의 내용을 기초로 하여 코드를 분석해 보아야 하는데, <span style="color: #a64d79;">지면 관계상, 여기에서는 chip.c 파일의 초기화 부분과 probe 함수 내용을 capture하는 것으로 코드 분석을 대신하고자 한다. 👻</span></div><div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6KaSrN8Mk3I8YJtmKl8B-8cysSyyrnUskcoeXy02fdt8IRKNKqwur4K7ftZbQVlWSyA0chsLl0DMQakdi37wyYnpDE3XPzsdq33gEQ1oRI9JQjp_Ii4lDiuDegMe6qLEIZ58yP9nujOtp/s581/mv88e6xxx_init.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="538" data-original-width="581" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6KaSrN8Mk3I8YJtmKl8B-8cysSyyrnUskcoeXy02fdt8IRKNKqwur4K7ftZbQVlWSyA0chsLl0DMQakdi37wyYnpDE3XPzsdq33gEQ1oRI9JQjp_Ii4lDiuDegMe6qLEIZ58yP9nujOtp/s320/mv88e6xxx_init.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.10] Marvell mv88e6xxx driver 초기화 코드(1)</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2Oz9VK0e737EkgLAifmdkjTsqyNdhyxmNGD6cttcI7pqoRsKFw9yT003JZwgVZVBB1mv2JNYTusZfdTucBNcHfVlKaFVhuJntY3SqPbDlI1NREmy0hFDN12PAscMUzxk818kTf6mggMDO/s914/mv88e6xxx_probe.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="914" data-original-width="680" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2Oz9VK0e737EkgLAifmdkjTsqyNdhyxmNGD6cttcI7pqoRsKFw9yT003JZwgVZVBB1mv2JNYTusZfdTucBNcHfVlKaFVhuJntY3SqPbDlI1NREmy0hFDN12PAscMUzxk818kTf6mggMDO/w298-h400/mv88e6xxx_probe.png" width="298" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.11] Marvell mv88e6xxx driver 초기화 코드(2) - probe 함수</span></div></div><div><br /></div><div><br /></div><div><span style="background-color: #ffe599;"><b><여기서 잠깐 !></b></span></div><div>Ultra 보드에는 4MB 크기의 SPI NOR flash가 한개 장착되어 있다. 아래 내용은 이와 관련한 device tree 내용을 capture한 것으로, NOR flash 내에 3개의 파티션 즉, u-boot, hw-info, u-boot-env이 위치하고 있음을 알 수 있다. 이는 값비싼 SPI NOR flash에는 자주 변경하지 않으면서 크기가 작은 u-boot만을 넣어 두고, 용량이 큰 linux kernel과 rootfs는 값싼 eMMC에 배치하는 전형적인 구성이라고 볼 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm2FuDiJzd8ukoB1JhpHHmeeeztqXJBwNMwoneYm_FErrZpyHVJTEDYficRG2O96QpIvSPsqoCHCAWiB_o5oMFKmMmf3pu9uexnfT2v_S_Yc0Ym1dBJZWvFGLQ7ekCfHwclUeLXfdJKRM7/s625/esbin_ultra_spi_nor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="625" data-original-width="421" height="500" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjm2FuDiJzd8ukoB1JhpHHmeeeztqXJBwNMwoneYm_FErrZpyHVJTEDYficRG2O96QpIvSPsqoCHCAWiB_o5oMFKmMmf3pu9uexnfT2v_S_Yc0Ym1dBJZWvFGLQ7ekCfHwclUeLXfdJKRM7/w338-h500/esbin_ultra_spi_nor.png" width="338" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.12] SPI NOR flash에 대한 device tree 표현</span></div><br /><div>📌 <span style="color: #ff00fe;">SPI flash는 SPI interface를 통해 CPU와 연결된다. SPI는 CS(Chip Select), SCK(Serial Clock), MOSI(Master Output Slave Input), MISO(Master Input Slave Output)라는 4가닥 선을 사용하는 serial 통신 방식이다. 요즘은 이 방식을 많이 사용한다.</span></div><div>____________________________</div><div><br /></div></div><div><b style="background-color: #ffe599;"><여기서 잠깐 !></b></div><div>최근에 출시된 802.11ax(WiFi 6)를 지원하는 보드(SoC: Qualcomm IPQ6010)가 있어 여기에 소개해 본다.</div><div><br /></div><div style="text-align: center;"><a href="http://linuxgizmos.com/networking-sbc-boasts-2-5gbe-gbe-with-poe-and-optional-5g-and-wifi-6/">http://linuxgizmos.com/networking-sbc-boasts-2-5gbe-gbe-with-poe-and-optional-5g-and-wifi-6/</a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG3L4mBUePSpbqqEK7lHH6NKqlnXi76KDGhHrL9NUytJlqAJDR4FlcElAdmyDVTJAYzfg1jD-RqBwTK7RrNu8OrW9HwaiTYoRVXYcGNbqLxRtqmraqe0kaQ07QmvlEd_CnG9XEDYAik6nN/s350/wallys_dr6018v2-sm.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="244" data-original-width="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG3L4mBUePSpbqqEK7lHH6NKqlnXi76KDGhHrL9NUytJlqAJDR4FlcElAdmyDVTJAYzfg1jD-RqBwTK7RrNu8OrW9HwaiTYoRVXYcGNbqLxRtqmraqe0kaQ07QmvlEd_CnG9XEDYAik6nN/s320/wallys_dr6018v2-sm.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.13] WiFi 6(802.11ax)를 지원하는 보드 - DR6018 v2</span></div><div>____________________________</div><div><br /></div><div><br /></div><div><div>늘 느끼는 거지만 (요즘 한층 더 복잡해진) linux device driver를 분석하는 것은 결코 만만한 일이 아니다. 특히 device 별로 새로운 framework이 소개되고 있는 탓에 이해를 더 어렵게 만들고 있는 것 같다.</div><div><br /></div><div><span style="background-color: #d9ead3;">시작할 때 의도했던 것과는 다르게 분석 내용이 너무 수준 이하(?)라는게 좀 아쉽다. 부족한 부분은 추후 좀 더 보충해 볼 것을 기약하며 이번 장을 마치도록 하겠다.</span> 😅</div><div><br /></div></div><div><br /></div><div><b><span style="color: #b45f06; font-size: medium;">To be continued ... </span></b></div><div><br /></div><div><br /></div><div><b><font color="#3d85c6" size="6">7. References</font></b></div><div>[1] <a href="http://espressobin.net/espressobin-ultra-build-instruction/">http://espressobin.net/espressobin-ultra-build-instruction/</a> </div><div>[2] ESPRESSObin ULTRA- Quick Start Guide -Rev 03</div><div>[3] <span style="color: #990000;">Ethernet switch support in the Linux kernel</span>, Alexandre Belloni, Bootlin</div></div><div>[4] <span style="color: #990000;">From the Ethernet MAC to the link partner</span>, Maxime Chevallier, Antoine Ténart, Bootlin</div><div>[5] <a href="https://docplayer.net/50750816-Distributed-switch-architecture-a-k-a-dsa.html">Distributed Switch Architecture, A.K.A DSA, Andrew Lunn, Vivien Didelot, Florian Fainelli</a></div><div>[6] marvell-link-street-88E6341-product-brief.pdf</div><div>[7] http://wiki.macchiatobin.net/tiki-index.php?page=BSP+HowTo</div><div>[8] https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-18-04</div><div>[9] http://pyrasis.com/Docker/Docker-HOWTO#ps</div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#38761d">SlowBoot</font></b></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-88234506260961440942020-07-21T21:51:00.003+09:002020-07-24T17:29:55.713+09:00Linux Kernel Programming - GPIO Interrupt and Bottom Halves이번 시간에는 <font color="#a64d79"><b>GPIO interrupt and Bottom Halves(Deferring Work)</b></font>라는 주제로 <b>몇가지 kernel programming 예제(linux 4.19.94 기준)</b>를 소개해 보도록 하겠다. 😎<div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyKk5dQ66P5ceVtemppr8wl5sfHm7KJCtUYnBPZ3h1u21_RfA8BKJ7ZBAJV72nF20POhgLHBznml07tYnCE5EV9j32g0HlOHlorYfM55wyZxOYwYL3Rym6Y-InE1myvwZJa2A-b5YrXbuf/s778/linux_interrupt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="331" data-original-width="778" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyKk5dQ66P5ceVtemppr8wl5sfHm7KJCtUYnBPZ3h1u21_RfA8BKJ7ZBAJV72nF20POhgLHBznml07tYnCE5EV9j32g0HlOHlorYfM55wyZxOYwYL3Rym6Y-InE1myvwZJa2A-b5YrXbuf/w400-h170/linux_interrupt.png" width="400" /></a></div><div style="text-align: center;"><br /></div><div><br /></div><div><div><b><font size="4">목차</font></b></div><div><div><i><b>1. STM32MP157C Discovery Kit 환경 설정</b></i></div></div><div><i><b>2. GPIO Interrupt Platform Driver</b></i></div><div><i><font color="#3d85c6"> - Device tree and platform driver, GPIO Interrupt(top half)</font></i></div><div><b><i>3. Bottom Halves</i><i> and Deferring Work</i></b></div><div><i><font color="#3d85c6"> - Kernel timer</font></i></div><div><i><font color="#3d85c6"> - Tasklet</font></i></div><div><i><font color="#3d85c6"> - Workqueue</font></i></div><div><i><font color="#3d85c6"> - Threaded Interrupt(IRQ Thread)</font></i></div><div><i><font color="#3d85c6"> - Kernel Thread</font></i></div><div><i><b>4. References</b></i></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">1. STM32MP157C Discovery Kit 환경 설정</font></b></div><div>DK2 보드와 관련해서는 이미 이전 blog post를 통해 여러 차례 소개한 바가 있다. DK2 보드가 생소한 분들은 먼저 아래 blog post의 내용을 참조하기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html</a></div><div style="text-align: center;"><br /></div><div>지금부터는 아래 ST wiki page의 내용을 기초로 하여<font color="#666666"> (이번 blog post에서 사용할) </font>ARM cross toolchain(정확하게는 Yocto SDK) 및 linux kernel 등을 설치해 보도록 하겠다.</div><div><br /></div><div style="text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157x-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-A7/Install_the_SDK">https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157x-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-A7/Install_the_SDK</a></div><div><br /></div><div><span style="background-color: #d9ead3;"><b><Yocto SDK 설치></b></span></div><div><div>$ <b>./st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.4-dunfell-mp1-20-06-24.sh </b></div><div><font size="2">ST OpenSTLinux - Weston - (A Yocto Project Based Distro) SDK installer version 3.1-openstlinux-5.4-dunfell-mp1-20-06-24</font></div><div><font size="2">=======================================================================================================================</font></div><div><font size="2">Enter target directory for SDK (default: /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24): </font></div><div><font size="2">You are about to install the SDK to "/opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24". Proceed [Y/n]? y</font></div><div><font size="2">[sudo] chyi의 암호: </font></div><div><font size="2">Extracting SDK................................................................................................................................................................................................................done</font></div><div><font size="2">Setting it up...done</font></div><div><font size="2">SDK has been successfully set up and is ready to be used.</font></div><div><font size="2">Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g.</font></div><div><br /></div><div><div><font color="#990000" size="2">[Tip] (설치 후 확인해 보니) ARM용 gcc compiler는 아래 디렉토리에 존재한다.</font></div><div><font color="#990000" size="2"> /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/sysroots/x86_64-ostl_sdk-linux/usr/bin/arm-ostl-linux-gnueabi </font></div></div><div><font color="#990000" size="2"><br /></font></div><div> $ <b>. /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi</b></div></div><div><i> -> 이 파일에는 cross-compile과 관련한 모든 환경 변수(SYSROOT, compile path 등)가 담겨 있다. 이 명령을 매번 실행하는 것 보다는 ~/.bashrc에 넣어 두면 편리하다.</i></div><div><i> -> 설치된 gcc(arm-ostl-linux-gnueabi-gcc) version이 9.3.0임을 알 수 있다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9vIRK1_HqkeY4yw5bTQkZiIJTm0PNqFsETmWhirqhuz2jSUcGKN4C01po5xgLHZ8sMaCAoiYHbwgl59dMjZLg4STR3-eUItZwpcwMgxys-_kHH2IC1iCiMluQfbMMHumdcxD32F5UYLf/s691/gcc_version.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="113" data-original-width="691" height="65" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEht9vIRK1_HqkeY4yw5bTQkZiIJTm0PNqFsETmWhirqhuz2jSUcGKN4C01po5xgLHZ8sMaCAoiYHbwgl59dMjZLg4STR3-eUItZwpcwMgxys-_kHH2IC1iCiMluQfbMMHumdcxD32F5UYLf/w400-h65/gcc_version.png" width="400" /></a></div><div><br /></div><div><br /></div><div><span style="background-color: #d9ead3;"><b><kernel download & build></b></span></div><div>$ <b>tar xvf en.SOURCES-kernel-stm32mp1-openstlinux-20-02-19.tar.xz</b></div><div>$ <b>cd stm32mp1-openstlinux-20-02-19/sources/arm-ostl-linux-gnueabi/linux-stm32mp-4.19-r0</b></div><div>$ <b>tar xvf linux-4.19.94.tar.xz</b></div><div>$<b> cd linux-4.19.94</b></div><div><div><br /></div><div>$ <b>make menuconfig</b></div><div>$ <b>make uImage vmlinux dtbs LOADADDR=0xC2000040 -j8</b></div><div>$ <b>make modules</b></div><div>$ <b>mkdir -p $PWD/install_artifact/</b></div><div>$ <b>make INSTALL_MOD_PATH="$PWD/install_artifact" modules_install</b></div></div><div><br /></div><div>이 정도로 해서 간단하게 device driver(or kernel programming) 개발 환경 설정 작업을 마무리하도록 하겠다. 보다 자세한 사항은 <a href="https://github.com/ALIBERA/linux_book_2nd_edition/blob/master/Linux_4.19_STM32MP1_practical_labs.pdf">참고 문헌 [1]</a>을 참조하기 바란다.</div><div><br /></div><div><br /></div></div><div><div><b><font color="#3367d6" size="6">2. GPIO Interrupt Platform Driver</font></b></div><div>필자는 이미 Linux kernel programming(or device driver programming)에 관하여 (3년 전에) 상세히 정리한 바가 있다.</div></div><div><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2017/03/linux-kernel-programming-guide.html">https://slowbootkernelhacks.blogspot.com/2017/03/linux-kernel-programming-guide.html</a></div><div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2017/03/efficient-linux-kernel-4x-programming.html">https://slowbootkernelhacks.blogspot.com/2017/03/efficient-linux-kernel-4x-programming.html</a></div></div><div><br /></div><div style="text-align: center;">and</div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2017/05/yocto-project-linux-device-driver.html">https://slowbootkernelhacks.blogspot.com/2017/05/yocto-project-linux-device-driver.html</a></div><div><br /></div><div>하지만 Linux kernel은 나날이 발전(<font color="#999999">오늘 현재 5.7.9가 release되어 있음</font>)하고 있어서, 위의 내용으로는 충분치 못하다는 생각이 들었다. 따라서 이번 posting에서는 여러 주제 중 <u>interrupt 관련 부분만을 뽑아</u> 최신 kernel (linux 4.19.94) 에 맞게<font color="#674ea7"> </font>재 정리해 보고자 한다.</div><div><br /></div><div><b><font color="#38761d" size="5">2.1) DK2 보드의 User Button</font></b></div><div>DK2 보드에는 사용자용 버튼(User1, User2)이 두개 있다. 이 두개의 버튼은 본래 u-boot에서 firmware writing mode(User1: USB programming mode, User2: Android fastboot mode)로 진입하기 위해 만들어졌지만, 필자는 이를 <u><font color="#bf9000"><b>gpio interrupt 처리용으로 잠시 용도변경</b></font></u>해 볼 생각이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTnLge5-sdUG-yFOZ0u7FsOvZKwczhPaZpkOsTKd6w9An_JJrMEPQjBDmRt1mLxti1C_uSLfSjRVMqH-fxzypabBblmgI8mIceGws5dwLpLqNVtbnwB8u_OYTLbgbDShl51z4PJBHe7Xv/s1007/dk2_user1_button.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="261" data-original-width="1007" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTnLge5-sdUG-yFOZ0u7FsOvZKwczhPaZpkOsTKd6w9An_JJrMEPQjBDmRt1mLxti1C_uSLfSjRVMqH-fxzypabBblmgI8mIceGws5dwLpLqNVtbnwB8u_OYTLbgbDShl51z4PJBHe7Xv/w400-h104/dk2_user1_button.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] DK2 보드의 사용자 버튼(User1, User2)</div><div class="separator" style="clear: both; text-align: left;"><font color="#990000" size="2">[Tip] 위의 그림에서 User2 버튼이 B2로 표기된 부분은 오타인 듯 보인다. 즉, B2 -> B4로 표기되는 것이 맞을 것 같다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwF0894z_5NRLYw8S3pZZnWrlpMl42kVuUJN80nSqf8glK8t28MYwOR6f5aFnRSqPWCpgClAWiM8iKRpsuQZzAQfUI46Rujd05cVgdk9UrKoxDzm8WgcmesOn4cH0R0KvY3SZrJx4WJ6eU/s957/dk2_user_button_pinmap.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="171" data-original-width="957" height="114" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwF0894z_5NRLYw8S3pZZnWrlpMl42kVuUJN80nSqf8glK8t28MYwOR6f5aFnRSqPWCpgClAWiM8iKRpsuQZzAQfUI46Rujd05cVgdk9UrKoxDzm8WgcmesOn4cH0R0KvY3SZrJx4WJ6eU/w640-h114/dk2_user_button_pinmap.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.2] DK2 보드의 사용자 버튼(User1, User2)의 pinmap</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHffEwifXgO6l3UPhC4XPHI2y5DHMiT7sAH0OiNtAoD7MNUzXtXvkfeqVr3DaWFFqCqCjSfyzlsKWOGpcFIZnKDwXsa7izuzhDWIqHnzhkHM4H2_7nJ9siuGBc6Zrgq-sGLtlvm7U_Bx2q/s887/dk2_block_diag_gpio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="448" data-original-width="887" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHffEwifXgO6l3UPhC4XPHI2y5DHMiT7sAH0OiNtAoD7MNUzXtXvkfeqVr3DaWFFqCqCjSfyzlsKWOGpcFIZnKDwXsa7izuzhDWIqHnzhkHM4H2_7nJ9siuGBc6Zrgq-sGLtlvm7U_Bx2q/s320/dk2_block_diag_gpio.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.3] DK2 보드의 block도 중 User button(우측) 발췌</span></div><div><br /></div><div><br /></div><div><b><font color="#38761d" size="5">2.2) Device Tree 내용 추가</font></b></div><div>앞서 언급한 User1 버튼은 아래 그림과 같이 PA14 pin(GPIO A bank 14번째 pin)에 연결되어 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2WeMsg5LacUjbeZLo5fBR_65Nq-hoMNAW1wANRjJ2YlovVuJqZcV4Jszug4g7Z_hGg7P6IMbO5HNkEpqPuCyWdpGhPFoh8mTR4QaoEREKEevSJUUrc83SG4jRsVY8zCyILVa42DRgfjfF/s330/dk2_PA14_button_schematic.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="142" data-original-width="330" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2WeMsg5LacUjbeZLo5fBR_65Nq-hoMNAW1wANRjJ2YlovVuJqZcV4Jszug4g7Z_hGg7P6IMbO5HNkEpqPuCyWdpGhPFoh8mTR4QaoEREKEevSJUUrc83SG4jRsVY8zCyILVa42DRgfjfF/w400-h173/dk2_PA14_button_schematic.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.4] User1 버튼에 대한 회로도 - push-pull 회로</span></div><div><br /></div><div>DK2 보드용 device tree 파일 내용을 살펴보면, STMP157C 칩(SoC)에는 대략 10개(gpio A ~ I, Z) 정도의 GPIO bank가 존재하는 것 같다. 또한 하나의 GPIO bank에는 16개의 GPIO pin이 포함되어 있음을 알 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjxS7z73Ya9CcLuq5QVOvASa1cw_NFvGwWs4hKGnH60pnH0EneSsuEkqXmyHI_oMRSOb_7IfbCCBhqKs3BQpO-FznFdyfDKQ1VPg_lpkpVRG9u9da-2Mu9FFOqlozfoiWonw9IQQ8Zodh5/s952/dk2_gpio_bank.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="952" data-original-width="404" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjxS7z73Ya9CcLuq5QVOvASa1cw_NFvGwWs4hKGnH60pnH0EneSsuEkqXmyHI_oMRSOb_7IfbCCBhqKs3BQpO-FznFdyfDKQ1VPg_lpkpVRG9u9da-2Mu9FFOqlozfoiWonw9IQQ8Zodh5/w170-h400/dk2_gpio_bank.png" width="170" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.5] STMP157C의 GPIO controller에 대한 device tree 표현 - </span><span style="text-align: left;">stm32mp157cac-pinctrl.dtsi 파일에서 발췌</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL8CRXJyNrRWZWdJwtaksTrrTdBxakXZa7VUjn4LN7fj-UtovNx_woYYehdayESSv1Uc-2NnT4KZfSYNiLIw_iCc95pj9RSDhk1sFVTFC91DSDZV1FBcClRdKTP8e8gBtAPwKYWCF_7pki/s820/dk2_gpio_bank.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="277" data-original-width="820" height="135" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgL8CRXJyNrRWZWdJwtaksTrrTdBxakXZa7VUjn4LN7fj-UtovNx_woYYehdayESSv1Uc-2NnT4KZfSYNiLIw_iCc95pj9RSDhk1sFVTFC91DSDZV1FBcClRdKTP8e8gBtAPwKYWCF_7pki/w400-h135/dk2_gpio_bank.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="text-align: left;">[그림 2.6] kernel booting message</span></div><div><br /></div></div><div><br /></div><div><span style="background-color: #f1c232;"><b><여기서 잠깐 !></b></span></div><div><span><i><font color="#990000"> -> DK2 보드의 device tree에 관하여</font></i></span><br /></div><div>1장에서 사용한 kernel source를 기준으로 device tree 파일(linux-4.19.94/arch/arm/boot/dts/stmp32mp*)의 상관 관계를 파악해 보면 대략 다음과 같다.</div><div><div style="text-align: center;"><b><font color="#e69138"><br /></font></b></div><div style="text-align: center;"><b><font color="#e69138">stm32mp157c.dtsi</font></b></div><div style="text-align: center;"><b>stm32mp157cac-pinctrl.dtsi -> </b><b style="text-align: left;"><font color="#8e7cc3">stm32mp157-pinctrl.dtsi</font></b></div><div style="text-align: center;"><b><font color="#666666">stm32mp157c-m4-srm.dtsi</font></b></div></div><div style="text-align: center;"><b>^</b></div><div style="text-align: center;"><b>|</b></div><div style="text-align: center;"><b><font color="#6aa84f">stm32mp157a-dk1.dts</font></b></div><div style="text-align: center;"><b>^</b></div><div style="text-align: center;"><b>|</b></div><div style="text-align: center;"><b><font color="#3d85c6">stm32mp157c-dk2.dts</font></b></div><div style="text-align: center;">[그림 2.7] DK2 보드의 device tree 상관 관계도</div><div style="text-align: center;"><br /></div><div style="text-align: left;">그런데, 이 내용은 <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">이전 blog post에서 분석한 내용(buildroot 기반)</a>과는 사뭇 차이가 난다. 왜 그럴까 ?</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKU00RmVqu2GVwQnDt7wYizukbP49yfKfzhoYAvbj5URkdeyKkubWVUDgCT493R2MzBaSdI_H7JPa2FuUpBDq_D68DIuLhd5lBJs42jroM79Ajk8yw0LMjZ1LouFbUDn5-eezsXstbNrK5/s321/dk2_device_tree_hierarchy_buildroot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="321" data-original-width="266" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKU00RmVqu2GVwQnDt7wYizukbP49yfKfzhoYAvbj5URkdeyKkubWVUDgCT493R2MzBaSdI_H7JPa2FuUpBDq_D68DIuLhd5lBJs42jroM79Ajk8yw0LMjZ1LouFbUDn5-eezsXstbNrK5/s320/dk2_device_tree_hierarchy_buildroot.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.8] DK2 보드의 device tree 상관 관계도 - buildroot 기준</div><div><br /></div><div>이는 아마도, Yocto 환경(linux-4.19.94)과 buildroot 환경(linux-5.7.1)에서 오는 차이인 듯하다. 아니, kernel 버젼이 다른 것이 더 큰 이유가 될 것 같다.</div><div><br /></div><div>어찌됐든 우리는 이 중에서 User1 button을 활용한 GPIO interrupt 부분에 관심이 있으니, 이와 관련해서 좀 더 분석해 보기로 하자.</div><div><br /></div><div><b style="background-color: #d9d2e9;"><gpio controller & device 상호 관계></b></div><div><div style="text-align: center;"><b>intc(GIC) <---- gpioa controller <--- User1 button</b></div><div style="text-align: center;"><b> <font color="#b45f06"> (interrupt-parent) (interrupt device)</font></b></div></div><div><br /></div><div><br /></div><div><span style="background-color: #d9d2e9;"><b><gpioa controller node></b></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCK5W9vnh6iMBNCYzTxFipCCyMGTgfA9ft41TwTTGEvZILJk6IkZiDH9tU44F7PoBQoppEz1W4ZFwVz2pzFS3p8atazptCQgeHWm_6BZRj8k6q0rTmwHDuKxLO4Ve3YtZte79tW2A55iqO/s270/dk2_gpia_1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="198" data-original-width="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCK5W9vnh6iMBNCYzTxFipCCyMGTgfA9ft41TwTTGEvZILJk6IkZiDH9tU44F7PoBQoppEz1W4ZFwVz2pzFS3p8atazptCQgeHWm_6BZRj8k6q0rTmwHDuKxLO4Ve3YtZte79tW2A55iqO/s0/dk2_gpia_1.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.9] gpioa bank(gpio a controller) - stm32mp157-pinctrl.dtsi</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhayVPI-pYuAMVmqvhy6Djxa3nUzduORgEtz8mfW1HNBPUtai94a-7fOFR6axD43ziCELaQdV5HsEBrSFQ9aLlUoh_T06EdQevuakQDz3fe8_nqrrGYSqbDjOJQn-4y6xJ0silO_yj7A-7O/s346/dk2_gpioa_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="108" data-original-width="346" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhayVPI-pYuAMVmqvhy6Djxa3nUzduORgEtz8mfW1HNBPUtai94a-7fOFR6axD43ziCELaQdV5HsEBrSFQ9aLlUoh_T06EdQevuakQDz3fe8_nqrrGYSqbDjOJQn-4y6xJ0silO_yj7A-7O/s320/dk2_gpioa_2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.10] </span>gpioa bank(gpio a controller) - stm32mp157cac-pinctrl.dtsi</div><div><b><br /></b></div><div>GPIO 속성 설정과 관련해서는 아래 문서를 참조할 필요가 있다.</div><div style="text-align: center;"><b>Documentation/devicetree/bindings/gpio/gpio.txt</b></div><div><b><br /></b></div><div>User1 button 용 device tree node는 대략 다음과 같다(예상해 볼 수 있다).</div><div><br /></div><div><b style="background-color: #d9d2e9;"><User1 button - gpio device node></b></div><div><div>user1_button {</div><div> <font color="#999999"> compatible = "blahblahblah";</font></div><div> user1-gpios = <<b><font color="#a64d79">&gpioa 14</font></b> <font color="#999999">GPIO_ACTIVE_LOW</font>>;</div><div> interrupt-parent = <<b><font color="#a64d79">&gpioa</font></b>>;</div><div> interrupts = <<font color="#a64d79"><b>14</b></font> <font color="#999999">IRQ_TYPE_EDGE_FALLING</font>>;</div><div>};</div></div><div><br /></div><div><div><span style="background-color: #b6d7a8;"><속성 정보 설명></span></div><div><b><font color="#b45f06">[<name>-]</font>gpios</b> 속성 지정자</div><div> => <i>bank(phandle), pin 번호, active-high or active-low value</i></div><div><i><font color="#990000" size="2">[참고] <name>-gpios 형태로 사용해야 함(new style). <name>- 없이 gpios, gpio도 사용 가능(하위 버젼 호환성 차원에서 지원)</font></i></div><div><div><b><br /></b></div><div><b>interrupt-parent </b>속성</div><div><b> </b>=> <i>interrupt controller(여기서는 gpioa)에 대한 phandle 값</i></div><div><b><br /></b></div><div><b>interrupts </b>속성</div><div><b> </b>=><b> </b><i>interrupt signal을 내보내는 device(gpio pin/pad)의 pin 값(여기서는 14)과, IRQ type(include/dt-bindings/interrupt-controller/irq.h 내용 참조) 지정</i></div></div><div>-- -- -- -- --</div></div><div><br /></div><div>GPIO pin을 제대로 활용하기 위해서는 pin control 설정에 대해서도 정확히 알고 있어야 한다. 이와 관련해서는 아래 문서를 참조하도록 하자.</div><div style="text-align: center;"><b>Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPMCx3UyWE4HLRLFWI-ekDi4xQrMgxLhU7roHZvFSVJT9hdXHu-JFDgZusFjlb_VgmIFcU2wiFoo54KCkftxIvY1Vtu9Mkd1v3Gv81Zi8_AZXlt2wtoHGurplcj1hA_VjiISQUMsHGGulq/s698/dk32_pinctrl_txt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="698" data-original-width="574" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPMCx3UyWE4HLRLFWI-ekDi4xQrMgxLhU7roHZvFSVJT9hdXHu-JFDgZusFjlb_VgmIFcU2wiFoo54KCkftxIvY1Vtu9Mkd1v3Gv81Zi8_AZXlt2wtoHGurplcj1hA_VjiISQUMsHGGulq/w329-h400/dk32_pinctrl_txt.png" width="329" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.11] Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt</div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: #ffd966; text-align: left;">---------------</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div>이상의 내용을 기초로 device tree 코드를 구현해 보도록 하자.</div><div><br /></div><div><div><span style="background-color: #b6d7a8;"><stm32mp157-pinctrl.dtsi에 추가할 내용></span></div><div><i>pinctrl_user2_button_a: user2-pb-0 {</i></div><div><i> pins {</i></div><div><i> pinmux = <STM32_PINMUX('A', 14, GPIO)>;</i></div><div><i> drive-push-pull;</i></div><div><i> };</i></div><div><i>};</i></div><div><div><font color="#990000" size="2">[Tip] STM32_PINMUX macro는 include/dt-bindings/pinctrl/stm32-pinfunc.h 파일에 정의되어 있다.</font></div><div><font color="#990000" size="2">[Tip] 위에서 drive-push-pull을 지정한 이유는 그림 2.4의 회로도를 유심히 살펴보면 알 수가 있다. Push-pull 출력은 2개의 TR(transistor)로 구성되어 있는데, 아래 스위치(TR)를 누르면 출력 핀(PA14)이 GND와 연결되어 LOW가 출력(전류 싱크)되고, 위쪽 스위치를 누르면 출력 핀은 VCC(3.3V)와 연결되어 HIGH가 출력(전류 소스)된다. Push-pull과 대비되는 개념으로 open-drain/collector가 있는데, 얘는 전류 싱크로만 동작 가능하다. 즉, LOW 상태와 회로가 open된 상태인 하이 임피던스만 존재한다.</font></div></div></div><div><span style="background-color: #b6d7a8;"><br /></span></div><div><span style="background-color: #b6d7a8;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlzjW3K1wGZIwzqOGOpAcCb8kbSWTMHClj_IexYrHmgiA7pjJJ1iAOIOQAqq3TWSdz6s8JJO9jqG4QGjNXvdKGWl9G0lHUieWZoISM6ZyTCdIUpJ5dJentlf4b_S-vL-nSkraeLRa9yzi/s719/dk2_stm32_pinmux_macro.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="474" data-original-width="719" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFlzjW3K1wGZIwzqOGOpAcCb8kbSWTMHClj_IexYrHmgiA7pjJJ1iAOIOQAqq3TWSdz6s8JJO9jqG4QGjNXvdKGWl9G0lHUieWZoISM6ZyTCdIUpJ5dJentlf4b_S-vL-nSkraeLRa9yzi/w400-h264/dk2_stm32_pinmux_macro.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.12] include/dt-bindings/pinctrl/stm32-pinfunc.h 파일</div></span></div><div><span style="background-color: #b6d7a8;"><br /></span></div><div><span style="background-color: #b6d7a8;"><stm32mp157a-dk1.dts에 추가할 내용></span></div><div><div><i>my_button_interrupt {</i></div><div><i> compatible = "eagle,int-button";</i></div><div><i> pinctrl-names = "default";</i></div><div><i> pinctrl-0 = <&pinctrl_user2_button_a>; /*<span style="background-color: white;"> </span></i><span style="background-color: white;"><i>stm32mp157-pinctrl.dtsi에서 정의 */</i></span></div><div><i> mybtn-gpios = <&gpioa 14 </i><font color="#b45f06" style="font-style: italic;">GPIO_ACTIVE_LOW</font><i>>; /* new style gpio specifier */</i></div><div><i> interrupt-parent = <&gpioa>;</i></div><div><i> interrupts = <14 <font color="#b45f06">IRQ_TYPE_EDGE_FALLING</font>>;</i></div><div><i>};</i></div></div><div><br /></div><div>Device tree 작업을 마쳤으니, 관련 내용을 target board에 반영시켜 볼 차례이다^^.</div><div><br /></div><div>$<b> cd linux-4.19.94</b></div><div>$ <b>make dtbs</b></div><div><i> -> 지금까지 작업한 내용을 compile해 보자.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5g0bUIQyUYg17mC_5URpGI3H-QtNhzngR56vM7JcL1bFmqmytzc0vcrw7k-2coMDuQdTrIYYGsT6CcuE8lf9jpOGHafzBSebRWXOhcLGcifu2a929hrfz8aTJEKPRA888REizi6j5005V/s953/dk2_make_dtbs.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="131" data-original-width="953" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5g0bUIQyUYg17mC_5URpGI3H-QtNhzngR56vM7JcL1bFmqmytzc0vcrw7k-2coMDuQdTrIYYGsT6CcuE8lf9jpOGHafzBSebRWXOhcLGcifu2a929hrfz8aTJEKPRA888REizi6j5005V/w640-h88/dk2_make_dtbs.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.13] compile 후, dtb 파일 생성</div><div><br /></div><div>다음으로, compile 결과 파일(dtb 파일)을 target board에 올려 보도록 하자.</div><div><br /></div><div><b><Target board></b></div><div>root@stm32mp1:~# <b>ifconfig eth0 192.168.1.100 netmask 255.255.255.0 up</b></div><div><br /></div><div><b><Desktop PC></b></div><div>$ cd arch/arm/boot</div><div>$ <b>scp ./uImage root@192.168.1.100:~/workspace/boot</b></div><div><i> -> device tree 파일만 수정했으나, 현재 동작중인 kernel과 새로 build한 kernel 간에 차이가 있을 수 있으므로, kernel image(uImage)도 함께 교체하도록 한다.</i></div><div>$ cd dts</div><div>$ <b>scp ./stm32mp157c-dk2.dtb root@192.168.1.100:~/workspace/boot</b></div><div>$ <b>scp ./stm32mp157c-dk2-a7-examples.dtb root@192.168.1.100:~/workspace/boot</b></div><div>$ <b>scp ./stm32mp157c-dk2-m4-examples.dtb root@192.168.1.100:~/workspace/boot</b></div><div><font color="#990000" size="2">[Tip] DK2 보드는 현재 microSD로 부팅한 상태이며, /boot 디렉토리에 kernel과 dtb 파일 등이 위치하고 있다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIa9ri44RYll5Wuw5YqtUcWDMfxs8koGFCLwTREmRrHAm5jWTzc5z9fNawDCQUXgsPN_03-4dhP3glvKLckoFdMEpEmWEICV-tCLThDIaDVBVmEsnAXblYsRxQukWa9YTa0A3Znrt1X73V/s758/dk2_boot_dir.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="682" data-original-width="758" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIa9ri44RYll5Wuw5YqtUcWDMfxs8koGFCLwTREmRrHAm5jWTzc5z9fNawDCQUXgsPN_03-4dhP3glvKLckoFdMEpEmWEICV-tCLThDIaDVBVmEsnAXblYsRxQukWa9YTa0A3Znrt1X73V/s320/dk2_boot_dir.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.14] target board /boot 디렉토리</div><div><br /></div><div><b><Target board></b></div><div>root@stm32mp1:~# cd ~/workspace/boot</div><div>root@stm32mp1:~# <b>cp ./uImage /boot</b></div><div>root@stm32mp1:~# <b>cp ./*.dtb /boot</b></div><div>root@stm32mp1:~# sync; sync; <b>reboot</b></div><div><i> -> 파일 교체 후에는 반드시 부팅을 하도록 한다.</i></div><div><br /></div><div><b><font color="#38761d" size="5">2.3) Platform driver 구현</font></b></div><div>Device tree 작업이 끝났으니, 이제 부터는 이를 사용하는 platform driver(gpio interrupt driver)를 구현해 볼 차례이다.</div><div><br /></div><div><div>원래는 driver 작성 과정을 상세히 설명할 계획이었으나, 시간 관계상 source code의 위치를 소개하는 것으로 이를 대신하고자 한다.</div><div><br /></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_08/lab3_interrupt.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_08/lab3_interrupt.c</a></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx5jIhCSQFoVhvCCybBvRFtcLfH1HCxCIgKRtyYjTvS4OOXmCW6S0w5-2fHKSqepxQjoxO6EguBmu7-rBvu06VQvOJonfnCa6g95S8zibHsyTP6HiG0Kf1ZKW1T75jnA_w101NYJqijIke/s862/dk2_lab3_interrupt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="862" data-original-width="756" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx5jIhCSQFoVhvCCybBvRFtcLfH1HCxCIgKRtyYjTvS4OOXmCW6S0w5-2fHKSqepxQjoxO6EguBmu7-rBvu06VQvOJonfnCa6g95S8zibHsyTP6HiG0Kf1ZKW1T75jnA_w101NYJqijIke/s320/dk2_lab3_interrupt.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.15] GPIO interrupt - platform driver probe 함수 소개</div><div><br /></div><div>그럼, driver가 제대로 동작하는지 확인해 보도록 하자.</div><div><br /></div><div><b><Desktop PC></b></div><div>$ <b>git clone https://github.com/ChunghanYi/linux_kernel_hacks</b></div><div><i> -> 위의 코드는 필자의 github에 올려 두었으니, 이를 먼저 내려 받도록 한다.</i></div><div>$ <b>cd linux_kernel_hacks/writing_device_drivers_by_coopj/s_08</b></div><div>$ <b>../genmake</b></div><div><b> </b><i>-> Makefile을 자동으로 생성해준다.</i></div><div>$ <b>make clean</b></div><div>$ <b>make</b> </div><div>$ <b>file lab3_interrupt.ko</b></div><div><i> -> cross-compile이 제대로 되었는지 확인해 본다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcOMzZUa-0J1jF2j5sJXCGLC074U0OMLqYypZNOjwr0SQA9d2DoJ4OWiYFkMSD5H3Idfcr17NRnW9IkPFFCBa7i4bZ_ENKq3R71q1-DBaobRnOFrthaGPyx632jBi5_TDC22_TYPxCORhz/s953/dk2_lab3_interrupt_file.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="79" data-original-width="953" height="34" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcOMzZUa-0J1jF2j5sJXCGLC074U0OMLqYypZNOjwr0SQA9d2DoJ4OWiYFkMSD5H3Idfcr17NRnW9IkPFFCBa7i4bZ_ENKq3R71q1-DBaobRnOFrthaGPyx632jBi5_TDC22_TYPxCORhz/w400-h34/dk2_lab3_interrupt_file.png" width="400" /></a></div><div><br /></div><div>$ <b>scp ./lab3_interrupt.ko root@192.168.1.100:~/workspace</b></div><div><i> -> scp 명령을 사용하여 target board로 kernel module을 올린다.</i></div><div><br /></div><div><b><Target board></b></div><div><div>root@stm32mp1:~/workspace# <b>insmod ./lab3_interrupt.ko </b></div><div><i> -> insmod 명령을 사용하여 kernel module을 구동시킨다.</i></div><div><font size="2">[ 3769.676181] int-button my_button_interrupt: my_probe() function is called.</font></div><div><font color="#990000" size="2">[ 3769.681772] stm32mp157-pinctrl soc:pin-controller@50002000: pin PA14 already requested by my_button_interrupt; cannot claim for GPIOA:14</font></div><div><font color="#990000" size="2">[ 3769.694580] stm32mp157-pinctrl soc:pin-controller@50002000: pin-14 (GPIOA:14) status -22</font></div><div><font size="2">[ 3769.701946] int-button my_button_interrupt: gpio get failed</font></div><div><font size="2">[ 3769.707667] int-button: probe of my_button_interrupt failed with error -22</font></div></div><div><br /></div><div>어랍쇼~ 에러가 발생한다. 어디가 문제일까 ?<font color="#800180"> </font><b style="color: #800180;">"pin-controller ... pin PA14 already requested"</b><span>라는 부분이 보이는데 ?!</span></div><div><br /></div><div>이상하다. GPIOA 14 pin에 대한 설정을 다른 곳에서 이미 하고 있나 ? 그렇다면, 일단 pinctrl 설정 부분을 막고 테스트해 보자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0L_CcLX0xahLlEP4LHWGIfPJu8YT0HKIKUtm5Jx1Ek1_XXT4ZH1C8YdAaVpCOPNREOlUHZtlLH00St4TQIcNR61czHtwXZlmHeK0jhoLl_eml8pClFxYllCFK9Ki6KtfqMshpfrsiboHL/s508/dk2_interrupt_driver_device_tree.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="242" data-original-width="508" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0L_CcLX0xahLlEP4LHWGIfPJu8YT0HKIKUtm5Jx1Ek1_XXT4ZH1C8YdAaVpCOPNREOlUHZtlLH00St4TQIcNR61czHtwXZlmHeK0jhoLl_eml8pClFxYllCFK9Ki6KtfqMshpfrsiboHL/w400-h190/dk2_interrupt_driver_device_tree.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.16] device tree 수정 버젼(stm32mp157a-dk1.dts) - pinctrl 부분 제거</div><div><br /></div><div><b><Target board></b></div><div>root@stm32mp1:~/workspace# <b>insmod ./lab3_interrupt.ko</b></div><div><i> -> 수정 후, 다시 테스트(반복되는 과정은 생략)해 보니, 정상 동작한다.</i></div><div><i> -> User1 버튼을 누르면, 한줄씩 메시지가 출력된다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4HZF_FNZ0hZqcDQf7U6CQYpg2qdRbTBTv4By_kOFLITexxV2kiP9PG8Kfs3rXr2XR8Uv-XQqKPF-XLoHTadJw17IqwkrfyityBtkevH7K1P64c5OjmsqdsTgP5S7x3ClWeS6l7UTbyyz2/s895/dk2_lab3_interrupt_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="356" data-original-width="895" height="159" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4HZF_FNZ0hZqcDQf7U6CQYpg2qdRbTBTv4By_kOFLITexxV2kiP9PG8Kfs3rXr2XR8Uv-XQqKPF-XLoHTadJw17IqwkrfyityBtkevH7K1P64c5OjmsqdsTgP5S7x3ClWeS6l7UTbyyz2/w400-h159/dk2_lab3_interrupt_ok.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.17] lab3_interrupt.ko 모듈 정상 동작 모습</div><div><font color="#990000" size="2">[Tip] 왜 PA14 already requested 메시지가 출력되는지를 알기 위해서는 전체 device tree 부분을 면밀히 검토해 보아야 할 듯하다.</font></div><div><br /></div><div><div><b style="background-color: #ffe599;"><여기서 잠깐 !></b></div><div><i style="background-color: white;"><b> </b> -> devm_request_irq( ) 함수에 대해...</i></div><div>-------------------------------------------------------------------------------------------------------------------</div><div>int <b>devm_request_irq</b>(struct device *dev,<br /> unsigned int irq,<br /> irq_handler_t handler,<br /> unsigned long irq_flags,<br /> const char *devname,<br /> void *dev_id);</div><div><br /><i>a) interrupt handler를 등록한다.</i><br /><i>b)기존에 많이 사용하던 request_irq( ) 함수와 비교해, 첫번째 argument가 struct device pointer라는 점에서 차이가 있는데, 이런 함수를 일컬어 <b>managed resource API</b>(workqueue로 유명한 허태준씨가 2007년 kernel 2.6.21부터 제안함)라고 부른다.</i></div><div><i>c) <font color="#351c75">request_irq()는 사용 후, free_irq()를 반드시 해 주어야 하나, devm_request_irq()는 driver 제거 or probe 실패 시 자동으로 memory를 해제시켜 주는 특징이 있다.</font><br /></i><i>d) 자세한 사항은 참고문헌 [4]를 참고하도록 하자.</i><br /><br /><i> - <b>dev</b>: device나 module이 해제될 때에 자동으로 제거되는 장치에의 pointer</i><br /><i> - <b>irq: IRQ number</b>. platform device의 경우는 platform_get_irq() 함수를 통해 얻은 값을 사용하면 됨.</i><br /><i> - <b>handler</b>:<b> </b>IRQ handler 함수 pointer</i><br /><i> - <b>irq_flags: </b> IRQ flag 값(아래 값을 사용할 수 있음)</i><br /><i> #define IRQF_TRIGGER_NONE 0x00000000</i><br /><i> #define IRQF_TRIGGER_RISING 0x00000001</i><br /><i> #define IRQF_TRIGGER_FALLING 0x00000002</i><br /><i> #define IRQF_TRIGGER_HIGH 0x00000004</i><br /><i> #define IRQF_TRIGGER_LOW 0x00000008</i><br /><i> #define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \</i><br /><i> IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)</i><br /><i> #define IRQF_TRIGGER_PROBE 0x00000010</i><br /><i> - <b>devname</b>: interrupt를 위해 사용하는 이름(/proc/interrupts로 확인 가능)</i><br /><i> - <b>dev_id</b>: device별 data structure를 가리키는 pointer를 전달하기 위해서 사용함.</i><br />-------------------------------------------------------------------------------------------------------------------</div></div><div><br /></div><div>이상으로 기본적인 GPIO interrupt driver(platform driver)와 관련 device tree 작업을 진행해 보았다.</div><div><br /></div><div><br /></div><div><div><b><font color="#3367d6" size="6">3. Bottom Halves and Deferring Work</font></b></div><div>이제부터는 2장에서 작성한 platform driver의 내용을 조금씩 변경해 가면서, kernel timer, tasklet, threaded interrupt, work queue, kernel thread 등에 관하여 살펴 보도록 하자. Kernel이 upgrade되면서 많은 부분이 달라졌다. 따라서 예전에 정리해 둔 내용으로는 문제가 있다(<font color="#999999">하지만, 그림은 나름 쓸만하여 copy & paste해 보았다</font> 😅).</div></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCp80BatW1hT0EpKOnWC8xl7e3r019c17pRRUMx4APwk21H5jXRAjrR95tgCYztxLmxEj50fZ0tKT2N9UJNMv3EuPVFYtd-aAfJ-D0wRnbYQN2jN1VEz807f_JHGYovrlV4OQxwCIA4bJ8/s867/linux_interrupt_bottom_halves.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="322" data-original-width="867" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCp80BatW1hT0EpKOnWC8xl7e3r019c17pRRUMx4APwk21H5jXRAjrR95tgCYztxLmxEj50fZ0tKT2N9UJNMv3EuPVFYtd-aAfJ-D0wRnbYQN2jN1VEz807f_JHGYovrlV4OQxwCIA4bJ8/w400-h149/linux_interrupt_bottom_halves.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] Linux interrupt(top half)와 Bottom halves 개념도</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNOJUXjZc-z2KpwEPQzlIVY-e8u-w5TCiW3F8JJFzx6jWQDZhy16JunfrmU0Iqb3ak1GclDkm8RdlEo02Wl5ziK74ESVu0w7YrFiEn0PwoH3lNmU6OV9EMNcH4eAE1BTFxPVexxuvQV8Dz/s1035/interrupt_handler.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="667" data-original-width="1035" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNOJUXjZc-z2KpwEPQzlIVY-e8u-w5TCiW3F8JJFzx6jWQDZhy16JunfrmU0Iqb3ak1GclDkm8RdlEo02Wl5ziK74ESVu0w7YrFiEn0PwoH3lNmU6OV9EMNcH4eAE1BTFxPVexxuvQV8Dz/s320/interrupt_handler.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] Interrupt와 interrupt handler 개요도</div><div><div><br /></div></div><div>본격적인 내용 설명에 앞서 (좀 오래된 문서이기는 하지만) 필자가 오래 전에 작성해 둔 <a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/android_kernel_hacks/Android_Device_Driver_Guide13.pdf">참고 문헌 [3]</a>을 반드시 훑어 볼 것을 권한다. 지면 & 시간 관계상 모든 것을 다시 설명을 할 수는 없으니 말이다. 😂</div><div><br /></div><div><b><font color="#38761d" size="5">3.1) Kernel Timer</font></b></div><div><b style="background-color: #cfe2f3;"><개요></b></div><div><b style="background-color: #cfe2f3;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUA2bZRlCEKqVZgu9T1EBxaBsh4fPpTG_AY3HnFp2CBMjloMLuKaXaDScCu0EOQbVYzYFVULhmRjCSe55AQ-mAI_ltPDQgzpBMKPINC1YVc7BceprGFchscC57PflOz6ly9bwvHNlpdltQ/s1017/timer2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="647" data-original-width="1017" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUA2bZRlCEKqVZgu9T1EBxaBsh4fPpTG_AY3HnFp2CBMjloMLuKaXaDScCu0EOQbVYzYFVULhmRjCSe55AQ-mAI_ltPDQgzpBMKPINC1YVc7BceprGFchscC57PflOz6ly9bwvHNlpdltQ/w400-h255/timer2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] kernel timer 개요도</div><div><br /></div><div><font color="#990000" size="2">[Tip] kernel timer API는 예전 버젼</font><span style="color: #990000; font-size: small;">(3.x 이하, 시점은 정확하지 않음)</span><span style="color: #990000; font-size: small;">과 많은 차이를 보인다. 특히 초기화 함수인 init_timer() 대신 timer_setup()를 사용해야 한다. 그 밖에도 많은 부분에 변화가 있다. 아래 예제 코드를 통해 직접 확인해 보기 바란다.</span></div><div><br /></div><div><b style="background-color: #d9ead3;"><Example code></b></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_11/new/lab4_periodic_timers_alt_new.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_11/new/lab4_periodic_timers_alt_new.c</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGEHEm7jTHisGuHyRBLZPPd2cTrAWDgOMYP2A5nzPjzdwXQPQ8jScReR8B2zqDFVzEGGGvIkCLIBGFrBDOKUo2x4VO_hVBUeObWDK4xZN2eAXxoOeC6riSqdOfoHPSdXLfudy9w78pcIyy/s741/timer_githubcode.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="741" data-original-width="603" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGEHEm7jTHisGuHyRBLZPPd2cTrAWDgOMYP2A5nzPjzdwXQPQ8jScReR8B2zqDFVzEGGGvIkCLIBGFrBDOKUo2x4VO_hVBUeObWDK4xZN2eAXxoOeC6riSqdOfoHPSdXLfudy9w78pcIyy/w325-h400/timer_githubcode.png" width="325" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.4] kernel timer 예제 코드</div><div><br /></div><div><b style="background-color: #ead1dc;"><실행 모습></b></div><div>root@stm32mp1:~/workspace# <b>insmod ./lab4_periodic_timers_alt.ko</b></div><div style="text-align: left;"> <i> -> 구동해 보니, 두개의 kernel timer가 서로 다른 주기로 message를 출력함을 알 수 있다.</i></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCVHxD4E2Xz4AsG8TYkHTVzPN7ZyYi1ftFVrAoWIO8KuCd_e4RM-4u9oCqzBppsld16U5Gd0AljJPyTf1Zp0LoeVwtR6sIyC-ssrjMrWryKynUQvfF_ipR8f4lpANv0kc6zPunvWwR0IIg/s671/timer1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="615" data-original-width="671" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCVHxD4E2Xz4AsG8TYkHTVzPN7ZyYi1ftFVrAoWIO8KuCd_e4RM-4u9oCqzBppsld16U5Gd0AljJPyTf1Zp0LoeVwtR6sIyC-ssrjMrWryKynUQvfF_ipR8f4lpANv0kc6zPunvWwR0IIg/s320/timer1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.5] kernel timer 예제 실행 모습</div><div><font color="#990000" size="2">[Tip] 편의 상, kernel timer example은 2장에서 소개한 platform driver랑은 무관하게 작성하였다.</font></div><div><br /></div><div><div><b><font color="#38761d" size="5">3.2) Tasklet</font></b></div><div><b style="background-color: #cfe2f3;"><개요></b></div><div><b style="background-color: #cfe2f3;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhphNRlUA7_PoAz-51q7DPshUlg9gG0tAynNMobtBjEOeLUzjEXM4BiEic2MAli5NgHlW2vkA7p2TNIiUk0OIVEYgSqWfzKskSm0NCSg-cNTE6aNIMBa-y0Ff41jQja-YfBkdfVfQqqQUQX/s1072/tasklet2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="737" data-original-width="1072" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhphNRlUA7_PoAz-51q7DPshUlg9gG0tAynNMobtBjEOeLUzjEXM4BiEic2MAli5NgHlW2vkA7p2TNIiUk0OIVEYgSqWfzKskSm0NCSg-cNTE6aNIMBa-y0Ff41jQja-YfBkdfVfQqqQUQX/w400-h275/tasklet2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.6] tasklet 개요도</div><div><br /></div><div><b style="background-color: #d9ead3;"><Example code></b></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_tasklet.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_tasklet.c</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMZiXFMpCjpoNePISWc9F4AmCmnnzteKMD3U_U5M_HMiTiwYnEC9vpNRqyS2KPBxvbn8RpmYn4ie6RmHvYGPD-4rDZWowgXc6xLkptJHG7Z-MI11fwsyDEapyvK98UL__35qgjqnAS2RWG/s683/tasklet_githubcode.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="567" data-original-width="683" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMZiXFMpCjpoNePISWc9F4AmCmnnzteKMD3U_U5M_HMiTiwYnEC9vpNRqyS2KPBxvbn8RpmYn4ie6RmHvYGPD-4rDZWowgXc6xLkptJHG7Z-MI11fwsyDEapyvK98UL__35qgjqnAS2RWG/w400-h333/tasklet_githubcode.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.7] tasklet 예제 코드</div><div><br /></div><div><b style="background-color: #ead1dc;"><실행 모습></b></div><div>root@stm32mp1:~/workspace# <b>insmod ./lab_platform_interrupt_tasklet.ko</b></div><div><i> -> 구동 후, User1 button을 누르면 tasklet code(아래 그림 하단의 message 출력)가 정상 동작한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB8G4W0GJYp-w7Zom4Ffq6jgvKVpjIWQNzLSU3UCYF1zW4OJd35iqHaslPNSS4mqF4Kh1or9Shn3iUheA2hoB8w-fb-ToV41jWx2XWuStoEmABJLMyXKwkrHP71Q_GULtIDPjP37KUFsR1/s850/tasklet1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="605" data-original-width="850" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgB8G4W0GJYp-w7Zom4Ffq6jgvKVpjIWQNzLSU3UCYF1zW4OJd35iqHaslPNSS4mqF4Kh1or9Shn3iUheA2hoB8w-fb-ToV41jWx2XWuStoEmABJLMyXKwkrHP71Q_GULtIDPjP37KUFsR1/w400-h285/tasklet1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">[그림 3.8] tasklet 예제 실행 모습</div></div><div><br /></div><div><div><font color="#38761d" size="5"><b>3.3) Workqueue</b></font></div><div><b style="background-color: #cfe2f3;"><개요></b></div><div><b style="background-color: #cfe2f3;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg94CZX_A3hY54i45YXygW9CsSuRmPBjlrYepkcgikYSTX2a7hyphenhyphenv0e9_Mq0PAtXf88-dsxuZ3utBZ9itbTRnTEKCy8_jntcZofgaTpP3xE3WZA67n7jIm_6rJWhK4O-Ij-BBmPMlsM6KL7a/s1102/workqueue2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="744" data-original-width="1102" height="270" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg94CZX_A3hY54i45YXygW9CsSuRmPBjlrYepkcgikYSTX2a7hyphenhyphenv0e9_Mq0PAtXf88-dsxuZ3utBZ9itbTRnTEKCy8_jntcZofgaTpP3xE3WZA67n7jIm_6rJWhK4O-Ij-BBmPMlsM6KL7a/w400-h270/workqueue2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.9] workqueue 개요도</div><div><br /></div><div><b style="background-color: #d9ead3;"><Example code></b></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_workqueue.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_workqueue.c</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcNrvVbYSb-JvQQdTOSZOjYGCyF_I38vP-z956MjtNvcQpGEogebrfaVpEQHyYydvZvIRtgf11iUAlb1MZpELaIsJxrzcb-Uba8K_3hK-qxatgNF407LAzTlpKYvU-NxO3BuGhSY9wnHQg/s827/workqueue_githubcode.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="827" data-original-width="648" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcNrvVbYSb-JvQQdTOSZOjYGCyF_I38vP-z956MjtNvcQpGEogebrfaVpEQHyYydvZvIRtgf11iUAlb1MZpELaIsJxrzcb-Uba8K_3hK-qxatgNF407LAzTlpKYvU-NxO3BuGhSY9wnHQg/w314-h400/workqueue_githubcode.png" width="314" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.10] workqueue 예제 코드</div><div><br /></div><div><b style="background-color: #ead1dc;"><실행 모습></b></div><div>root@stm32mp1:~/workspace# <b>insmod ./lab_platform_interrupt_workqueue.ko</b></div><div><i> -> 구동 후, User1 button을 누르면 workqueue code(아래 그림 하단의 message)가 정상 동작한다.</i></div><div><i><br /></i></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5Tusmg2zQyklWxPo9oi2EujMGJ6uRs5IDy2KY6ps3RBkFds5K-12cf_peL0wY-ibvn8MITQwE0ZViZTuzZ9gkTxWEw7MMi7IBi1wbL0hQx7tARWjliUMWMeEm1_615Vz6Vlqjweci0xSj/s847/workqueue1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="536" data-original-width="847" height="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5Tusmg2zQyklWxPo9oi2EujMGJ6uRs5IDy2KY6ps3RBkFds5K-12cf_peL0wY-ibvn8MITQwE0ZViZTuzZ9gkTxWEw7MMi7IBi1wbL0hQx7tARWjliUMWMeEm1_615Vz6Vlqjweci0xSj/w400-h254/workqueue1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.11] workqueue 예제 실행 모습</div></div></div><div><br /></div><div><b><font color="#38761d" size="5">3.4) Threaded Interrupt</font></b></div></div><div><b style="background-color: #cfe2f3;"><개요></b></div><div><b style="background-color: #cfe2f3;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY_glTxClEM5FajSaLCY758ZkaIJXZjbobfMX0Q-I28JkeLmVqVeH4nQHeckC7saKcXeKNIV3IGr57NwV0VWqh7nmuq-_oLx6U4bqrdUYz4x_UzDRTCJl9nQlNnPlZ7rhLgxoY-qdiaY6i/s1111/threaded_irq3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="781" data-original-width="1111" height="281" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY_glTxClEM5FajSaLCY758ZkaIJXZjbobfMX0Q-I28JkeLmVqVeH4nQHeckC7saKcXeKNIV3IGr57NwV0VWqh7nmuq-_oLx6U4bqrdUYz4x_UzDRTCJl9nQlNnPlZ7rhLgxoY-qdiaY6i/w400-h281/threaded_irq3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.12] threaded interrupt(threaded irq) 개요도</div><div><br /></div><div><b style="background-color: #d9ead3;"><Example code></b></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_threaded_irq.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_threaded_irq.c</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQapfS3TWZ6LJwcMZKL55g8kJ9GDOmIW4fIfeRQnlBDZm_HcDxqd5xSzpvgtPoWNSL2RXabXD0nUrw72ZNZcXvXFaBSJLLI5yRGu5Bw2Yjb9GFPwT9fszy3WicBfrN5306YDwS7dW4b_TR/s599/threaded_irq_githubcode1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="544" data-original-width="599" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQapfS3TWZ6LJwcMZKL55g8kJ9GDOmIW4fIfeRQnlBDZm_HcDxqd5xSzpvgtPoWNSL2RXabXD0nUrw72ZNZcXvXFaBSJLLI5yRGu5Bw2Yjb9GFPwT9fszy3WicBfrN5306YDwS7dW4b_TR/w400-h364/threaded_irq_githubcode1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ9cYVPATNmBbvCIk8hUosGQdOTSZT32zHsTFUVVCZwEFs6CoS74O7MCJQunG8pOnpLn3xGHgE4yLTodHpBOgUm62Ndb1TogjAoiNzjAmQ8xJKCf-u0eUVPFcVP7j-Ynr9QBsPjon37Wc6/s765/threaded_irq_githubcode2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="685" data-original-width="765" height="359" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ9cYVPATNmBbvCIk8hUosGQdOTSZT32zHsTFUVVCZwEFs6CoS74O7MCJQunG8pOnpLn3xGHgE4yLTodHpBOgUm62Ndb1TogjAoiNzjAmQ8xJKCf-u0eUVPFcVP7j-Ynr9QBsPjon37Wc6/w400-h359/threaded_irq_githubcode2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.13] threaded interrupt 예제 코드</div><div><br /></div><div><b style="background-color: #ead1dc;"><실행 모습></b></div><div>root@stm32mp1:~/workspace# <b>insmod ./lab_platform_interrupt_threaded_irq.ko</b></div><div><i> -> 구동 후, User1 button을 누르면 irq thread routine(아래 그림 하단의 message)이 정상 동작한다.</i></div><div><i><br /></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh27VTJcIi9EU4A5U43PUuUnD6XK7ENk9Bz6HvCtFVZ_hNmqrevGM02mM7YnbrQ5YoHgaSMCTfaZy152lAk7X0eIgPriJ8Y_TVyYotkY9FnTxtQ8pZswHcTK8uMcISQSfJiYmUfWwvFfdHg/s825/threaded_irq1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="553" data-original-width="825" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh27VTJcIi9EU4A5U43PUuUnD6XK7ENk9Bz6HvCtFVZ_hNmqrevGM02mM7YnbrQ5YoHgaSMCTfaZy152lAk7X0eIgPriJ8Y_TVyYotkY9FnTxtQ8pZswHcTK8uMcISQSfJiYmUfWwvFfdHg/w400-h268/threaded_irq1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.14] threaded interrupt 예제 실행 모습</div><div><br /></div><div><div><font color="#38761d" size="5"><b>3.5) Kernel Thread</b></font></div></div><div><b style="background-color: #cfe2f3;"><개요></b></div><div><b style="background-color: #cfe2f3;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS-SoqkXe8mn9tiN4BuHj_V0HS-wTrHfG0xH11Qdk44_3PfkrfkjDBzMRP1ssuWjWlfxJlFAS76nUYHRzBQWorpxKmHJVcbUcQmme3_hegGiWfvlLGyFc0ivsX_s93tVN8t263aN96eydm/s1010/kthread2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="751" data-original-width="1010" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjS-SoqkXe8mn9tiN4BuHj_V0HS-wTrHfG0xH11Qdk44_3PfkrfkjDBzMRP1ssuWjWlfxJlFAS76nUYHRzBQWorpxKmHJVcbUcQmme3_hegGiWfvlLGyFc0ivsX_s93tVN8t263aN96eydm/w400-h297/kthread2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.15] kernel thread 개요도</div><div><br /></div><div><b style="background-color: #d9ead3;"><Example code></b></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_thread.c">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/writing_device_drivers_by_coopj/s_20/new/lab_platform_interrupt_thread.c</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglqEobNlf2wVzaYlrzgF2sjbbjMd_icUi5CPziUCQhsqxY_3N4_MsaJspMpYqJl7wrEYSshEtpFmkT18n42Nogly9KISpPnWWKjWm9aScGxBaYhLEYyv22FANxyeRVNOl-loeq8NQo18No/s724/kthread_githubcode1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="724" data-original-width="679" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglqEobNlf2wVzaYlrzgF2sjbbjMd_icUi5CPziUCQhsqxY_3N4_MsaJspMpYqJl7wrEYSshEtpFmkT18n42Nogly9KISpPnWWKjWm9aScGxBaYhLEYyv22FANxyeRVNOl-loeq8NQo18No/w375-h400/kthread_githubcode1.png" width="375" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGUVxQIJqlks0ZgfZGtPvuMi0zru3TVYQUDak-U4c4mh7IgxQN0EVvEN7aW7XhkmOavOJQWCopscTK16IdyXpB4P9uJVPREZIaT_4Z9wyRDcA9zrBSMBFR-Kz3F8ZZNq91Rl7Vs6iObWHQ/s604/kthread_githubcode2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="288" data-original-width="604" height="191" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGUVxQIJqlks0ZgfZGtPvuMi0zru3TVYQUDak-U4c4mh7IgxQN0EVvEN7aW7XhkmOavOJQWCopscTK16IdyXpB4P9uJVPREZIaT_4Z9wyRDcA9zrBSMBFR-Kz3F8ZZNq91Rl7Vs6iObWHQ/w400-h191/kthread_githubcode2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.16] kernel thread 예제 코드</div><div><br /></div><div><b style="background-color: #ead1dc;"><실행 모습></b></div><div><div>root@stm32mp1:~/workspace# <b>insmod ./lab_platform_interrupt_thread.ko</b></div><div><font size="2">[24771.478353] int-button my_button_interrupt: The irq number is 68.</font></div><div><font size="2">[24771.483115] int-button my_button_interrupt: platform_get_irq(): 68</font></div><div><font size="2">[24771.489646] int-button my_button_interrupt: Successfully loading ISR handler.</font></div></div><div><i> -> 구동 후, User1 button을 누르면 thread routine(아래 그림 하단의 message)이 정상 동작한다.</i></div><div><i><br /></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0DlPtZeLt4IApkVnaHWr3Y3FtD2GHIEOoiteX-WICZITFTJLxndW87xPaboV9y_86I7U8t2vNELKJRVoaWx274vVxSlplji0yv8vdRi_0m3oqQ2ObJLwxcS-aeOfbnrvN_auZwFtBd4Fz/s849/kthread1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="516" data-original-width="849" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0DlPtZeLt4IApkVnaHWr3Y3FtD2GHIEOoiteX-WICZITFTJLxndW87xPaboV9y_86I7U8t2vNELKJRVoaWx274vVxSlplji0yv8vdRi_0m3oqQ2ObJLwxcS-aeOfbnrvN_auZwFtBd4Fz/w400-h243/kthread1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.17] kernel thread 예제 실행 모습</div><div><br /></div><div><br /></div><div>이상으로 kernel 4.19.94 환경에서 GPIO interrupt & bottom halves 관련 platform driver & device tree 작성에 관하여 소개해 보았다. 대부분 간단한(?) 수준의 코드(<b><font color="#38761d">하지만, 누군가에게는 꼭 필요한 코드</font></b>)이므로 이해하는데는 크게 무리가 없었을 것으로 믿는다. 😋</div><div><b style="background-color: white; color: #333333; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 14.85px; text-align: center;"><span style="color: #b45f06; font-family: verdana, sans-serif; font-size: large;"><br /></span></b></div><div style="text-align: right;"><b style="background-color: white; color: #333333; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 14.85px; text-align: center;"><span style="color: #b45f06; font-family: verdana, sans-serif; font-size: large;">May the source be with you~</span></b> </div><div style="text-align: right;"><br /></div><div><div><div><span style="text-align: center;"><br /></span></div><div><b><font color="#3367d6" size="6">4. References</font></b></div><div>[1] <a href="https://github.com/ALIBERA/linux_book_2nd_edition/blob/master/Linux_4.19_STM32MP1_practical_labs.pdf">https://github.com/ALIBERA/linux_book_2nd_edition/blob/master/Linux_4.19_STM32MP1_practical_labs.pdf</a></div></div><div>[2] Linux Device Drivers Development, John Madieu, Packt</div><div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAOYbybYyTn_SsXJtrIYx6AMBK9lCas-4UqlDjO55DjUvkLar3BGZQlRJkjzTZUZkekWxn_6FkBaVbtScglPKQNowv6g89_qmQ2QJLTGqzEgpdV-vWJ1l2KTRE7J39bOr9aaaoziuYcTZ4/s250/lddd_book.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="250" data-original-width="202" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAOYbybYyTn_SsXJtrIYx6AMBK9lCas-4UqlDjO55DjUvkLar3BGZQlRJkjzTZUZkekWxn_6FkBaVbtScglPKQNowv6g89_qmQ2QJLTGqzEgpdV-vWJ1l2KTRE7J39bOr9aaaoziuYcTZ4/w162-h200/lddd_book.jpeg" width="162" /></a></div><div class="separator" style="clear: both;"><font color="#990000" size="2">[Tip] 책 내용 중에 몇가지 오류가 있기는 하나, 나름 최신 kernel 내용을 언급하고 있는 (아주) 좋은 책이다. </font><span style="color: #990000; font-size: small;">근데, 왜 Amazon은 Packt(늘 느끼는 거지만 출판 상태가 별로 좋지 못함) 책을 열심히 밀고 있는 걸까 ?</span></div><div><br /></div></div><div style="text-align: center;"><a href="https://github.com/ChunghanYi/linux_kernel_hacks/tree/master/linux_device_drivers_development_by_john_madieu">https://github.com/ChunghanYi/linux_kernel_hacks/tree/master/linux_device_drivers_development_by_john_madieu</a></div><div><br /></div><div>[3] <a href="https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/android_kernel_hacks/Android_Device_Driver_Guide13.pdf">https://github.com/ChunghanYi/linux_kernel_hacks/blob/master/android_kernel_hacks/Android_Device_Driver_Guide13.pdf</a></div><div>[4] <a href="http://www.haifux.org/lectures/323/haifux-devres.pdf"><span style="color: #666666;"><span style="color: black;">The Right Way<span style="font-family: inherit;">: </span></span></span>Managed Resource Allocation in Linux Device Drivers, Eli Billauer</a></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: right;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6KQepzEeCo3bPqSZthfttHhYS3h5xuwcM2dw9TLVIiDKIkuFoaeks7w4VkPi8fJetE6eC6QqsJNKHovaVu79hREa7XLlj6XK0NabK51FLe8bIUQMoVxY11fhDmPm4swimoPoreRCmpXVk/s370/slowboot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="114" data-original-width="370" height="62" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj6KQepzEeCo3bPqSZthfttHhYS3h5xuwcM2dw9TLVIiDKIkuFoaeks7w4VkPi8fJetE6eC6QqsJNKHovaVu79hREa7XLlj6XK0NabK51FLe8bIUQMoVxY11fhDmPm4swimoPoreRCmpXVk/w200-h62/slowboot.png" width="200" /></a></div></div><div class="separator" style="clear: both; text-align: right;"><br /></div><div><br /></div></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-64035264130097057842020-07-01T17:06:00.002+09:002020-07-24T10:21:43.157+09:00ARM Bare-Metal Programming - 1편 이번 blog post에서는 <b><font color="#0b8043">ARM(32bit) 용 bare metal programming(1편)</font></b>에 관한 내용을 소개하고자 한다. Bare metal programming을 위한 target board로는 QEMU(processor emulator/가상 환경)을 활용(<font color="#999999">추후 STM32F103 Nucleo-64 보드를 대상으로 할 예정</font>)하기로 하겠다.<br /><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhimZNQ65qQz5rbrjo2rt3HNBxl18wzrKGgZhLYF5qNBUXx55qY84G-hhjHd-cizUcBhe-qUMlDvE8R0Y5cA3PUSBf4AD7aX39cZmF9N6kJ7dAsrVhrqn4GwnvsS_kl0SsGFYMMqWlz76W9/s521/bare_meta.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="521" data-original-width="520" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhimZNQ65qQz5rbrjo2rt3HNBxl18wzrKGgZhLYF5qNBUXx55qY84G-hhjHd-cizUcBhe-qUMlDvE8R0Y5cA3PUSBf4AD7aX39cZmF9N6kJ7dAsrVhrqn4GwnvsS_kl0SsGFYMMqWlz76W9/w199-h200/bare_meta.png" width="199" /></a></div><div><br /></div><div><b><목차></b></div><div><i><b>1. 개발 환경 준비</b></i></div><div><i><font color="#9e9e9e"> - ARM GCC toolchain 설치</font></i></div><div><i><font color="#9e9e9e"> - QEMU 설치</font></i></div><div><i><font color="#9e9e9e"> - 간단한 예제 돌려 보기</font></i></div><div><b><i>2. Assembly Programming 기초</i></b></div><div><b><i>3. Linker & </i><i>Linker Script</i></b></div><div><i><b>4. 리셋 벡터, Exception Handling 그리고 C code 진입하기</b></i></div><div><i>5. References</i></div><div><br /></div><div><br /></div><div><div style="text-align: center;"><b><font color="#f57c00">"Bringing up an ARM embedded system from scratch"</font></b></div></div><div style="text-align: center;"><b><font color="#f57c00"><br /></font></b></div><div><br /></div><div><div><font color="#3367d6" size="6"><b>1. 개발 환경 준비</b></font></div><div><div>이 장에서는 bare metal programming을 위한 기본 단계로, ARM cross toolchain과 <a href="https://www.qemu.org/">QEMU(processor emulator)</a>를 설치한 후, (맛뵈기 차원에서) 간단한 assembly program를 하나 만들어 돌려 보도록 하겠다.<font color="#999999"> </font><font color="#6aa84f">아래에서 설명하는 모든 작업은 Ubuntu 18.04 desktop에서 실시하였다.</font></div><div><br /></div><div><div>$ <b>sudo apt install gcc-arm-none-eabi</b></div><div><font color="#b51200" size="2">[Tip] ARM용 raw 실행 파일을 만들기 위해서는 arm-none-eabi-gcc가 설치되어야 한다.</font></div><div><br /></div><div>$ <b>arm-none-eabi-gcc --version</b></div><div><font size="2">arm-none-eabi-gcc (15:6.3.1+svn253039-1build1) 6.3.1 20170620</font></div><div><font size="2">Copyright (C) 2016 Free Software Foundation, Inc.</font></div><div><font size="2">This is free software; see the source for copying conditions. There is NO</font></div><div><font size="2">warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</font></div><div><br /></div><div>$ <b>sudo apt install qemu-system-arm</b></div><div><br /></div><div>$ <b>qemu-system-arm --version</b></div><div><font size="2">QEMU emulator version 2.11.1(Debian 1:2.11+dfsg-1ubuntu7.28)</font></div><div><font size="2">Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers</font></div></div></div><div><br /></div><div>$ <b>qemu-system-arm -M ?</b></div><div><i> => qemu가 지원하는 machine의 목록을 출력해 준다. 이 중 적당한 machine을 하나 선택하도록 하자.</i></div><div><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWonwRd_b2uGV9eEPvh0tE3bbpodDg-tnWxA23xD2qWoYEusIBVyyq1x5011ubQgDh2LxiYo2V3xJSGH9GkjYlbgPp_Y8EL6OE_ytme8hwfRK9xe5APQgRzqbJrGJyEmzmILeTErZnAk7H/s715/qemu_M.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="644" data-original-width="715" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWonwRd_b2uGV9eEPvh0tE3bbpodDg-tnWxA23xD2qWoYEusIBVyyq1x5011ubQgDh2LxiYo2V3xJSGH9GkjYlbgPp_Y8EL6OE_ytme8hwfRK9xe5APQgRzqbJrGJyEmzmILeTErZnAk7H/s320/qemu_M.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.1] QEMU에서 지원하는 machine 종류 출력</span></div><div><br /></div><div>다음으로 (아래 site 내용을 참조하여) arm-none-eabi-gdb를 설치해 보자.</div><div style="text-align: center;"><b>https://acassis.wordpress.com/2018/12/27/adding-arm-none-eabi-gdb-to-ubuntu-18-04/</b></div><div style="text-align: center;"><br /></div><div><div>$ <b>sudo dpkg -i ./libreadline6_6.3-8ubuntu2_amd64.deb </b></div><div><font size="2">Selecting previously unselected package libreadline6:amd64.</font></div><div><font size="2">(데이터베이스 읽는중 ...현재 318299개의 파일과 디렉터리가 설치되어 있습니다.)</font></div><div><font size="2">Preparing to unpack .../libreadline6_6.3-8ubuntu2_amd64.deb ...</font></div><div><font size="2">Unpacking libreadline6:amd64 (6.3-8ubuntu2) ...</font></div><div><font size="2">libreadline6:amd64 (6.3-8ubuntu2) 설정하는 중입니다 ...</font></div><div><font size="2">Processing triggers for libc-bin (2.27-3ubuntu1) ...</font></div><div><br /></div><div>$ <b>sudo dpkg -i ./gdb-arm-none-eabi_7.10-1ubuntu3+9_amd64.deb </b></div><div><font size="2">Selecting previously unselected package gdb-arm-none-eabi.</font></div><div><font size="2">(데이터베이스 읽는중 ...현재 318311개의 파일과 디렉터리가 설치되어 있습니다.)</font></div><div><font size="2">Preparing to unpack .../gdb-arm-none-eabi_7.10-1ubuntu3+9_amd64.deb ...</font></div><div><font size="2">Unpacking gdb-arm-none-eabi (7.10-1ubuntu3+9) ...</font></div><div><font size="2">gdb-arm-none-eabi (7.10-1ubuntu3+9) 설정하는 중입니다 ...</font></div><div><font size="2">Processing triggers for man-db (2.8.3-2ubuntu0.1) ...</font></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">[Tip] 위의 방식이 마음에 안들면 <a href="https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads">arm 개발 site</a>에서 보다 최신의 arm toolchain을 내려 받아 설치하는 방법도 있다. 자세한 사항은 필자의 아래 blog <u>2장 a 절</u> 내용을 참조하기 바란다.</font></div><div class="separator" style="clear: both; text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html"><font size="2">https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html</font></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div style="text-align: justify;">Toolchain과 QEMU가 준비되었으니, 간단한 assembly program(덧셈 예제)을 하나 만들어 돌려 보도록 하자.</div><div style="text-align: justify;"><br /></div><div>$ <b>vi add.S</b></div><div><i> => assembly code는 확장자로 .S 혹은 .s를 사용한다.</i></div><div><i> => 아래 코드는 r0 register에 숫자 5를 r1 register에 숫자 4를 대입하고, 둘을 더해 r2 register에 저장한 후, b stop 명령을 계속 실행하면서 무한 loop에 빠지는 program이다.</i></div><div><i> => .text는 assembler directive라고 하며, 이하의 명령이 code section에 포함됨을 알려 준다. 아래 코드에는 없으나 변수 영역(data section)을 표시하는 .data라는 directive도 있다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOW6vVJ9ReiaAt9s3UPUsDcbqfIZImxwDZvo4ZoCrP7OzDPVsSa2sE_4xk4Zu3J7EO0v2AW4lRxY_bDsZXf77ebGz5DrvbtUUhN0AXAv8fOEADH7x_G6FAaWa5Dm3AgCUmYW531TzZjILN/s563/add_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="168" data-original-width="563" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOW6vVJ9ReiaAt9s3UPUsDcbqfIZImxwDZvo4ZoCrP7OzDPVsSa2sE_4xk4Zu3J7EO0v2AW4lRxY_bDsZXf77ebGz5DrvbtUUhN0AXAv8fOEADH7x_G6FAaWa5Dm3AgCUmYW531TzZjILN/w640-h190/add_S.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] add.S 파일</div><div><br /></div><div><span style="background-color: #f7cb4d;"><b><여기서 잠깐 ~></b></span></div><div>assembly code는 보통 "<b><font color="#7b1fa2">label: instruction @ comment</font></b>" 형태로 구성된다.</div><div><br /></div><div><font color="#f57c00"><b>label</b> </font> <i>메모리 상에서의 명령어(instruction)의 위치(번지)를 표시함.</i></div><div><b><font color="#f57c00">instruction</font></b> <i>ARM instruction(32 bit or 16 bit) 이나 assembler directive가 올 수 있다. assembler directive는 assembler에게 알려주는 명령에 해당하며 반드시 .(점)으로 시작한다.</i></div><div><b><font color="#f57c00">@comment </font></b> <i>글자그대로 주석이다.</i></div><div>------</div><div><br /></div><div>$ <b>arm-none-eabi-as -o add.o add.S</b></div><div><i> => assembly code compile(이 경우는 compile 대신 assemble 한다고 함)은 as(assembler)를 이용한다.</i></div><div><i> => 결과 파일은 add.o 임.</i></div><div><br /></div><div>$<b> arm-none-eabi-ld -Ttext=0x0 -o add.elf add.o</b></div><div><i> => 실행 가능한 파일을 생성하기 위해서는 ld(linker)를 사용해야 한다.</i></div><div><i> => -Ttext=0x0 은 label(위의 경우는 start)의 주소를 지정하는 역할을 한다. 즉 start label은 0x0 번지에서 시작한다는 뜻이다.</i></div><div><i> => 위 명령 실행 결과, add.elf라는 실행 파일이 만들어지게 된다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRlvZswZAxqodpyKFQDgdR1ygaJJkEqEsyJDopV59Aq2TjdY_X4as3-8WpHyb56fi0c0l4QzeAicZy-Gq-1HMBYXsyarylsop4tACFGkzw5Y2FcoruBa0HogYA1cKVp13ov_S4N4_U9fqy/s714/add_elf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="226" data-original-width="714" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRlvZswZAxqodpyKFQDgdR1ygaJJkEqEsyJDopV59Aq2TjdY_X4as3-8WpHyb56fi0c0l4QzeAicZy-Gq-1HMBYXsyarylsop4tACFGkzw5Y2FcoruBa0HogYA1cKVp13ov_S4N4_U9fqy/w400-h126/add_elf.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.3] arm-none-eabi-nm add.elf 실행 모습</div><div><font color="#b51200" size="2">[Tip] <a href="https://namu.wiki/w/ELF">ELF(Executable and Linkable Format)</a>는 <span style="background-color: white;">실행, 오브젝트 파일, 공유 라이브러리, 또는 코어 덤프를 할 수 있게 하는 바이너리 파일(UNIX/Linux 실행 파일 format)을 말한다.</span></font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHhMyji5C8JhXNyXY69stpDmuOWymVEjcBo60hXQwcHcPE3Oe1-WAXKIzzJfX0h97ZyP4YfBEGW9L_MRMDsApuH48KN5YEO30OpZ2L2IbXU90n6RT86DPZ5b60RH-M4i5AhCE78uayczi3/s244/220px-Elf-layout--en.svg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="244" data-original-width="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHhMyji5C8JhXNyXY69stpDmuOWymVEjcBo60hXQwcHcPE3Oe1-WAXKIzzJfX0h97ZyP4YfBEGW9L_MRMDsApuH48KN5YEO30OpZ2L2IbXU90n6RT86DPZ5b60RH-M4i5AhCE78uayczi3/" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.4] ELF 파일 형식</div><div>--------</div><div><br /></div><div>$ <b>qemu-system-arm -M realview-pb-a8 -kernel ./add.elf -S -gdb tcp::1234,ipv4</b></div><div><i> => qemu(processor emulator)를 돌려 보자.</i></div><div><i> => machine으로 <font color="#0b8043"><b>realview-pb-a8</b></font>를 선택하자.</i></div><div><i> => -kernel option으로 add.elf를 지정하자.</i></div><div><i> => -S option은 QEMU가 시작하자마자 일시 정지(suspend) 시키는 역할을 한다.</i></div><div><i> => -gdb tcp::1234,ipv4는 외부에서 gdb로 연결(tcp 1234 번 port로 연결)해 올 수 있도록 해준다(내부에 gdbserver가 포함되어 있음)</i></div><div><font color="#b51200" size="2">[Tip] machine type은 다른 것을 선택해도 무방하나, 참고문헌 [2]를 기초로 realview-pb-a8을 일단 선택해 보았다.</font></div><div><font color="#b51200" size="2">[Tip] tcp port 1234는 다른 값으로 지정해도 된다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_dfiSy-m9hQsd32XJAfenUuSl8ck5hrfKuMIJ_gvU8KDIKE2slD_W8B2z3_cUn0h4KwERFd6_Z7r3DRqxJ6dB1Cy-KWgXQrYQ40iqiQNOgaxckVnArq3soq4rVhPWx1g5QsDFIITfEWWb/s989/qemu_gdb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="135" data-original-width="989" height="88" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_dfiSy-m9hQsd32XJAfenUuSl8ck5hrfKuMIJ_gvU8KDIKE2slD_W8B2z3_cUn0h4KwERFd6_Z7r3DRqxJ6dB1Cy-KWgXQrYQ40iqiQNOgaxckVnArq3soq4rVhPWx1g5QsDFIITfEWWb/w640-h88/qemu_gdb.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.5] qemu-system-arm 실행 모습</div><div><br /></div><div>$ <b>arm-none-eabi-gdb</b></div><div><i> => 다른 터미널 창에서 arm 용 gdb를 실행하자.</i></div><div><i><br /></i></div><div style="text-align: center;"><b><font color="#7b1fa2">arm-none-eabi-gdb <=======> gdbserver @ QEMU(add.elf 실행 대기 중)</font></b></div><div><br /></div><div>(gdb) <b><font color="#0b8043">target remote:1234</font></b></div><div> <i>=> 앞서 실행한 qemu 내의 gdbserver와 연결한다.</i></div><div>(gdb) <b><font color="#0b8043">c</font></b></div><div><i> => 코드(add.elf)를 실행한다.</i></div><div><i> => add.elf는 무한 loop에 빠지도록 되어 있으므로 Ctrl-C로 강제 중단하자.</i></div><div>(gdb) <b><font color="#0b8043">info registers</font></b></div><div><i> => 현재 register 정보를 확인해 본다.</i></div><div><i> => r0, r1, r2 register 내용을 보면, 각각 0x5, 0x4, 0x9로 add.S code에서 의도한 대로 내용이 저장되어 있다.</i></div><div>(gdb) <b><font color="#0b8043">x/4x 0</font></b></div><div><i> => 0x00000000 메모리 번지 부터 4개의 item(4byte씩 4개)를 출력한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8q74CFSjCXbUoMpoblULLI2i7Ntps765yd-jmZfPoeHlgZSeNBRthaoMxg4qpztVIYbj_2rtHkrZ0w80PZnUYQpykj_vmyGVedVa1bpqzmHoazuAybaeYLs8a1UXQEqvCgm5FW7tCYjX0/s794/arm_gdb_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="794" data-original-width="705" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8q74CFSjCXbUoMpoblULLI2i7Ntps765yd-jmZfPoeHlgZSeNBRthaoMxg4qpztVIYbj_2rtHkrZ0w80PZnUYQpykj_vmyGVedVa1bpqzmHoazuAybaeYLs8a1UXQEqvCgm5FW7tCYjX0/w568-h640/arm_gdb_run.png" width="568" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.6] qemu-system-arm 실행 모습</div><div><br /></div><div><div>(gdb) <b><font color="#0b8043">x/4iw 0x0</font></b></div><div><i> => i option을 사용하면 memory에 올라와 있는 instruction을 disassemble할 수도 있다.</i></div><div><font color="#f57c00"> 0x0:<span style="white-space: pre;"> </span>mov<span style="white-space: pre;"> </span>r0, #5</font></div><div><font color="#f57c00"> 0x4:<span style="white-space: pre;"> </span>mov<span style="white-space: pre;"> </span>r1, #4</font></div><div><font color="#f57c00"> 0x8:<span style="white-space: pre;"> </span>add<span style="white-space: pre;"> </span>r2, r1, r0</font></div><div><font color="#f57c00">=> 0xc:<span style="white-space: pre;"> </span>b<span style="white-space: pre;"> </span>0xc</font></div></div><div><br /></div><div><br /></div><div>이상으로 간단한 arm toolchain & QEMU 설치 후, assembly program을 하나 작성하고 QEMU 상에서 돌려보는 과정을 소개해 보았다. 이어지는 장에서는 assembly program 작성 방법을 좀 더 깊이있게 소개(2장) 보고, linker와 linker script의 역할(3장)에 대해 소개해 보도록 하겠다.</div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">2. Assembly Programming </font><font color="#9e9e9e" size="6">(정말)</font><font color="#3367d6" size="6"> 기초</font></b></div><div>이번 장에서는 2개의 assembly program 예제를 가지고, Assembly Programming의 가장 기초적인 부분을 짚고 넘어가 보기로 하겠다.</div><div><br /></div><div><b><font color="#0b8043" size="5">a) Array의 합을 계산하는 program</font></b></div><div>코드를 바로 제시하면 다음과 같다. 우측의 주석이 잘 정리되어 있으므로 코드 흐름을 이해하는 것은 그리 어렵지 않다. 아래 program을 실행하고 나면 최종적으로 r3 register에 55가 저장되어야 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEJ7li8JX0LJWwdyu4gA5J3mxbvmrpyXDKw2BpEXVG_5S07vuuSrLsM3CfUvYC82kzjiUyOCFpKaqSxZ8kRG9xwwSyBUm3EF7UZ5aQ6oLF7sVV3kVTCq0aMoTY5_DPmDkoWk0LLin9DxuN/s565/sum_data_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="276" data-original-width="565" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEJ7li8JX0LJWwdyu4gA5J3mxbvmrpyXDKw2BpEXVG_5S07vuuSrLsM3CfUvYC82kzjiUyOCFpKaqSxZ8kRG9xwwSyBUm3EF7UZ5aQ6oLF7sVV3kVTCq0aMoTY5_DPmDkoWk0LLin9DxuN/w400-h195/sum_data_S.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] Array의 합을 계산하는 program - sum-data.S</div><div><br /></div><div>Program build에 앞서 <b>.byte</b>와 <b>.align</b> assembler directive의 의미를 먼저 알아보도록 하자.</div><div><br /></div><div><b style="background-color: #b7e1cd;"><.byte directive></b></div><div>1 byte(8 bits) 크기의 값들을 메모리에 연속으로 배치하고자 할 때 사용한다(byte array로 이해하면 됨). 이와 유사한 표현으로 <b>.2byte</b>, <b>.4byte</b> 등이 있는데, 각각이 의미하는 바는 각각 16 bits, 32bits array로 이해하면 된다. <b>.byte</b> 뒤에 기술하는 argument의 형식으로는 다음과 같은 것들이 올 수 있다.</div><div><br /></div><div><div><i><font color="#f57c00">pattern: .byte 0b01010101, 0b00110011, 0b00001111</font></i></div><div><i><font color="#f57c00">npattern: .byte npattern - pattern</font></i></div><div><i><font color="#f57c00">halpha: .byte 'A', 'B', 'C', 'D', 'E', 'F'</font></i></div><div><i><font color="#f57c00">dummy: .4byte 0xDEADBEEF</font></i></div><div><i><font color="#f57c00">nalpha: .byte 'Z' - 'A' + 1</font></i></div></div><div><br /></div><div><b style="background-color: #b7e1cd;"><.align directive></b></div><div><b>.align</b> directive는 4 bytes(32bits) 단위로 ARM 명령어를 배치하기 위해 사용된다. 이는 instruction만 죽 나열되어 있는 상황에서는 불필요하며, instruction 중간 중간에 data bytes나 half words(16 bites)가 선언되어 있을 경우에만 의미가 있다. 4bytes 단위로 align하기 위해 필요한 경우에 padding bytes가 삽입되게 된다.</div><div><br /></div><div>이제 code를 실행해 보자.</div><div>$ <b>vi sum.ld</b></div><div> <i> => 먼저, 아래와 같이 간단한 linker script(의미는 3장에서 자세히 설명)를 하나 만든다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQTUdE7H9cQMBSjh-xsmVnrGmasumVQyn4nTozcnUOr9bHjHvfbcqHVEESVtusCEiHyiMi7i7VkZDMy2hCSX57ufGPFUupO7xBizlHjKEQbERhSj7I-IihPV0sZl0pWfjOuPV-BBWOQV0u/s272/sum_ld.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="137" data-original-width="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQTUdE7H9cQMBSjh-xsmVnrGmasumVQyn4nTozcnUOr9bHjHvfbcqHVEESVtusCEiHyiMi7i7VkZDMy2hCSX57ufGPFUupO7xBizlHjKEQbERhSj7I-IihPV0sZl0pWfjOuPV-BBWOQV0u/" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.2] 간단한 linker script - sum.ld</div><div><br /></div><div>$ <b>arm-none-eabi-as -o sum-data.o sum-data.S</b></div><div><i> => assemble하여 sum-data.o object 파일을 생성한다.</i></div><div><br /></div><div>$ <b>arm-none-eabi-ld -T sum.ld -o sum-data.axf ./sum-data.o</b></div><div><i> => ld 명령으로 sum-data.axf(ELF/DWARF 파일)을 생성해 낸다.</i></div><div><i> => -T option은 linker script를 지정할 때 사용한다.</i></div><div><br /></div><div>$ <b>qemu-system-arm -M realview-pb-a8 -kernel ./sum-data.axf -S -gdb tcp::1234,ipv4</b></div><div><i> => qemu를 사용하여 실행 파일을 구동시킨다.</i></div><div><br /></div><div>다른 창(terminal)에서 arm-none-eabi-gdb를 실행해 보면 다음과 같다. 반독되는 내용이므로 구체적인 설명은 생략한다. 다만, (info register 명령 실행 결과) r3 register에 55가 저장된 것은 눈여겨 볼 부분이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUlf6Rg1vOyHbIXrO7KzhudF1x9MkMMserp6-Bt7xrvsc8fhXHhXG0I6w75q7ckOVhSMlbhSjaE-91o3kH92eiHvUdL9enlbOk4noDtgcvZo40ZpBTN0fg35CB1arK0GYQ4nEG4ljL-mw/s961/array_sum_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="961" data-original-width="708" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKUlf6Rg1vOyHbIXrO7KzhudF1x9MkMMserp6-Bt7xrvsc8fhXHhXG0I6w75q7ckOVhSMlbhSjaE-91o3kH92eiHvUdL9enlbOk4noDtgcvZo40ZpBTN0fg35CB1arK0GYQ4nEG4ljL-mw/w472-h640/array_sum_run.png" width="472" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.3] <span style="text-align: left;">sum-data.axf에 대해 </span><span style="text-align: left;">arm-none-eabi-gdb 실행 모습</span></div><div><br /></div><div><b><font color="#0b8043" size="5">b) String의 길이를 구하는 program</font></b></div><div>역시 코드를 바로 살펴 보도록 하자. 코드 우측의 주석을 보면 알 수 있듯이 "Hello World" string의 각 byte를 하나씩 체크하면서 nul(= 0)이 나올때까지 반복하는 program이다. 물론 program의 이름에 걸맞게 loop를 돌면서 1씩 값을 증가시키고 이를 r1 register에 저장한다. Program 끝 부분에서 r1 -=1을 하는 이유는 맨 마지막 문자(nul 값)을 제외시켜야 하기 때문이다. 따라서 최종적으로 r1 register의 값이 11이면 정답이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmcXTyK-p9czmDFt8q6TVGo4G_DAlRllNH58lseQgAOF1cDYh9Z-Cgt3PMfDo4ykiS9LQC6pZQwk_1BUDyuS8tigp5nG2m5NmBsbvQkNZV8u4k3ieG3z2cVp1pVMVZZwRV5AssLhoMYHKH/s443/strlne_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="341" data-original-width="443" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmcXTyK-p9czmDFt8q6TVGo4G_DAlRllNH58lseQgAOF1cDYh9Z-Cgt3PMfDo4ykiS9LQC6pZQwk_1BUDyuS8tigp5nG2m5NmBsbvQkNZV8u4k3ieG3z2cVp1pVMVZZwRV5AssLhoMYHKH/w400-h308/strlne_S.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.4] string length를 계산하는 program - strlen.S</span></div><div><br /></div><div>이 program에서는 두가지의 assembler directive 즉, <b>.asciz</b>와 <b>.equ</b>가 눈에 띈다.</div><div><br /></div><div><span style="background-color: #b7e1cd;"><b><.asciz directive></b></span></div><div><b>.asciz</b>는 string literal을 정의하기 위해 사용된다. 이와 비슷한 것으로 <b>.ascii</b>가 있는데, 둘간의 차이는 string 맨 끝에 null charactor(= 0)가 있고 없고이다. 즉, 이름에서 유추할 수 있듯이 .<b>asciz</b>는 string 맨 끝에 0이 추가되고, <b>.ascii</b>는 추가되지 않는다.</div><div><br /></div><div><b style="background-color: #b7e1cd;"><.equ directive></b></div><div>Assembler는 symbol table이라는 것을 관리하는데, <b>.equ</b>는 symbol table에 항목을 추가할 때 사용한다. 즉, 위의 예에서 "<b>.equ nul, 0</b>"이 하는 일은 symbol table에 nul이라는 이름을 추가하고, 그 값이 0이라는 것을 알려준다.</div><div><br /></div><div>그럼, 이제부터 코드를 돌려 보도록 하자. 앞서와 반복되는 내용이니 같은 설명을 반복하지는 않겠다.</div><div>$ <b>arm-none-eabi-as -o strlen.o strlen.S</b></div><div>$ <b>arm-none-eabi-ld -T strlen.ld -o strlen.axf strlen.o</b></div><div>$ <b>qemu-system-arm -M realview-pb-a8 -kernel ./strlen.axf -gdb tcp::5678,ipv4</b></div><div><i> => 이번에는 gdbserver port를 5678로 변경해 보았다.</i></div><div>$ <b>arm-none-eabi-gdb</b></div><div><i> => r1 register 값이 0xb(= 11)로 제대로 들어갔음을 알 수 있다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRDmCVEXmdPDDROOuDkvAAXrGoTbv0_zmvoyeaOcd3VZUCtuF47pVMo2RkLnNYllRLj08-oH5w67BLTR-n2hhFo_aeG_4xaV11xaUlBwK-88l1VlvR7X09KaHKkdC3x0BU6-Aonky40KBZ/s758/strlen_gdb.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="758" data-original-width="699" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRDmCVEXmdPDDROOuDkvAAXrGoTbv0_zmvoyeaOcd3VZUCtuF47pVMo2RkLnNYllRLj08-oH5w67BLTR-n2hhFo_aeG_4xaV11xaUlBwK-88l1VlvR7X09KaHKkdC3x0BU6-Aonky40KBZ/w369-h400/strlen_gdb.png" width="369" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.5] string length를 계산하는 program 실행 모습</span></div><div><br /></div><div>이상으로 2개의 assembly code를 예로 들어, arm assembly programming의 기초 사항을 정리해 보았다. 다음 장에서는 실행 program 생성에 중대한 역할을 하는 linker에 대해 알아 보도록 하자.</div><div><br /></div><div><span style="background-color: #f7cb4d;"><b><여기서 잠깐 !></b></span></div><div><i> => <font color="#b51200">ARM Assembly Programming에 대해 보다 심도있는 내용을 원하는 분은 아래 site를 참조하기 바란다.</font></i></div><div><i><br /></i></div><div style="text-align: center;"><a href="https://azeria-labs.com/writing-arm-assembly-part-1/">https://azeria-labs.com/writing-arm-assembly-part-1/</a></div><div>-------------</div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">3. Linker & Linker Script</font></b></div><div>이번 장에서는 linker와 linker script에 관해서 소개하고자 한다.</div><div><br /></div><div><b><font color="#0b8043" size="5">a) Linker가 하는일</font></b></div><div>먼저 linker는 아래 그림에서와 같이 여러개의 object 파일을 하나로 묶어 실행 가능한 파일(ELF)을 생성하는 역할을 한다. 이 과정에서 <b><font color="#f57c00">symbol resolution(A)</font></b>과 <b><font color="#f57c00">relocation(B)</font></b>이라는 두가지 일이 진행되게 된다.</div><div><font color="#b51200" size="2">[Tip] ld는 <b>l</b>ink e<b>d</b>itor or <b>l</b>oa<b>d</b>er를 의미한다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPGf57v4K-jUBSX5eFQpZ3uIAhGJUU8vLNhUlueyfclM-GuDRBP6Pgk_WY_tG7mpcqaoUR7bzJeXTS738RbW7ZV2J6qYp4PJW-hHhKz6poPAenGuiZ7PLY_A9E1qrUQLuG5IFF0DRZsu0j/s549/linker_role.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="174" data-original-width="549" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPGf57v4K-jUBSX5eFQpZ3uIAhGJUU8vLNhUlueyfclM-GuDRBP6Pgk_WY_tG7mpcqaoUR7bzJeXTS738RbW7ZV2J6qYp4PJW-hHhKz6poPAenGuiZ7PLY_A9E1qrUQLuG5IFF0DRZsu0j/w400-h126/linker_role.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.1] linker의 역할</span></div><div><br /></div><div>Linker의 역할을 구체적으로 설명하기 위해 main.S와 sub.S로 구성된 예를 하나 들어 보자. 이 두개의 program이 하는 일은 아주 간단하다. 즉, main.S에 정의되어 있는 byte array(10, 20, 25)의 값을 더해서 그 결과를 r3 register에 저장하는 것이다. 단, 더하는 routine은 main.S가 아니라 sub.S에 정의되어 있어, main.S에서 sub.S의 (일종의)함수를 호출하는 코드라고 볼 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjioXe8XR3Pwu-egwyuGyIO_xnTjxItoPke_HgDcJaLkvCca5iL6CzE9H4WYXnDXr3HUC0ckF0Mgxk5-5egGuZRkiU3ODx-m4hX_lYp6dtCuV0cy9f1_r1GmmFqUEJZ4D0tyg2SCGn0pxfQ/s568/main_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="245" data-original-width="568" height="173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjioXe8XR3Pwu-egwyuGyIO_xnTjxItoPke_HgDcJaLkvCca5iL6CzE9H4WYXnDXr3HUC0ckF0Mgxk5-5egGuZRkiU3ODx-m4hX_lYp6dtCuV0cy9f1_r1GmmFqUEJZ4D0tyg2SCGn0pxfQ/w400-h173/main_S.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] main.S 코드</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiELeylaHBD5snoMZHGWQyrYOp2fwKW7sWc2DRK2Ok1DhQjSudqUo7GSKJWie6rg0ew1ab3fNFMvz6xUVzt-5U4PPNrSvuwRsuBpzMXuQZr5cEnRbPNzkIQrxPbi4pkqF7QEGPJ8FwLZN_3/s685/sub_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="283" data-original-width="685" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiELeylaHBD5snoMZHGWQyrYOp2fwKW7sWc2DRK2Ok1DhQjSudqUo7GSKJWie6rg0ew1ab3fNFMvz6xUVzt-5U4PPNrSvuwRsuBpzMXuQZr5cEnRbPNzkIQrxPbi4pkqF7QEGPJ8FwLZN_3/w400-h165/sub_S.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] sub.S 코드</div><div><br /></div><div><span style="background-color: #b7e1cd;"><b><.global directive></b></span></div><div>Assembly 언어에서 label은 모두 외부에서 사용 불가하도록 되어있다(<font color="#9e9e9e">C 언어로 생각해 본다면 static 함수 선언로 선언된 경우는 외부에서 호출 불가하다는 내용과 유사하다고 볼 수 있음</font>). 따라서 이를 외부에서 사용 가능하게 하려면 해당 label을 .global로 선언해 주어야 한다. 위의 예에서는 "<b>.global sum</b>" 이라고 선언되어 있으므로, main.S에서 해당 label을 사용(호출)할 수 있는 것이다.</div><div><br /></div><div>이 상태에서 두개의 파일을 build(assemble)한 후, nm 명령으로 symbol table의 상태를 확인해 보도록 하자.</div><div><br /></div><div>$ <b>arm-none-eabi-as -o main.o main.S</b></div><div>$ <b>arm-none-eabi-as -o sub.o sub.S</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLO1eeSWk6mvXK5uHDR-VyMacbhFtZO2MqJ7qDIB7fR3vNwCfWUFGmb0-K6JIUjEGT1bx7_4J7H3teWVWGkBxtCZKlD1gYDj360pwBM7y0NYVe1eLkachkXHiT5Uw9nkjcNUWdtTXBGBM6/s724/nm_main_sub.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="166" data-original-width="724" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLO1eeSWk6mvXK5uHDR-VyMacbhFtZO2MqJ7qDIB7fR3vNwCfWUFGmb0-K6JIUjEGT1bx7_4J7H3teWVWGkBxtCZKlD1gYDj360pwBM7y0NYVe1eLkachkXHiT5Uw9nkjcNUWdtTXBGBM6/w640-h146/nm_main_sub.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.4] nm 명령으로 main.o와 sub.o의 symbol table 확인</div><div><br /></div><div>위의 nm 명령 결과 중, <b>t</b>는 symbol이 정의되어 있음을 뜻하고, <b>u</b>는 정의되어 있지 않음을 뜻한다. 또한 <b>T</b>나 <b>U</b> 처럼 대문자로 표기된 경우는 해당 symbol이 .global로 선언되어 있을 때이다. 내용을 보니 main.o에서 sum label은 역시나 <b>U</b>로 표기되어 있다.</div><div><br /></div><div>그렇다면, 위의 두 파일을 linker로 연결해 보면 어떻게 될까 ?</div><div>$ <b>arm-none-eabi-ld -Ttext=0x0 -o sum.axf main.o sub.o</b></div><div><br /></div><div>$ <b>arm-none-eabi-nm sum.axf</b></div><div> <i> => 얘상대로 sum 앞에 <b>T</b>가 보인다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVIq4a9BnIBDPmpyli90wtEVXDoHI0L4aK2cTUVwQpB_XDO47p_bc5Lun0ki6p4YBAvivPK8I4QuNzQvQBBhyjUz5SepgVYyuoxsi9PIOo3AznOV4PECGAJoMT6dDpVdgyDqBOGK6uMBlG/s718/nm_sum_axf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="297" data-original-width="718" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVIq4a9BnIBDPmpyli90wtEVXDoHI0L4aK2cTUVwQpB_XDO47p_bc5Lun0ki6p4YBAvivPK8I4QuNzQvQBBhyjUz5SepgVYyuoxsi9PIOo3AznOV4PECGAJoMT6dDpVdgyDqBOGK6uMBlG/w640-h264/nm_sum_axf.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.5] nm 명령으로 sum.axf의 symbol table 확인</div><div><br /></div><div>지금까지 설명한 과정을 <b><font color="#f57c00">symbol resolution(A)</font></b>이라고 한다.</div><div><br /></div><div>그렇다면 <b><font color="#f57c00">relocation(B)</font></b>이란 무엇일까 ?</div><div>아래와 같이 -Ttext option을 주어 text section의 시작을 0x0 => 0x100으로 변경한 상태에서 linking을 해보면, 아래와 같이 모든 symbol의 주소(예: 00000120 T sum)가 그에 맞게 조절됨을 알 수 있는데, 이것이 relocation이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqD-j8G6Lv0PfALjHyR4flKD49r1RpPrOTH2OZE_KSNWB68CKQYPEgIX4ss8IzF1-jpVUy4IX7CYAVZQEAsWKDirt-C1mh30Wmk3_tNAfyEOIWKI4AfJ_D6Zcgoq3u94h1_IHDoPfBl9do/s970/nm_sum_axf_relocation.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="326" data-original-width="970" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqD-j8G6Lv0PfALjHyR4flKD49r1RpPrOTH2OZE_KSNWB68CKQYPEgIX4ss8IzF1-jpVUy4IX7CYAVZQEAsWKDirt-C1mh30Wmk3_tNAfyEOIWKI4AfJ_D6Zcgoq3u94h1_IHDoPfBl9do/w640-h216/nm_sum_axf_relocation.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.6] nm 명령으로 sum.axf의 symbol table 확인</div><div><font color="#b51200" size="2">[Tip] 내용이 너무 장황해 질 듯하여, 아주 간단하게 설명하였으나, relocation을 위해서는 section merging(서로 다른 파일에 흩어져 있는 동일 section을 하나로 통합)과 section placement(앞서 설명한 시작 주소 변경에 따른 위치 조정)라는 과정이 동반된다.</font></div><div><br /></div><div><b><font color="#0b8043" size="5">b) Linker script</font></b></div><div>앞서 언급한 대로 linker는 section merging과 section placement 절차를 수행한다. 이때 어는 section이 merge(통합)되고, 어느 위치가 메모리에 재배치되는지에 관해서는 linker script라는 파일을 통해 세세히 기술해 줄 수가 있다. 즉, linker는 linker script의 내용을 토대로 section merging & placement 과정을 진행하게 된다.</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXG4DJ8Zva9SbF2TtIbPomRqAxc90rhJjSqWUu8axe934L8rpSza_JuJ8wtmUUWKvN5VD7svtaoiMuJI-SIYhyphenhyphenlOV293qGPQKBAixxurLKrILZrDsUAwwYybV4MFdNsjUAOM9KpqRKSpo6/s292/sample_ld.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="134" data-original-width="292" height="147" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXG4DJ8Zva9SbF2TtIbPomRqAxc90rhJjSqWUu8axe934L8rpSza_JuJ8wtmUUWKvN5VD7svtaoiMuJI-SIYhyphenhyphenlOV293qGPQKBAixxurLKrILZrDsUAwwYybV4MFdNsjUAOM9KpqRKSpo6/w320-h147/sample_ld.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.7] linker script 구조 설명(1)</div><div><br /></div><div>❶ SECTIONS 명령은 section이 어떻게 merge되고 어느 위치에 배치되는지를 기술한다.</div><div>❷ . = 0x00000000 은 location counter를 의미하며 첫번째 section(여기서는 text section)이 메모리 주소 0x00000000에 위치한다는 것을 알려 준다.</div><div>❸ ❹ 입력 파일인 abc.o와 def.o에 있는 text section은 output file의 text section으로 들어감을 의미한다.</div><div><br /></div><div>위의 linker script는 아래와 같이 *를 사용하여 단순화해서 표현할 수도 있다(보통 이렇게 많이 쓴다).</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhj5l-QqG0UnS-AyYpVZHu7wQgH3rjd83acMofdJD8lWvnlhlboTSo_rV-VqZC0azzY-2_40LeAyzZy18G2EsX0mdMNyvyPFpNr-mYdhhyphenhypheny9gq6IT2aDCJo8DXRYsbOFLp1laXGvHZjUVxg/s301/sample1_ld.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="89" data-original-width="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhj5l-QqG0UnS-AyYpVZHu7wQgH3rjd83acMofdJD8lWvnlhlboTSo_rV-VqZC0azzY-2_40LeAyzZy18G2EsX0mdMNyvyPFpNr-mYdhhyphenhypheny9gq6IT2aDCJo8DXRYsbOFLp1laXGvHZjUVxg/" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">[그림 3.8] linker script 구조 설명(2)</div><div><br style="text-align: left;" /></div><div style="text-align: left;">아래 예는 .text section과 .data section을 모두 포함한 경우의 linker script 예제이다. .text section은 종전과 같이 0x0에 위치하고 있지만, .data section은 0x400 부터 배치됨을 보여준다.</div><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYiq4ET44OMLg0KBrlzKzVXT4xLWIYs0sVoKbxLNouKyjNhF1e_8hN5WVoKcVuHOpQsrSTz-RHHiGWPiEXCl9nuHAW8oKlztD0UnMayC9D2qoWEoznXYLX33qjPcfZLdCAdgVk52DWzT7p/s289/sample2_ld.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="136" data-original-width="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYiq4ET44OMLg0KBrlzKzVXT4xLWIYs0sVoKbxLNouKyjNhF1e_8hN5WVoKcVuHOpQsrSTz-RHHiGWPiEXCl9nuHAW8oKlztD0UnMayC9D2qoWEoznXYLX33qjPcfZLdCAdgVk52DWzT7p/" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.9] linker script 구조 설명(3)</div><div><br /></div><div>위의 linker script를 사용하는 예제 program 하나 테스트해 보자. 앞서 [그림 2.1]과 동일한 예제코드이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUXTlEQ4PhBio6wOlxRZujai9wEp0ZvJxDrXRVdgmTqdj_h5l-ABP4W3PuHxWUIeKyMeYsA3Us0qY_RBOG7jEX7inGDZhmcOlZ92pgvHQJ_-hNC300a8evnQVid1rPM6jIZ1e1pOtBsOb-/s564/sample2_S.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="267" data-original-width="564" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUXTlEQ4PhBio6wOlxRZujai9wEp0ZvJxDrXRVdgmTqdj_h5l-ABP4W3PuHxWUIeKyMeYsA3Us0qY_RBOG7jEX7inGDZhmcOlZ92pgvHQJ_-hNC300a8evnQVid1rPM6jIZ1e1pOtBsOb-/w400-h189/sample2_S.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.10] Array의 합을 계산하는 program - sample2.S</div><div><br /></div><div>$ <b>arm-none-eabi-as -o sample2.o sample2.S</b></div><div>$ <b>arm-none-eabi-ld -T sample2.ld -o sample2.axf sample2.o</b></div><div><br /></div><div>nm 명령으로 symbol table 내용을 확인해 보면, text section과 data section의 memory 주소가 linker script에 지정한 값대로 출력됨을 알 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7KtdG0I3FoUBw1dUfAsRBRJKNydU4qUvbLrmTdo1fyvh0Bn0u_FvNi2Q9AsP7SzGzynSTqxVj5sdPyK0CkhyjY0gkaUGLtHjrav1qLRXr_aNedW0Wdteeq-bHpoHAI-M9zYge8ZJf6i9i/s791/nm_sample2_axf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="118" data-original-width="791" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7KtdG0I3FoUBw1dUfAsRBRJKNydU4qUvbLrmTdo1fyvh0Bn0u_FvNi2Q9AsP7SzGzynSTqxVj5sdPyK0CkhyjY0gkaUGLtHjrav1qLRXr_aNedW0Wdteeq-bHpoHAI-M9zYge8ZJf6i9i/w640-h96/nm_sample2_axf.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.11] arm-none-eabi-nm -n ./sample2.axf 실행 결과</div><div><br /></div><div>이상으로 linker와 linker script의 역할에 대해 간략히 살펴 보았다. 다음 장에서는 지금까지 설명한 내용을 기초로 본격적인 bare metal programming에 관한 설명에 돌입하고자 한다.</div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">4. 리셋 벡터, Exception Handling 그리고 C Code 진입하기</font></b></div><div>지금까지 1 ~ 3장을 통해 bare metal programming을 위한 준비 사항을 정리해 보았다. 그렇다면 이제 부터는 본격적인 bare metal programming에 들어가 보도록 하자. 이절에서 소개하는 내용은 <a href="https://github.com/navilera/Navilos">아래 책</a>을 기초로 하였음을 밝힌다. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Y8n7Rc2wSCYeguCG3EEENtlsUxJTr8olOqt_mniMrTtE4ManGWLbn1Nhh0NkyM-ymBIqbIunrxGFC2tx0QnAcK24ouyuASXl-Kz6dhg1VT1YKGu9ncqGCqottZYbB9NZ_gr5SkXOuB9q/s252/maanu.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="252" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_Y8n7Rc2wSCYeguCG3EEENtlsUxJTr8olOqt_mniMrTtE4ManGWLbn1Nhh0NkyM-ymBIqbIunrxGFC2tx0QnAcK24ouyuASXl-Kz6dhg1VT1YKGu9ncqGCqottZYbB9NZ_gr5SkXOuB9q/s0/maanu.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.1] 임베디드 OS 개발 프로젝트 책(인사이트 이만우 저)</div><div><br /></div><div><b><font color="#38761d" size="5">a) Reset vector와 Exception vector</font></b></div><div>ARM core에 전원이 인가되면 ARM core가 가장 먼저 하는 일은 Reset vector(0x00000000 번지)를 실행하는 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq0xHzoG3Fs4VzV1e3WgLfYe6yeeI7wTl5_ud1BKWVbNAcVM4-RsLaEtNXYaAqJ50J4Kyxxn01HSKPallN9G6ie7wwMzPmZaGGnUxIKHjYzcjQ7q_5KVL3MBWitJvJtp3tYcEbPSyx7PRE/s994/armv7_processor_mode.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="490" data-original-width="994" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq0xHzoG3Fs4VzV1e3WgLfYe6yeeI7wTl5_ud1BKWVbNAcVM4-RsLaEtNXYaAqJ50J4Kyxxn01HSKPallN9G6ie7wwMzPmZaGGnUxIKHjYzcjQ7q_5KVL3MBWitJvJtp3tYcEbPSyx7PRE/w640-h317/armv7_processor_mode.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.2] ARMv7 Processor Mode <b>[참고문헌 5]</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvpA3BA5We0L2x5Rktx0vWyhRAx7hkt5s5jy9CH0mopF4rAbaECNPDXLDK3Rg8uwj1y_5GfdqCtmVofc2pws0TRwMPfry5pTmE-HUaWvwoBWPEHTPwipUjjUJqePgg9s3Ss_DjlvniyYMK/s603/arm_register_set3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="603" data-original-width="582" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvpA3BA5We0L2x5Rktx0vWyhRAx7hkt5s5jy9CH0mopF4rAbaECNPDXLDK3Rg8uwj1y_5GfdqCtmVofc2pws0TRwMPfry5pTmE-HUaWvwoBWPEHTPwipUjjUJqePgg9s3Ss_DjlvniyYMK/w386-h400/arm_register_set3.png" width="386" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELqY9kJQ_OXNwTPqYmZOtqJvevpz3dVJNVMGxjUODVvpGbWlf-HNYmE59JNxumNHisshPNdQ1jIKiHtc9rGlewCDTdeXQlmEgKES2Xz15eD_9zclZVTp9u6WIlm4Lf_9ebd8qtTkrFmXs/s884/arm_register_set2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="701" data-original-width="884" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhELqY9kJQ_OXNwTPqYmZOtqJvevpz3dVJNVMGxjUODVvpGbWlf-HNYmE59JNxumNHisshPNdQ1jIKiHtc9rGlewCDTdeXQlmEgKES2Xz15eD_9zclZVTp9u6WIlm4Lf_9ebd8qtTkrFmXs/w400-h318/arm_register_set2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.3] ARM Register Sets <b>[참고문헌 5]</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRcJuMAIDLfazdkue6pR6YrKIN-jr11uae2t1ypSOZgAMzElF8qcnXr8pbRGKCdRXxtrDRix6WZ9qHIDtGYf_uS-MEYRmBHEQr_KmI8XK3fpM6nXedAGGPzn_hUL74laMli_C3RBB0Ql1m/s868/arm_cpsr_register.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="106" data-original-width="868" height="78" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRcJuMAIDLfazdkue6pR6YrKIN-jr11uae2t1ypSOZgAMzElF8qcnXr8pbRGKCdRXxtrDRix6WZ9qHIDtGYf_uS-MEYRmBHEQr_KmI8XK3fpM6nXedAGGPzn_hUL74laMli_C3RBB0Ql1m/w640-h78/arm_cpsr_register.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.4] ARM Current Program Status Register <b>[참고문헌 5]</b></div><div><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4XlpakheazN9JL03hRW1P3W2R-CHVH4Q5WMgSI5858YEL_LhyphenhyphenhAewOg6PY8EURzBea_LnEQ8zp3KZG0wk_frwPQMnZ8nAtbrLaV48rL3kIQ8EMbwU6iYxtOEHfBIlaUs-9Ai-rT0i8zlB/s896/arm_exception_behavior1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="347" data-original-width="896" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4XlpakheazN9JL03hRW1P3W2R-CHVH4Q5WMgSI5858YEL_LhyphenhyphenhAewOg6PY8EURzBea_LnEQ8zp3KZG0wk_frwPQMnZ8nAtbrLaV48rL3kIQ8EMbwU6iYxtOEHfBIlaUs-9Ai-rT0i8zlB/w640-h248/arm_exception_behavior1.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_0SQFU2YDpsMVGCOiV3XrFwQmyS605r-p1n42zqHSv3LVfIcPT-YzvrEEOJSSudUd5MIadZCzh3pxmN7ky281KNoT_BqFWodj0awmeoa4-lB0m2D6svOCgG-TMyJ_MNDRSloZ1M_6CwE4/s894/arm_exception_behavior3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="189" data-original-width="894" height="136" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_0SQFU2YDpsMVGCOiV3XrFwQmyS605r-p1n42zqHSv3LVfIcPT-YzvrEEOJSSudUd5MIadZCzh3pxmN7ky281KNoT_BqFWodj0awmeoa4-lB0m2D6svOCgG-TMyJ_MNDRSloZ1M_6CwE4/w640-h136/arm_exception_behavior3.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.5] ARM Vector Table <b>[참고문헌 5]</b></div><div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8OFA0WB_67XUWKTgz8WM0caDuCrJYZdyQY3mFGVFndOTmgMrOhZASGhCgfMVEZY9i5KFNB9OHlBW6cC7aAs4EvGq8zSwGzyDeUAF9WFE_rogKQ0aVDcwMeVCfogkQYrhmw4aNiJLxym2_/s533/arm_exception_handling.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="254" data-original-width="533" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8OFA0WB_67XUWKTgz8WM0caDuCrJYZdyQY3mFGVFndOTmgMrOhZASGhCgfMVEZY9i5KFNB9OHlBW6cC7aAs4EvGq8zSwGzyDeUAF9WFE_rogKQ0aVDcwMeVCfogkQYrhmw4aNiJLxym2_/w400-h190/arm_exception_handling.png" width="400" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 4.6] ARM Exception Handing <b>[참고문헌 4]</b></div><div class="separator" style="clear: both; text-align: center;"><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFmZF6yrILkuFVusDmX9HSHOpz41Oiic2_JR_1xj0wHp9djBz80vlI9ZB8HiD7PxDNQlqDMa4fIMdbV0_e8QMNoHT_V6xOrBNlu8uKVUZhEGvuTMc7sUnzCHsAA1SF93TlUsQs8IqDCy-V/s455/arm_memory_layout.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="303" data-original-width="455" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFmZF6yrILkuFVusDmX9HSHOpz41Oiic2_JR_1xj0wHp9djBz80vlI9ZB8HiD7PxDNQlqDMa4fIMdbV0_e8QMNoHT_V6xOrBNlu8uKVUZhEGvuTMc7sUnzCHsAA1SF93TlUsQs8IqDCy-V/s320/arm_memory_layout.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.7] ARM Memory Layout <b>[참고문헌 4]</b></div></div><div><br /></div><div><br /></div><div><b><font color="#38761d" size="5">b) 메모리 map 구성 및 스택 만들고, C main 함수 호출하기</font></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2C1x5TPCX4y3hcwbM_xjpyXv4PPJ7F_LNcwyAzLXNTrC1RfH1SsHN5NPKhEkWgGkDN0EI2Vmf9JbVroVoxn_u-3hf95acXmNgiz9uCflM2U9vr6rbtIMh88VYT-TTncZ29L5oP_NAs1Q_/s500/navilos_boot1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="500" data-original-width="485" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2C1x5TPCX4y3hcwbM_xjpyXv4PPJ7F_LNcwyAzLXNTrC1RfH1SsHN5NPKhEkWgGkDN0EI2Vmf9JbVroVoxn_u-3hf95acXmNgiz9uCflM2U9vr6rbtIMh88VYT-TTncZ29L5oP_NAs1Q_/w388-h400/navilos_boot1.png" width="388" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHlx5mmdVGtCu1yAlMgJt21UiZl77GxJ9Yf8tWKKrHnCpFD4R2ylwfdDicNPdH8WPMk8JWD5gzPy776FMb6MVPxdixLGTj0mdKhWMPwAbtabqxMFpKWBSXI17IHsC0zCnRmf6zLFChcN4E/s777/navilos_boot2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="777" data-original-width="523" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHlx5mmdVGtCu1yAlMgJt21UiZl77GxJ9Yf8tWKKrHnCpFD4R2ylwfdDicNPdH8WPMk8JWD5gzPy776FMb6MVPxdixLGTj0mdKhWMPwAbtabqxMFpKWBSXI17IHsC0zCnRmf6zLFChcN4E/w430-h640/navilos_boot2.png" width="430" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.8] Entry.S 파일 - reset handler 수행 후, C main( ) 함수 호출</div><div> </div><div><br /></div><div><b><font color="#b45f06">이번 장은 (시간이 없어) 정리를 하다가 중간에 중단을 하였다. </font></b>보다 상세한 사항은 참고 문헌 [2]를 참조해 주시기 바라며, 추후 다시 정리할 수 있는 기회가 있기를 희망해 본다. 😓</div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">5. References</font></b></div></div><div>[1] http://www.bravegnu.org/gnu-eprog/index.html</div><div><i> => 1~ 3장의 기초 자료로 사용함.</i></div><div><br /></div><div>[2] 임베디드 OS 개발 프로젝트, 이만우, 인사이트</div><div><i> => 4장의 기초 자료로 사용함.</i></div><div><i> => RTOS의 동작 원리 파악에 도움이 되는 Good book</i></div><div><br /></div><div>[3] Embedded programming with Android: Bringing Up and Android System from Scratch, Roger YE, Addison-Wesley</div><div><br /></div><div>[4] ARM System Developer’s Guide - Designing and Optimizing System Software, Andrew N. Sloss, Dominic Symes, Chris Wright, Morgan Kaufmann Publishers</div><div><i> => ARM architecture 소개(too old)</i></div><div><br /></div><div>[5] <a href="https://www.macs.hw.ac.uk/~hwloidl/Courses/F28HS/Docu/DEN0013D_cortex_a_series_PG.pdf">ARM Cortex-A Series Programmer's Guide, ARM</a></div><div><div><i> => ARMv7 architecture 소개</i></div><div><br /></div></div><div>[6] <a href="https://azeria-labs.com/writing-arm-assembly-part-1/">https://azeria-labs.com/writing-arm-assembly-part-1/</a></div><div><i> => ARM Assembly Programming 상세 소개</i></div><div><br /></div><div>[7]<a href="https://learningfromyoublog.wordpress.com/2017/07/27/debugging-linux-kernel-using-qemu/">https://learningfromyoublog.wordpress.com/2017/07/27/debugging-linux-kernel-using-qemu/</a></div><div><br /></div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-23048595686587287742020-06-29T16:23:00.013+09:002022-01-30T15:42:12.357+09:00Pi Camera sensor 그리고 Camera Device Driver에 관하여...이번 blog post에서는 (머리도 식힐겸 ??) <b>Raspberry Pi Camera</b>와 이를 위한 <b>linux camera device driver(w/ device tree)</b>에 관한 이야기를 게재해 볼까 한다.<div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd6USTFYxjr93egR8x9JZRCZ6uYV0b3igH7h1jbMjz9BTxVDqJw2CKnm4tpKGNVkeH4LWuuT7T_fNqMn3sl0Lr92aBLtIMEGhaBhVIGvZVQe3jBoMmzy88wIp1ULVXqrxFqgQUvTdaDkFE/s235/rpi3_picamera.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="215" data-original-width="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd6USTFYxjr93egR8x9JZRCZ6uYV0b3igH7h1jbMjz9BTxVDqJw2CKnm4tpKGNVkeH4LWuuT7T_fNqMn3sl0Lr92aBLtIMEGhaBhVIGvZVQe3jBoMmzy88wIp1ULVXqrxFqgQUvTdaDkFE/" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b>목차</b></div><div><i><b>1. Raspberry Pi 3 B and Pi Camera</b></i></div><div><i> - <font color="#9e9e9e">motion, mjpg-streamer 시험</font></i></div><div><b><i>2. Pi Camera와 </i><i>MIPI CSI-2의 이해</i></b></div><div><div><i><b>3. Pi Camera S/W Architecture</b></i></div><div><i><font color="#9e9e9e"> - V4L2 framework</font></i></div><div><i><font color="#9e9e9e"> - VideoCore IV & MMAL Interface</font></i></div><div><i><font color="#9e9e9e"> - Camera device tree & device driver</font></i></div></div><div><b><i><span style="color: #b45f06;">4. Raspberry Pi 4 and Pi Camera [나중에 정리한 것임]</span></i></b></div><div><i><b>5. References</b></i></div><div><br /></div><div><br /></div><div><font color="#9e9e9e" size="2">Raspberry Pi는 최초 등장 이후로 전세계적으로 많은 인기를 누리고 있다. 최근에는 Quad core ARM Cortex-A72(ARM v8) 64-bit SoC(Broadcom BCM2711)를 탑재한 Pi 4가 출시되기도 했는데, 본 blog post에서는 아쉽게도 Pi 4가 아니라 (전에 구매해 둔) Raspberry Pi 3 B를 대상으로 글을 기고해 보고자 한다.</font></div><div><br /></div><div><b style="color: #3367d6; font-size: xx-large;">1. Raspberry Pi 3 B and Pi Camera</b></div><div><div>먼저 1장에서는 Raspberry Pi 3 B(이하 RPI3로 칭하겠음)에 Pi Camera 장착 및 Pi OS를 설치하고, <b><font color="#ba67c8">motion, mjpg-streamer</font></b> 등의 application으로 camera가 capture한 영상을 화면에 출력하는 과정을 소개해 보도록 하겠다.</div><div><br /></div><div><font color="#0b8043" size="5"><b>a) Raspberry Pi 3 B 설치</b></font></div><div>Raspberry Pi OS 설치와 관련해서는 인터넷에서 관련 글을 쉽게 찾을 수 있기 때문에 본 blog post에서는 이와 관련한 자세한 내용은 설명하지 않도록 한다.</div><div style="text-align: center;"><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSNwwYR5teHg2yVbEK0flxtlebKSm3KT1Zg7tBTj5pkLseZXVSHeqqXiStG1L8cMn6JuCpAB81pjMrV8H2qdMP5XZGyd7ZlUhSwKL-SpnkdAQUjM2luayzagyLlriLpnV7_vdg-b-kSlUp/s800/rpios_etcher.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="410" data-original-width="800" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSNwwYR5teHg2yVbEK0flxtlebKSm3KT1Zg7tBTj5pkLseZXVSHeqqXiStG1L8cMn6JuCpAB81pjMrV8H2qdMP5XZGyd7ZlUhSwKL-SpnkdAQUjM2luayzagyLlriLpnV7_vdg-b-kSlUp/s320/rpios_etcher.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.1] RPi OS(2020-05-27-raspios-buster-armhf.img) 설치 - Ether 사용</div><div><br /></div><div><span style="color: #b45f06;">최근(2022년 1월 현재) RPi OS에도 많은 변화가 있는 듯 하다. 오랜만에 Pi camera를 구동할 일이 있어 최신 버젼을 내려 받아 설치 후, motion & mjpg-streamer를 돌려 보려고 했더니, 동작하지 않는다. 이를 해결하는 방법은 다양하게 존재하겠으나, </span><span style="color: #b45f06;">여기서는 raspbian stretch version을 이용하는 방법을 소개하고자 한다.</span></div><div><br /></div><div style="text-align: justify;"><span style="text-align: center;"><a href="http://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/">http://downloads.raspberrypi.org/raspbian/images/raspbian-2019-04-09/</a></span></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;"><br /></span></div><div style="text-align: left;">위의 그림 처럼 Etcher를 이용해서 image writing을 할 수도 있겠으나, dd를 사용하는 방법도 생각해 볼 수 있다.</div><div><span style="text-align: center;"><b><Ubuntu desktop></b></span></div><div><span style="text-align: center;"><div style="text-align: left;">$ <b>sudo dd if=./2019-04-08-raspbian-stretch.img of=/dev/sdc bs=4M conv=fsync status=progress</b></div><div style="text-align: left;"><span style="color: #666666; font-size: x-small;">3472883712 bytes (3.5 GB, 3.2 GiB) copied, 130 s, 26.7 MB/s</span></div><div style="text-align: left;"><span style="color: #666666; font-size: x-small;">830+0 레코드 들어옴</span></div><div style="text-align: left;"><span style="color: #666666; font-size: x-small;">830+0 레코드 나감</span></div><div style="text-align: left;"><span style="color: #666666; font-size: x-small;">3481272320 bytes (3.5 GB, 3.2 GiB) copied, 261.673 s, 13.3 MB/s</span></div><div style="text-align: left;"><span style="color: #666666; font-size: x-small;">===========</span></div><div><br /></div><div style="text-align: left;">Pi OS image writing을 하려면, 아래와 같은 준비물은 필수이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjiaUs2R6_y6wtzX1GsnIg97DgkcBoj3Tfeu0wodC_xabYjaxHdJuo-uzQtngr65WNvxsNr-SOSWsITaTy9j0W6pG0tKCik1yfDD4_3W_UMln41l1Ega0kP60iQ_WdQClS1RIXfkQPNqw8QQNGs1jYCVRNhBFChxs9-Z9w3gcrthBhqxvjVBonTYvUz_w=s4000" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4000" data-original-width="3000" height="320" src="https://blogger.googleusercontent.com/img/a/AVvXsEjiaUs2R6_y6wtzX1GsnIg97DgkcBoj3Tfeu0wodC_xabYjaxHdJuo-uzQtngr65WNvxsNr-SOSWsITaTy9j0W6pG0tKCik1yfDD4_3W_UMln41l1Ega0kP60iQ_WdQClS1RIXfkQPNqw8QQNGs1jYCVRNhBFChxs9-Z9w3gcrthBhqxvjVBonTYvUz_w=s320" width="240" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.2] microSD와 microSD to USB converter</span></div><div><br /></div><div style="text-align: left;"><b style="background-color: #b6d7a8;"><Serial console enable하기></b></div><div style="text-align: left;"><div>Serial console을 enable하기 위해서는 OS 설치 후, 먼저 아래 파일을 수정해 주어야 한다.</div><div><b><Ubuntu Desktop></b></div><div>$ <b>sudo vi /boot/config.txt</b></div><div><i> => 위의 그림 1.2의 converter를 Ubuntu desktop에 꽂은 후, 실제 mount되는 위치를 찾아 boot/config.txt 파일을 편집해 주어야 한다.</i></div><div>...</div><div><b>dtoverlay=pi3-disable-bt</b></div><div><b>sudo systemctl disable hciuart</b></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;">파일 편집을 끝낸 후에는 아래와 같이 Serial console cable 연결하여, 부팅하는 모습을 살펴 볼 수가 있겠다.</div></span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizbUhaplsuy07dPdfNeLidUbCjMr3_akrMUCanno6UyaVdAZ_PoYlNB90q3tBQSgAkk97xq3FVgSzi3_MgwjsstF-DChpuBSwhL17iIyljFiIHKujat3MxZLdzqyhC6bYghIVCrOEzirFU/s4128/20200624_131006.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizbUhaplsuy07dPdfNeLidUbCjMr3_akrMUCanno6UyaVdAZ_PoYlNB90q3tBQSgAkk97xq3FVgSzi3_MgwjsstF-DChpuBSwhL17iIyljFiIHKujat3MxZLdzqyhC6bYghIVCrOEzirFU/s320/20200624_131006.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.3] Serial console 연결</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUq-4tB2SMx_UFDlUN5MdG-FNzr_8G0a3bs4StJc8lSKH9qp-Uk_lQwKXNQJwMy_wNBYxzhC40wmEljXJ0a6X14fA7tKOb5hz3Y_to_52PBsqCO2Jd5Hf_Zq6LwDD5uGVja2k48oQ-OMww/s866/pi_minicom.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="694" data-original-width="866" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUq-4tB2SMx_UFDlUN5MdG-FNzr_8G0a3bs4StJc8lSKH9qp-Uk_lQwKXNQJwMy_wNBYxzhC40wmEljXJ0a6X14fA7tKOb5hz3Y_to_52PBsqCO2Jd5Hf_Zq6LwDD5uGVja2k48oQ-OMww/s320/pi_minicom.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.4] serial console - minicom(/dev/ttyUSB0, 115200, 8N1)</span></div><div><br /></div><div>$ <b>ssh pi@192.168.9.250</b></div><div><i>password: <font color="#f4a900">raspberry</font></i></div><div><font color="#b51200" size="2">[Tip] RPi 3 ip 192.168.9.250은 Pi OS 설치 후, /etc/network/interfaces 파일을 통해 수동 설정해 주었다. Console에서 아래 raspi-config 명령을 실행하면, 화면이 깨지는 문제가 있으니, 반드시 ssh를 이용하도록 하자.</font></div><div><br /></div><div>pi@raspberrypi:~$ <b>sudo raspi-config</b></div><div><i> => ssh로 접속하여 raspi-config 명령으로 주요 시스템 설정(<span style="color: #990000;">특히 Camera enable</span>)변경을 해주자.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCXp2egVPU-zntQ0q39vI8gXHlgW5XIz2NraFJGub2ior4gOKfDVm-xvFoGBGrS3bhVR6LgNtD0G-yddgtZ5xzepcTB77nph13291M5tIrqRcTPxRtnYSd_y1pVMFAJTnvoKCo1QGIW8dW/s851/raspi-config.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="638" data-original-width="851" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCXp2egVPU-zntQ0q39vI8gXHlgW5XIz2NraFJGub2ior4gOKfDVm-xvFoGBGrS3bhVR6LgNtD0G-yddgtZ5xzepcTB77nph13291M5tIrqRcTPxRtnYSd_y1pVMFAJTnvoKCo1QGIW8dW/s320/raspi-config.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.5] raspi-config 설정 변경 - Camera enable 시키기</span></div><div><br /></div><div>다음으로 camera app을 돌려 보기 전에 system을 전체적으로 upgrade해 주도록 하자.</div><div><br /></div><div>pi@raspberrypi:~$ <b>sudo apt-get update -y</b></div><div>pi@raspberrypi:~$ <b>sudo apt-get upgrade -y</b></div><div>pi@raspberrypi:~$ <b>sudo apt-get dist-upgrade</b></div><div>pi@raspberrypi:~$ <b>sync; sync; sudo reboot</b></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#0b8043" size="5">b) motion daemon 돌려 보기</font></b></div><div>이번 절에서는 Pi camera가 capture한 영상을 원격 PC에서 모니터링할 수 있는 <a href="https://motion-project.github.io/">motion project</a>를 소개해 보고자 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyQGSkCP4pHii3jE02K9jMEkJyIbY4UK1CeixjnYyGaAJMGpwpyA2mYaU-x4ExypzmDSsUbCFsGH85AbYxCNLDdu2UK7lbLshSoRAugtsz841wYKdUgMWW8OMQV2CO_52VX_p92vk932mp/s1143/motion_project.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="808" data-original-width="1143" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyQGSkCP4pHii3jE02K9jMEkJyIbY4UK1CeixjnYyGaAJMGpwpyA2mYaU-x4ExypzmDSsUbCFsGH85AbYxCNLDdu2UK7lbLshSoRAugtsz841wYKdUgMWW8OMQV2CO_52VX_p92vk932mp/s320/motion_project.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.6] motion project home page</span></div><div><br /></div><div>pi@raspberrypi:~$ <b>sudo apt-get install motion</b></div><div><br /></div><div>pi@raspberrypi:~$ <b>sudo vi /etc/motion/motion.conf</b></div><div>먼저 desktop PC에서 web browser로 영상을 보고자 한다면 반드시 아래와 같이 설정 변경을 해 주어야 한다.</div><div><i><font color="#f57c00">...</font></i></div><div><font color="#f57c00"><i>#daemon off</i></font></div><div><font color="#f57c00"><i>daemon on</i></font></div><div><font color="#f57c00"><i>...</i></font></div><div><i><font color="#f57c00">#stream_localhost on</font></i></div><div><i><font color="#f57c00">stream_localhost off</font></i></div><div><i><font color="#f57c00">...</font></i></div><div><i><font color="#f57c00">~</font></i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv1fyh41OD3DK_QCZ12o_3fzGoXTOhLrfOYDqeuscVHGd3s80BrxzB08mZtMQfpzQGFhP_Cvyjbay6hdfMQ4GF7fX0wxOLdqAjN2UbFPwacmdshhtG-QpJr5Moi5OH54jUj2sen5bI_BJ5/s1094/motion_conf2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="1094" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv1fyh41OD3DK_QCZ12o_3fzGoXTOhLrfOYDqeuscVHGd3s80BrxzB08mZtMQfpzQGFhP_Cvyjbay6hdfMQ4GF7fX0wxOLdqAjN2UbFPwacmdshhtG-QpJr5Moi5OH54jUj2sen5bI_BJ5/s320/motion_conf2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.7] motion.conf 파일 설정 바꾸기</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div>pi@raspberrypi:~$ <b>sudo service motion start</b></div><div><i> => RPi3 ip 192.168.9.250의 8081번 port로 web 접속을 시도하면 motion daemon이 capture한 영상을 화면에서 확인할 수 있다.</i></div><div><br /></div><div style="text-align: center;"><b>Desktop PC(web browser, 192.168.9.156) ==> RPi3(motion daemon, 192.168.9.250:8081)</b></div><div style="text-align: center;"><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFyhQwedTqojR0EjVMSs8oPfLSSil7T0BRaRPTIA_XreMNimkDr74eHcN4SLiOP2x067SumcpkHLRtoZbcNuWmpIKI1_0mZYvFhdY3Ih3A3mN5Q_UpmPJJF4GawWgeZKu4Z0QJ-SIR-gj/s1210/motion_cap1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="865" data-original-width="1210" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuFyhQwedTqojR0EjVMSs8oPfLSSil7T0BRaRPTIA_XreMNimkDr74eHcN4SLiOP2x067SumcpkHLRtoZbcNuWmpIKI1_0mZYvFhdY3Ih3A3mN5Q_UpmPJJF4GawWgeZKu4Z0QJ-SIR-gj/w400-h286/motion_cap1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="text-align: left;">[그림 1.8] motion daemon이 capture한 영상을 web browser로 확인하기</span></div></div><div><br /></div><div>이때, motion daemon의 CPU 점유율을 확인해 보면 다음과 같다(대략 10% 내외에서 동작하고 있다).</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pAgWW1UKJ1dh38KTzhoWBjegVPdTmqDP6athJzyg9xoRLO9VR-Vou0DNHHGHgN4sgJ_5wD5_B-GSAtuR9nOnUamMgdlDDY-oJpBIJbB7ReVgzY7ujwy60MvBNUAvV4hdaRqKWQGGn0OH/s1094/motion_top.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="1094" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4pAgWW1UKJ1dh38KTzhoWBjegVPdTmqDP6athJzyg9xoRLO9VR-Vou0DNHHGHgN4sgJ_5wD5_B-GSAtuR9nOnUamMgdlDDY-oJpBIJbB7ReVgzY7ujwy60MvBNUAvV4hdaRqKWQGGn0OH/w400-h240/motion_top.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.9] motion daemon의 CPU 점유율(width x height: 320 x 240)</span></div><div><br /></div><div>이 상태에서 화면 해상도(width x height)를 320 x 240에서 720 x 480으로 늘려 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_hNZ9FruU2cqFecPXGjN8iBe45_TXje4FyeuPCQn-P9RUreB_LH4w5sdskPyJsPO0Kg50hKZnU-GTRDZQftt9lM9K89KfQAkX8w5-ZHKC_OXJPaW5Y2PZD1vDLWmjGaNktFFiHHAivVGs/s1210/motion_cap2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="865" data-original-width="1210" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_hNZ9FruU2cqFecPXGjN8iBe45_TXje4FyeuPCQn-P9RUreB_LH4w5sdskPyJsPO0Kg50hKZnU-GTRDZQftt9lM9K89KfQAkX8w5-ZHKC_OXJPaW5Y2PZD1vDLWmjGaNktFFiHHAivVGs/w400-h286/motion_cap2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.10] 720 x 480으로 화면 해상도 변경 모습</span></div><div><br /></div><div>해상도를 증가시키니, CPU 점유율도 30% 정도까지 육박하는 것을 알 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRcJ6b5mk37vlT-IV2vvqI9fzWnguTb-dwFpNmACPFWf-WK-FDWDXHTYOfbVtqAdi6uJmAL7hnGVuBlra31wjjQ3NZ0C4L96Uay4aURgqDrfzEp9xHWZiwR7j-yWo5Ea5YmtGQyp4h_YG/s1094/motion_top2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="656" data-original-width="1094" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRcJ6b5mk37vlT-IV2vvqI9fzWnguTb-dwFpNmACPFWf-WK-FDWDXHTYOfbVtqAdi6uJmAL7hnGVuBlra31wjjQ3NZ0C4L96Uay4aURgqDrfzEp9xHWZiwR7j-yWo5Ea5YmtGQyp4h_YG/w400-h240/motion_top2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.11] 720 x 480으로 화면 해상도 변경 시 CPU 점유율</span></div><div style="text-align: left;"><font color="#b51200" size="2">[Tip] framerate(default 값: 2)를 15 정도로 올리기만 해도 CPU 점유율이 90% 대까지도 육박한다.</font></div><div style="text-align: center;"><br /></div><div>pi@raspberrypi:~$ <b>sudo vi /etc/default/motion</b></div><div><i> => 부팅 시에 자동으로 motion daemon을 시작하도록 하려면 아래와 같이 설정을 변경해 주어야 한다.</i></div><div><i><font color="#f57c00">#start_motion_daemon=no</font></i></div><div><i><font color="#f57c00">start_motion_daemon=yes</font></i></div><div><i><font color="#f57c00">~</font></i></div><div><br /></div><div>motion daemon은 이 밖에도 아주 다양한 기능을 제공한다. 자세한 사항은 아래 site를 참조하기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://motion-project.github.io/motion_config.html#configfiles">https://motion-project.github.io/motion_config.html#configfiles</a></div><div><br /></div><div><br /></div><div><b><font color="#0b8043" size="5">c) mjpg-streamer 돌려 보기</font></b></div><div>mjpg-streamer는 camera로 부터 읽어 들인 JPEG frame을 ip network을 통해 다양한 viewer 즉, Chrome, Firefox, Cambozola, VLC, mplayer에게 전달(stream)해 주는 역할을 하는 command line tool이다.</div><div><br /></div><div>아래 <a href="https://github.com/jacksonliam/mjpg-streamer">jacksonliam의 github의 코드</a>는 <a href="https://sourceforge.net/projects/mjpg-streamer/">original mjpg-streamer</a>를 fork하여 RPi 용으로 개조(정확하게는 RPi 용 input plugin을 새로 추가)한 version으로 CPU 점유율을 획기적으로 개선(사용량을 대폭 줄임)하였다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkIWINzhktRiKDOVwd1SyQqfhswP-0m8N32l2QeWBDLmnE9RBie3HH5JGA7Vxw1kA1lAj7JnkUMe2jIiA8B9gEMVbOMdyFDo7OjxUaIBXK5INSlGU3xEclMypWX1B2XrZQOdq1kmB8aUnY/s1314/mjpeg-streamer1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="927" data-original-width="1314" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkIWINzhktRiKDOVwd1SyQqfhswP-0m8N32l2QeWBDLmnE9RBie3HH5JGA7Vxw1kA1lAj7JnkUMe2jIiA8B9gEMVbOMdyFDo7OjxUaIBXK5INSlGU3xEclMypWX1B2XrZQOdq1kmB8aUnY/w400-h283/mjpeg-streamer1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.12] mjpg-streamer github -<font color="#b51200"> input_rapicam plugin</font>을 지원</span></div><div><br /></div><div>RPi 3에서 직접 source code를 내려 받아 build 후 실행해 보도록 하자.</div><div><br /></div><div>pi@raspberrypi:~$ <b>sudo apt-get install cmake libjpeg8-dev</b></div><div><br /></div><div>pi@raspberrypi:~$ mkdir workspace; cd workspace</div><div>pi@raspberrypi:~$ <b>git clone <a href="https://github.com/jacksonliam/mjpg-streamer">https://github.com/jacksonliam/mjpg-streamer</a></b></div><div>pi@raspberrypi:~$ <b>cd mjpg-streamer/mpjg-streamer-experimental</b></div><div><br /></div><div>pi@raspberrypi:~$ <b>make</b></div><div>pi@raspberrypi:~$ <b>sudo make install</b></div><div><br /></div><div>pi@raspberrypi:~$ <b>./mjpg_streamer --help</b></div><div><i> => mjpg_streadmer 사용법을 확인해 본다.</i></div><div><br /></div><div>pi@raspberrypi:~$<b> ./mjpg_streamer -i 'input_raspicam.so --help'</b></div><div> <i> => input_raspicam.so plugin 관련 사용법을 확인해 본다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCejDFXF0fK7hVh2v-5BqkovK2WxXQqm2UVap3dXpwk7OFVKo-8WcUBH0a4Z-S4izdEP75hDU5DleyPiSWjWj8ZphJa2mwMLAk2lNoseGU7kPxKMMNBywSx-MdqDKILukjXKF-HojXdlhv/s1030/mjpg_streamer_input_raspicam_help.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="1030" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCejDFXF0fK7hVh2v-5BqkovK2WxXQqm2UVap3dXpwk7OFVKo-8WcUBH0a4Z-S4izdEP75hDU5DleyPiSWjWj8ZphJa2mwMLAk2lNoseGU7kPxKMMNBywSx-MdqDKILukjXKF-HojXdlhv/w400-h243/mjpg_streamer_input_raspicam_help.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.13] mjpeg-streamer </span><span style="text-align: left;">input_raspicam.so plugin 관련 </span><span style="text-align: left;">도움말 살펴 보기</span></div><div><br /></div><div>pi@raspberrypi:~$ <b>./mjpg_streamer -o 'output_http.so --help'</b></div><div><i>=> output_http.so plugin 관련 사용법을 확인해 본다.</i></div><div><i><br /></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0aEw6Sv8UoTTv3v_XG5Pd2vXuBLw6wXpmlUfe0JvGAnWouu_6AuIgmLX6PF67QwzfJdK9L0tiFzYDe4Du1z59bhCyQWr8Nq0a2UmftATqnVuKaJMFAx5a-oQ_tu7NRYzv_h6uuFD2eB9s/s1005/mjpg_streamer_output_plugin_help.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="278" data-original-width="1005" height="111" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0aEw6Sv8UoTTv3v_XG5Pd2vXuBLw6wXpmlUfe0JvGAnWouu_6AuIgmLX6PF67QwzfJdK9L0tiFzYDe4Du1z59bhCyQWr8Nq0a2UmftATqnVuKaJMFAx5a-oQ_tu7NRYzv_h6uuFD2eB9s/w400-h111/mjpg_streamer_output_plugin_help.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.14] mjpeg-streamer output_http.so</span><i style="text-align: left;"> </i><span style="text-align: left;">plugin 관련 </span><span style="text-align: left;">도움말 살펴 보기</span></div><div><br /></div><div>pi@raspberrypi:~$ <b>./mjpg_streamer -o "outout_http.so -w ./www" -i "<font color="#f57c00">input_raspicam.so</font> -fps 10 -x 1280 -y 720 -vf"</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWzUoFO75-kBrt-0G4oiqTJbvoM_qRvqoUHGF3hyphenhyphen2v6pMfHlUb2MP8KK3T_kJFI_4JDoDXYYP_ofvsn5zOcMCidh0vlg6pskl8okBoLtYRw594YBWaj0RcuAAP39EeH6sb1SEJcmRBeD8A/s1089/mjpg_streamer4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="376" data-original-width="1089" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWzUoFO75-kBrt-0G4oiqTJbvoM_qRvqoUHGF3hyphenhyphen2v6pMfHlUb2MP8KK3T_kJFI_4JDoDXYYP_ofvsn5zOcMCidh0vlg6pskl8okBoLtYRw594YBWaj0RcuAAP39EeH6sb1SEJcmRBeD8A/w400-h138/mjpg_streamer4.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.15] mjpg-streamer 실행</span></div><div><font color="#b51200" size="2">[Tip] -vf option(</font><font color="#b51200" size="2">Set vertical flip)을</font><span style="color: #b51200; font-size: small;"> 사용하면 화면이 뒤짚여서 출력된다. RPi 3에 연결된 Pi camera가 뒤짚여 연결되어 있기 때문에 이 option을 사용해야 화면이 똑 바로 보이게 된다.</span></div><div><br /></div><div><b style="text-align: center;">http://192.168.9.250:8080</b></div><div><b style="text-align: center;"><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR3a1-utNUkgqgZnJv7wVUiJUsJwoBkL3dZJG8D3J2aiXlvBEpja9xMH4JYQs_tIoEEM3_n2Nu-X0eSqQojtpIT1qDDbnjXa3KqoPc6Yot8D0Ye4WpNWURXca9rICfWo7HgPcoE6S0mt6T/s1210/mjpg_streamer_sbucks2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="865" data-original-width="1210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR3a1-utNUkgqgZnJv7wVUiJUsJwoBkL3dZJG8D3J2aiXlvBEpja9xMH4JYQs_tIoEEM3_n2Nu-X0eSqQojtpIT1qDDbnjXa3KqoPc6Yot8D0Ye4WpNWURXca9rICfWo7HgPcoE6S0mt6T/s320/mjpg_streamer_sbucks2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.16] Web browser로 RPi3에 접속한 모습 - mjpg streamer가 streaming하는 영상 확인</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCQkxBgcYnPwuUM153IvcooBkkNH-dfzPV-iYW6YE7HH8eW64Vxcrz5e3skuR9IwU84bUzqWCWccm3_4Jr0HrWH8uIdH7a0xuCpH0xul03ubfk4vPw6FI_AsWU1igiLIpjvFkId2BT6HNo/s1139/mjpg_streamer6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="764" data-original-width="1139" height="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCQkxBgcYnPwuUM153IvcooBkkNH-dfzPV-iYW6YE7HH8eW64Vxcrz5e3skuR9IwU84bUzqWCWccm3_4Jr0HrWH8uIdH7a0xuCpH0xul03ubfk4vPw6FI_AsWU1igiLIpjvFkId2BT6HNo/w400-h269/mjpg_streamer6.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="text-align: left;">[그림 1.17] mjpg streamer의 CPU 점유율(4 ~ 5% 대)</span></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">아래 그림은 Ubuntu 18.04에서 mplayer를 사용하여 mjpg-streamer가 전송하는 영상을 출력하는 모습을 보여준다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ <b>mplayer -fps 30 -demuxer lavf "http://192.168.9.250:8080/?action=stream&ignored.mjpg"</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV8iUcPLTcVTDXNfyMSA4TOPdwlhc9Zeuc69gdxPhgS3bKqJgYgAge9pCFHRF3ahLMmdvt_8pwum3yze-saVQ28STfFBtOYsyhwccKRFR56nPy2fnk13VtIycQn6qizg_OiR8wmAHHfY6K/s911/mplayer1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="653" data-original-width="911" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjV8iUcPLTcVTDXNfyMSA4TOPdwlhc9Zeuc69gdxPhgS3bKqJgYgAge9pCFHRF3ahLMmdvt_8pwum3yze-saVQ28STfFBtOYsyhwccKRFR56nPy2fnk13VtIycQn6qizg_OiR8wmAHHfY6K/s320/mplayer1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidrKXK0RkqfBtqcLCqLwn-CTe-IvQPk3F7-_TeEzL43HOwEI9bMvB457Z3dTzxujBujopYY7LNvG7B8jvDHfkUB5co66_TsvK69thHViG2R989ACQPwRwbPMARZXWJKREGmL0olBTg7XWv/s1280/mplayer2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="750" data-original-width="1280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidrKXK0RkqfBtqcLCqLwn-CTe-IvQPk3F7-_TeEzL43HOwEI9bMvB457Z3dTzxujBujopYY7LNvG7B8jvDHfkUB5co66_TsvK69thHViG2R989ACQPwRwbPMARZXWJKREGmL0olBTg7XWv/s320/mplayer2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[</span><span style="text-align: left;">그림 1.18] mplayer로 </span><span style="text-align: left;">mjpg streamer가 streaming하는 영상 확인</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div>mjpg-streamer는 어떻게 해서 CPU 점유율을 현저히 떨어뜨릴 수 있었을까 ? 그 해답은 BCM2835 SoC 내에 존재하는 VideoCore IV GPU를 적극 활용했기 때문인데, 이와 관련해서는 3장에서 자세히 설명하도록 할 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">mjpg-streamer의 raspicam input plugin은 raspistill mmal source code를 기초로 하여 작성된 것이다. 따라서 아래 code도 함께 참조해 보기 바란다.</span></div><div><br /></div><div style="text-align: center;"><a href="https://github.com/raspberrypi/userland/tree/master/host_applications/linux/apps/raspicam/RaspiStill.c">https://github.com/raspberrypi/userland/tree/master/host_applications/linux/apps/raspicam/RaspiStill.c</a></div><div style="text-align: center;"><br /></div><div><br /></div><div>이상으로 RPi 3에 Pi Camera를 장착하고, motion & mjpg-streamer application을 이용해서 camera가 capture한 영상을 desktop PC에서 확인해 보았다. 다음 장에서는 지금까지 테스트에 사용한 Pi Camera의 주요 특징과 MIPI CSI-2 interface에 대해서 알아 볼 것이다.</div><div><br /></div><div><br /></div><div><b style="color: #3367d6; font-size: xx-large;">2. Pi Camera와 MIPI CSI-2의 이해</b></div><div>이 장에서는 Raspberry Pi 재단에서 개발/판매하는 Pi Camera V2(2016년 release)에 대해 살펴 보고자 한다. 이어서 Pi Camera를 Camera controller와 어떻게 연결(MIPI CSI-2 interface)하는 지에 대해서도 파악해 보고자 한다.</div><div><br /></div><div><font color="#0b8043" size="5"><b>a) Pi Camera V2</b></font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkDU6EMYYF3-f4Q9RlLSlSx7XiEAQsOu_5bc1gjlcYhqTYkofL-MSqVNDoE-K6npGe2heukHoOrBkSHP-rhp2GBkeoeJxU1sexNQHZ2yN9vueMWplrgH2lJucNjQFWaYDoR_GXp5Pz_1xN/s355/picamera.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="254" data-original-width="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkDU6EMYYF3-f4Q9RlLSlSx7XiEAQsOu_5bc1gjlcYhqTYkofL-MSqVNDoE-K6npGe2heukHoOrBkSHP-rhp2GBkeoeJxU1sexNQHZ2yN9vueMWplrgH2lJucNjQFWaYDoR_GXp5Pz_1xN/s320/picamera.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] Pi Camera Module v2</div><div><font color="#b51200" size="2">[Tip] 최근(2020년)에는 이 보다 성능이 더 우수한 <a href="https://www.raspberrypi.org/products/raspberry-pi-high-quality-camera/">12-megapixel High Quality Camera</a>도 release된 바가 있다.</font></div><div><br /></div><div><span style="background-color: #c6dafc;"><Pi Camera V2 주요 spec></span></div><div><table border="1" bordercolor="#888" cellspacing="0" style="border-collapse: collapse; border-color: rgb(136, 136, 136); border-width: 1px;"><tbody><tr><td style="min-width: 60px;"> 항목</td><td style="min-width: 60px;"> 상세 내용</td></tr><tr><td style="min-width: 60px;"> Still resolution</td><td style="min-width: 60px;">8 Megapixels </td></tr><tr><td> Video modes</td><td>1080p30, 720p60, 640 x 480p60/90 </td></tr><tr><td> Sensor 모델</td><td> <b><font color="#f57c00">Sony IMX219</font></b></td></tr><tr><td> Sensor resolution</td><td> 3280 x 2464 pixels</td></tr><tr><td> Linux integration</td><td> V4L2 driver available</td></tr></tbody></table><br /><br /></div><div>보다 자세한 스펙 사항은 아래 site에 잘 정리되어 있다.<br /><div style="text-align: center;"><a href="https://www.raspberrypi.org/documentation/hardware/camera/">https://www.raspberrypi.org/documentation/hardware/camera/</a></div></div><div><br /></div><div>다음으로 Sony IMX219 sensor의 구조를 대략적으로 살펴 보기로 하자.</div><div><br /></div><div style="text-align: center;"><a href="https://publiclab.org/system/images/photos/000/023/294/original/RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF">https://publiclab.org/system/images/photos/000/023/294/original/RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF</a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibMWevIrQ89R3RMSbXVopcmda5F-U-Ll8i5Lvvb3aA4HoOVpbleibh9ptKFmfeUvkzy3jJta0q71Gw_kU_abfrpuEqYJzX0dW5HpkPcLzDTwF6ZKNNwPjBF5XPLVLwlxgODQFbYh_1piJE/s822/imx219_blockdiagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="405" data-original-width="822" height="317" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibMWevIrQ89R3RMSbXVopcmda5F-U-Ll8i5Lvvb3aA4HoOVpbleibh9ptKFmfeUvkzy3jJta0q71Gw_kU_abfrpuEqYJzX0dW5HpkPcLzDTwF6ZKNNwPjBF5XPLVLwlxgODQFbYh_1piJE/w640-h317/imx219_blockdiagram.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.2] Sony IMX219 camera sensor block diagram</span></div><div><br /></div><div><br /></div><div>IMX219 camera 센서는 MIPI CSI-2 interface(D-PHY)를 사용하여 camera controller(SoC 쪽)와 연결되어 있다.</div><div><br /></div><div style="text-align: center;"><b>[RAM] <--- Controller(AP) <--- MIPI CSI-2 <--- IMX219</b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBzYAWr9KTXzGFf34jVv1zTLE56glGJzos7_-O3Nv4ejDnkZ5cUO2SSyMLERja9BXYRG8-gjm2vXj0BL_CfqWXr5Sl7ReRkrhbduY0cjGnDKT8OIooW7G46EeDYfml68Gdaszo7f_EaeL/s1134/v4l2_1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="326" data-original-width="1134" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFBzYAWr9KTXzGFf34jVv1zTLE56glGJzos7_-O3Nv4ejDnkZ5cUO2SSyMLERja9BXYRG8-gjm2vXj0BL_CfqWXr5Sl7ReRkrhbduY0cjGnDKT8OIooW7G46EeDYfml68Gdaszo7f_EaeL/w400-h115/v4l2_1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.3] Camera sensor와 Controller와의 관계 </span><span style="text-align: left;"> </span><b>[참고 문헌 3]</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"> </span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQTGpFEXTUu2q8iA1iDaA3uj71jh0MZbnDiMSK_3OSA9gFzh3qNS_A-hqc1c0CSB-y-6Qn8K8-XahAQEnlDIaTkfRSIr_svYL5Ye_6dRP5nMixW27sFyzwX1_UG72JzwzlOwhwyA8KNHBz/s373/imx219_mipi_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="236" data-original-width="373" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQTGpFEXTUu2q8iA1iDaA3uj71jh0MZbnDiMSK_3OSA9gFzh3qNS_A-hqc1c0CSB-y-6Qn8K8-XahAQEnlDIaTkfRSIr_svYL5Ye_6dRP5nMixW27sFyzwX1_UG72JzwzlOwhwyA8KNHBz/s320/imx219_mipi_output.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.4] Sony IMX219 camera sensor의 MIPI output block</span></div><div><br /></div><div><br /></div><div>IMX219 camera 센서의 각종 레지스터 제어를 위해서는 i2c interface가 사용된다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsgmsTNFrrAgG0kL4Oa5r6EQ_IiuZ6AEcWDY3NlBVIdWnNDGRwB_hRRqwRwT2i19sYC4xfLZa9ZxwB7nMzsQzwvad2C23kVfmi4k0FtAH4hkxBBo0070FuUSeZ0TnsSLVytkxJJXulbtTT/s537/imx219_i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="132" data-original-width="537" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsgmsTNFrrAgG0kL4Oa5r6EQ_IiuZ6AEcWDY3NlBVIdWnNDGRwB_hRRqwRwT2i19sYC4xfLZa9ZxwB7nMzsQzwvad2C23kVfmi4k0FtAH4hkxBBo0070FuUSeZ0TnsSLVytkxJJXulbtTT/s320/imx219_i2c.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.5] Sony IMX219 camera sensor 2 wire serial communication - CCI(Camera Control Instance)</span></div><div><br /></div><div><br /></div><div><b><font color="#0b8043" size="5">b) MIPI CSI-2</font></b></div><div>Camera sensor의 동작 방식을 제대로 이해하기 위해서는 MIPI CSI-2와 같은 camera interface에 대한 이해가 선행되어야 한다. </div><div>먼저 아래 그림은 <a href="https://www.mipi.org/">mipi alliance</a>에서 배포하고 있는 CSI-2 spec 문서에 포함되어 있는 내용으로 MIPI CSI-2 D-PHY 인터페이스와 C-PHY 인터페이스를 개략적으로 보여준다.</div><div> </div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp4lqrsr2xaFarSb2ry6LUEl20g9gMLm4ptjy-VAI0xZ_lGfN_zHyV5ld5ky2tEA8MysxB-GklhRnAH4EQZ5QpjqadiS9hbz2EhJzaV8Tu8u1gfl6ECwc_E34Tl_XydSXGoeqgRgL4hqU1/s512/mipi_csi2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="389" data-original-width="512" height="486" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp4lqrsr2xaFarSb2ry6LUEl20g9gMLm4ptjy-VAI0xZ_lGfN_zHyV5ld5ky2tEA8MysxB-GklhRnAH4EQZ5QpjqadiS9hbz2EhJzaV8Tu8u1gfl6ECwc_E34Tl_XydSXGoeqgRgL4hqU1/w640-h486/mipi_csi2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.6] MIPI CSI-2 : D-PHY, C-PHY<b> [참고 문헌 11]</b></div><div><br /></div><div>아래 그림은 위의 그림과 동일한 내용으로 CSI-2 D-PHY, CSI-2 C-PHY 외에도 CSI-3 Interface에 대한 그림도 포함되어 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2Ap8xiSThMxF6WwrDddknYEY1EMX3K1LBNFHJGe_FCytZ5AjaEEUt1BIjEqtZ2-2D1r7pa0AEt0zCkEWC-bSrUjKyP_c7YM75v6YBT2CKH-pj3_k6Y7YE0V6N2BkZdESZOKc3ZDhymXLq/s602/mipi_csi_interface.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="602" data-original-width="413" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2Ap8xiSThMxF6WwrDddknYEY1EMX3K1LBNFHJGe_FCytZ5AjaEEUt1BIjEqtZ2-2D1r7pa0AEt0zCkEWC-bSrUjKyP_c7YM75v6YBT2CKH-pj3_k6Y7YE0V6N2BkZdESZOKc3ZDhymXLq/w275-h400/mipi_csi_interface.png" width="275" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.7] MIPI CSI-2, CSI-3 Interface</div><div><br /></div><div><b>D-PHY</b>: clock lane(+/- 2 line으로 구성)과 data lane(2개 or 4개의 data lane)으로 구성</div><div><b>C-PHY</b>: clock을 data에 포함시켜 전달, lane당 3개의 line으로 구성</div><div><br /></div><div>MIPI CSI-2 D-PHY, C-PHY 및 CSI-2 Packet format 등과 관련해서는 (한눈에 보기 쉽게) 아래 문서에 잘 정리가 되어 있다. 저작권 문제가 있는 듯하여 관련 이미지를 별도로 capture하지는 않았으니, 아래 파일을 직접 참조해 보기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://www.mipi.org/sites/default/files/Camera%20Serial%20Interface_CSI2_CSI3_Overview.pdf">https://www.mipi.org/sites/default/files/Camera%20Serial%20Interface_CSI2_CSI3_Overview.pdf</a></div><div style="text-align: center;"><br /></div><div>MIPI PHY(physical layer) 못지 않게 중요한 부분이 CSI-2 protocol에 관한 부분이다. 아래 그림은 MIPI protocol layer에서 사용되는 MIPI CSI-2 packet format을 간력히 소개한 것이다. 아래 그림에서 Short packet(data type이 0x00 ~ 0x0F에 해당)은 frame start를 알려주는 packet이며, long packet(data type이 0x10 ~ 0x37에 해당)은 실제 data packet에 해당한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpeJLiTNqkgxK8VjFuz0nfCgTb93JRSpIHnT03DiaAIB0swsUWto74Gf6ni09xBBrgr9ZuuaZLAxI3B3JywlbXJHq43ItyKPylRqxvwWp7BtD5uee3-A2rOWYBVfjiRHa-Bk1BxhBvqAAm/s609/llp_format.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="175" data-original-width="609" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpeJLiTNqkgxK8VjFuz0nfCgTb93JRSpIHnT03DiaAIB0swsUWto74Gf6ni09xBBrgr9ZuuaZLAxI3B3JywlbXJHq43ItyKPylRqxvwWp7BtD5uee3-A2rOWYBVfjiRHa-Bk1BxhBvqAAm/w640-h184/llp_format.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.8] MIPI CSI-2 Packet Format </span><b style="text-align: left;">[참고 문헌 12]</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaAzKrknxkD946FtMLtBd4HziNoVQlY7QLjqv1SR40cayYQBJJwqrV9Nwi-xNbSYC66_kvElH187ALF-RyhfNqvaDAEMZZl2fPoZ58yb298PUPwwELi7kfpGr4vMY1Tj0z-C7_Djcv7PLu/s619/llp_long_packet_format.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="124" data-original-width="619" height="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaAzKrknxkD946FtMLtBd4HziNoVQlY7QLjqv1SR40cayYQBJJwqrV9Nwi-xNbSYC66_kvElH187ALF-RyhfNqvaDAEMZZl2fPoZ58yb298PUPwwELi7kfpGr4vMY1Tj0z-C7_Djcv7PLu/w640-h128/llp_long_packet_format.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.9] MIPI CSI-2 Packet Format </span><b style="text-align: left;">- long packet </b><b style="text-align: left;">[참고 문헌 12]</b></div><div><div><br class="Apple-interchange-newline" /><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijrisEEE2CZzNidCeaXiDYVCDZnSWE0EPVwXaVcjTdoIsrywHh0oweKyFErj-MgtLMnOg_K-verxJcE2cbyPv5xH2jrOmeQ-OZU_U1EJLMuvieEAiKgVfioCTJc7k2nCAtbGTyLVff9a0v/s390/llp_short_packet_format.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="169" data-original-width="390" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijrisEEE2CZzNidCeaXiDYVCDZnSWE0EPVwXaVcjTdoIsrywHh0oweKyFErj-MgtLMnOg_K-verxJcE2cbyPv5xH2jrOmeQ-OZU_U1EJLMuvieEAiKgVfioCTJc7k2nCAtbGTyLVff9a0v/s320/llp_short_packet_format.png" width="320" /></a></div><div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.10] MIPI CSI-2 Packet Format </span><b style="text-align: left;">- short packet </b><b style="text-align: left;">[참고 문헌 12]</b></div><div></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR7d1KPjU5ReUAl3zIm9U3_bpc03X2wxJ3nDFgqGIKI_V0AFsq2scSz381D4kSM97zHgsPqrh9atQVY3U07pzvypXxAVqgpiCZ6HPz9zZcnCoPAwNRoJWGCAzfdTW7Zln5Yi0_VyaeISxl/s858/llp_data_types.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="189" data-original-width="858" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR7d1KPjU5ReUAl3zIm9U3_bpc03X2wxJ3nDFgqGIKI_V0AFsq2scSz381D4kSM97zHgsPqrh9atQVY3U07pzvypXxAVqgpiCZ6HPz9zZcnCoPAwNRoJWGCAzfdTW7Zln5Yi0_VyaeISxl/w640-h140/llp_data_types.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 2.11] MIPI CSI-2 Data Type Table </span><b style="text-align: left;">[참고 문헌 12]</b></div><div><br /></div><div>이상으로 (정말 간략하게) PI Camera sensor와 MIPI CSI-2 interface에 대해 살펴 보았다. 다음으로 확인할 사항은 지금까지 설명한 내용(H/W 관점)을 S/W 관점에서 재 조명해 보는 것이다.</div><div><br /></div><div><br /></div><div><div><b><font color="#3367d6" size="6">3. Pi Camera S/W Architecture</font></b></div><div>이장에서는 <a href="https://linuxtv.org/downloads/v4l-dvb-apis/">V4L2 sub system</a>을 기반으로 하는 camera device driver(platform driver <=> sensor driver)와 Broadcom <b><font color="#9c27b0">Videocore IV(VCOS) 및 MMAL</font></b>(브로드컴 MultiMedia Abstraction Layer)에 관하여 간략히 언급해 보고자 한다.</div></div><div><br /></div><div><div><b><font color="#0b8043" size="5">a) V4L2(Video4Linux 2) subsystem</font></b></div><div>V4L2는 camera, TV Tuner와 같은 device를 위한 video capture framework(or sub system)이다.</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-_EbhGbfwHaycM5kTVUj7fQ5JAUB1oTILEa1m-DqK8rvXuHe85mEdwhgl7PSCHDfCcbUCGzw0e6ALrUgjlHm60-79IIbal2v5l8ZaQ4_OA_wzXI3TexkeDGZinv6WoaLV0KU_V4d2KiIm/s1323/prVt6.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1323" data-original-width="904" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-_EbhGbfwHaycM5kTVUj7fQ5JAUB1oTILEa1m-DqK8rvXuHe85mEdwhgl7PSCHDfCcbUCGzw0e6ALrUgjlHm60-79IIbal2v5l8ZaQ4_OA_wzXI3TexkeDGZinv6WoaLV0KU_V4d2KiIm/w274-h400/prVt6.png" width="274" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.1] Camera system architecture <b>[참고 문헌 13]</b></span></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">[Tip] 위의 그림의 IPU는 Raspberry Pi 보드에서는 GPU로 보면 될 듯하다.</font></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><div><div class="separator" style="clear: both; text-align: center;"><br class="Apple-interchange-newline" /><div style="text-align: justify;"><span style="text-align: left;">V4L2는 다양한 유형의 장치를 지원하며 생각보다 전체 구조가 매우 복잡하다. 따라서 이를 한마디로 요약하기는 참으로 힘들다. 그럼에도 불구하고 아래 그림 3.2 ~ 3.5에서 V4L2의 개념을 간단히 정리해 보았다.</span></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUqthiBsu8hLUCfaO3O2pxzIGrLFz6Ck3t89slmnMPBnj99cFE-3kZhcHBNXQO6ipR8Yw0TNTPqUEgHkrlgumohlGLL7k5RxxpHjj1GcHM5fLK4-GKtwhe_Myr-hlFusu2Wqft9vlx1aXI/s1134/v4l2_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="423" data-original-width="1134" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUqthiBsu8hLUCfaO3O2pxzIGrLFz6Ck3t89slmnMPBnj99cFE-3kZhcHBNXQO6ipR8Yw0TNTPqUEgHkrlgumohlGLL7k5RxxpHjj1GcHM5fLK4-GKtwhe_Myr-hlFusu2Wqft9vlx1aXI/w400-h149/v4l2_2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.2] V4L2 관점에서 바라본 Streaming 모드 아키텍쳐 </span><b>[참고 문헌 3]</b></div></div><div><span style="color: #b51200; font-size: small;">[Tip] V4L2 framwork은 Controller driver, Camera(sensor) driver, userspace program 전체에 걸쳐 동작하도록 설계되어 있다.</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqNt4_FtNLYlCRYIg3yWJMSgVDQqlOjULgg4nyFGmx0c1PBdbu44DzU138tV6L3lithzJ0E9q0-seNakbKYvFUL2YfjyYy2dN_Kb0mJ35B04lN0loKULtFv4CrHkk-_8GHXeuBUc_W52Xa/s1053/v4l2_framework.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="667" data-original-width="1053" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqNt4_FtNLYlCRYIg3yWJMSgVDQqlOjULgg4nyFGmx0c1PBdbu44DzU138tV6L3lithzJ0E9q0-seNakbKYvFUL2YfjyYy2dN_Kb0mJ35B04lN0loKULtFv4CrHkk-_8GHXeuBUc_W52Xa/w640-h406/v4l2_framework.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.3] V4L2 subsystem 개요 </span><b style="text-align: left;">[참고 문헌 14]</b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXrZPR2nOyX9O_neSL5_ELciUVOSAObsSeJJcYfBf57hyJCs9hrBcC3WmfiO0ktYjd9gIxvJm2Z_jzFZNQsRzJ2wyeWVcukrmICNwqaJBes-Wqp7Fctj8eN6Oi8Rc9VzM-dH3w47YKi_i1/s681/v4l2_3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="532" data-original-width="681" height="313" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXrZPR2nOyX9O_neSL5_ELciUVOSAObsSeJJcYfBf57hyJCs9hrBcC3WmfiO0ktYjd9gIxvJm2Z_jzFZNQsRzJ2wyeWVcukrmICNwqaJBes-Wqp7Fctj8eN6Oi8Rc9VzM-dH3w47YKi_i1/w400-h313/v4l2_3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.4] V4L2 관점에서 camera controller driver의 기본 흐름도(probe 함수 내용) </span><b>[참고 문헌 3]</b></div></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEQRTewo6Lmh_nZsgj0JHxAH8Yy3LBVi6nOWtEukqW8hbMRpU4AMbDRRse3Ktv_Sc9phl6WTWzqKD1iwL8WR4xIerafU0-T3VogcyNJRiDLsCAX-0bb9yr_pHbwWuV3JmiPL1rvwrUSSw_/s569/V4L2-image-capture-operation-flowchart.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="569" data-original-width="524" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEQRTewo6Lmh_nZsgj0JHxAH8Yy3LBVi6nOWtEukqW8hbMRpU4AMbDRRse3Ktv_Sc9phl6WTWzqKD1iwL8WR4xIerafU0-T3VogcyNJRiDLsCAX-0bb9yr_pHbwWuV3JmiPL1rvwrUSSw_/s320/V4L2-image-capture-operation-flowchart.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.5] V4L2 image capture operation(userspace application) flowchart</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD3kvGxXRNWAXNShwtOkgYo8BuF6s2_ff8ZESNb5O9iiAJZIH-8sfDLJ1v9384vNFrEb38u5ZHQ1CyH8oxRMmyarLTwUSXgmVJCkx3drf7mBucVHrmjGGgiFiSdvoFwJ0dUUQ2WrClYhHX/s634/v4l2_app_flow.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="634" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiD3kvGxXRNWAXNShwtOkgYo8BuF6s2_ff8ZESNb5O9iiAJZIH-8sfDLJ1v9384vNFrEb38u5ZHQ1CyH8oxRMmyarLTwUSXgmVJCkx3drf7mBucVHrmjGGgiFiSdvoFwJ0dUUQ2WrClYhHX/w400-h131/v4l2_app_flow.png" width="400" /></a></div><div><br /></div><div>V4L2 관련 보다 구체적인 사항은 필히 아래 site 내용을 검토해 보기 바란다.</div><div style="text-align: center;"><b><a href="https://linuxtv.org/downloads/v4l-dvb-apis/">https://linuxtv.org/downloads/v4l-dvb-apis/</a></b></div><div><br /></div><div><br /></div><div>이 밖에도 v4l-utils 패키지를 설치하면 <b>v4l2-ctl</b>(video4linux device를 제어하는 명령)이라는 명령을 사용할 수 있는데, 이를 통해 현재 v4l2 device가 무엇인지를 확인할 수 있다. </div><div><br /></div><div><b><font color="#f57c00">v4l2-ctl --list-devices</font></b> 명령을 실행하면 현재 video4linux device의 전체 목록을 확인할 수 있는데, 아래 그림에는 /dev/video0와 연결된 하나의 device 즉, <b>mmal service 16.1 (platform:bcm2835-v4l2)</b>가 보인다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBlo9jmlz0-oeH885mjbuFehiTR25qL71X7ACf4-OXu7fJCZmiF14YnugBT_AunbgqyjdqoFgRpf_KPQmmB5JqJX6LdxQE6Xk85Eu8K_sPWUeMf6EWYnKaGgP6RnvfMXXdkMfSW7sBII3I/s503/v4l2_ctrl1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="191" data-original-width="503" height="153" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBlo9jmlz0-oeH885mjbuFehiTR25qL71X7ACf4-OXu7fJCZmiF14YnugBT_AunbgqyjdqoFgRpf_KPQmmB5JqJX6LdxQE6Xk85Eu8K_sPWUeMf6EWYnKaGgP6RnvfMXXdkMfSW7sBII3I/w400-h153/v4l2_ctrl1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">[그림 3.6] v4l2-ctl 명령 (1)</div></div><div><br /></div><div>다음 내용은 vtl2-ctl를 사용하여 첫번째 device에 대한 driver 정보를 출력해 본 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUcvGghH1JciKcGakECbS2NCMYMNvfc2viEwlfz8cUfZX2pzysW8XEan-JknPYLGQNrn3QaSmj2RrI_i8g6IU2iZ8gxaPmr24iqcG8RiQ8L8HCbQknRdySJGjcX6CfuNtAGqisvib4VIow/s884/v4l2_ctl2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="884" data-original-width="604" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUcvGghH1JciKcGakECbS2NCMYMNvfc2viEwlfz8cUfZX2pzysW8XEan-JknPYLGQNrn3QaSmj2RrI_i8g6IU2iZ8gxaPmr24iqcG8RiQ8L8HCbQknRdySJGjcX6CfuNtAGqisvib4VIow/w274-h400/v4l2_ctl2.png" width="274" /></a></div><div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">[그림 3.7] v4l2-ctl 명령 (2)</div></div><div><br /></div></div><div><div>그렇다면, RPi 3에 구현되어 있는 V4L2 kernel driver는 어떤 것들이 있을까 ?</div><div>아래 명령은 현재 구동 중인 v4l2 관련 kernel module을 보여준다. 이중 특히 눈여겨 볼 부분은 <b><font color="#4285f4">bcm2835_v4l2</font></b>, <b><font color="#0b8043">bcm2835_mmal_vchiq</font></b> 등이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif_9SW6DCRtVvaDNWNDLzf_QiFHw31hkTw5lqBuMPJpKgajm842KeQrY4fMDuOCqFQlrPqO86MkHY9ftX3gUdBfSiuopLRAaLeq5iGYrK4_jbcEzHDD3sfVeCputaDM9mTp8SgEGfBeKte/s1051/rpi3_v4l2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="228" data-original-width="1051" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEif_9SW6DCRtVvaDNWNDLzf_QiFHw31hkTw5lqBuMPJpKgajm842KeQrY4fMDuOCqFQlrPqO86MkHY9ftX3gUdBfSiuopLRAaLeq5iGYrK4_jbcEzHDD3sfVeCputaDM9mTp8SgEGfBeKte/w640-h138/rpi3_v4l2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.8] v4l2 kernel module</div><div><br /></div><div><span style="background-color: #f7cb4d;"><b><여기서 잠깐 !></b></span></div><div><i> => bcm2835_v4l2 및 bcm2835 mmal_vchiq 등 관련 kernel code는 어디에 있을까 ?</i></div><div><i> => kernel에서 어디에 있는지를 찾는데, 위의 mmal이 힌트가 될 수 있다.</i></div><div><div>chyi@mars:~/workspace/Boards/RPi3B/linux/drivers$ <b>grep -rl mmal *</b></div><div><span style="color: #f57c00; font-size: small;">staging/vc04_services/vchiq-mmal/mmal-common.h</span></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-msg-common.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/Makefile</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-msg-port.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-vchiq.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-vchiq.c</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-msg.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-msg-format.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vchiq-mmal/mmal-parameters.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/Makefile</font></div><div><font color="#f57c00" size="2">staging/vc04_services/bcm2835-camera/bcm2835-camera.c</font></div><div><font color="#f57c00" size="2">staging/vc04_services/bcm2835-camera/controls.c</font></div><div><font color="#f57c00" size="2">staging/vc04_services/bcm2835-camera/bcm2835-camera.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/bcm2835-camera/Makefile</font></div><div><font color="#f57c00" size="2">staging/vc04_services/bcm2835-codec/bcm2835-v4l2-codec.c</font></div><div><font color="#f57c00" size="2">staging/vc04_services/vc-sm-cma/vc_sm.h</font></div><div><font color="#f57c00" size="2">staging/vc04_services/Kconfig</font></div></div><div>--------------</div></div><div><br /></div><div><div><div><b><font color="#0b8043" size="5">b) camera device driver</font></b></div><div>RPi 3는 재밌게도(?) 두가지의 BCM283x 용 camera driver를 제공 한다(단, 동시에 사용은 불가).</div><div><br /></div><div><b>1) drivers/media/platform/bcm2835 <=> </b><b>drivers/media/i2c/imx219.c</b></div></div><div><i> => 일명 Unicam driver(platform driver) <=> imx219 camera sensor driver</i></div><div><i> => broadcom VideoCore랑은 상관 없이 동작. 즉 MIPI CSI-2로 부터 직접 data를 읽어와 SDRAM에 저장</i></div><div><i> => device tree 내용도 별도로 정리되어 있음.</i></div><div><i> --> SoC internal IP block: <span style="text-align: center;">Documentation/devicetree/bindings/media/</span>bcm2835-unicam.txt</i></div><div><i> --> camera sensor: Documentation/devicetree/bindings/media/i2c/imx219.txt 참조 요망</i></div><div><i> => GPU의 다양한 기능을 사용하지 않고, CPU에서 바로 처리하는 방식(느림).</i></div><div><br /></div><div><b>2) <font color="#7b1fa2">drivers/staging/vc04_services/bcm2835-camera</font></b></div><div><i> => broadcom VideoCore를 이용하는 방식(빠름).</i></div><div><i> => VideoCore firmware(VCOS라는 RTOS)는 부팅시 device tree 내용을 확인하여 csi0 or csi1에 대한 active node 정보가 존재하지 않을 경우에만, 동작하도록 함.</i></div><div><i> => imx219 camera sensor에 대한 driver 역시 VCOS에 포함되어 있을 것으로 예상됨.</i></div><div><i><font color="#b51200"><br /></font></i></div><div>그렇다면, 이 둘 중 현재 어떤 녀석이 사용되고 있는 것일까 ?</div><div><br /></div><div>먼저, kernel booting message를 확인해 보면, <b><font color="#7b1fa2">bcm2835-camera 드라이버(실제 driver 이름은 bcm2835-v4l2)</font></b> 즉, 두번째 녀석이 사용되는 듯 보인다. 보다 정확한 내용 확인을 위해 device tree가 enable되어 있는지를 확인해 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJCd3KSq62mQJelYuOUXa6OjK-aPSGe38PPggXs2WgwrEgWAHUwfWd5JCtCMP_ha171I0OyG1QZj4PFKaC3kowot0ZXLqSqG3quoj8RUgNf_p85GSloISskV3_wpVc6YKQwNBgBmBy1JBf/s1164/rpi3_dmesg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="1164" height="149" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJCd3KSq62mQJelYuOUXa6OjK-aPSGe38PPggXs2WgwrEgWAHUwfWd5JCtCMP_ha171I0OyG1QZj4PFKaC3kowot0ZXLqSqG3quoj8RUgNf_p85GSloISskV3_wpVc6YKQwNBgBmBy1JBf/w400-h149/rpi3_dmesg.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.9] Kernel dmesg</div><div><br /></div><div><b><font color="#0b8043" size="5">c) camera device tree 분석</font></b></div><div>RPi 3에서 현재 동작 중인 device tree 내용을 확인해 보도록 하자.</div><div><br /></div><div><div>pi@raspberrypi:~$ sudo apt-get install device-tree-compiler</div><div>pi@raspberrypi:~$ <b>dtc -I fs -O dts /sys/firmware/devicetree/base</b> > ~/workspace/rpi3.dts</div></div><div><br /></div><div><span style="text-align: center;">이 상태에서 rpi3.dts 파일을 열어 보면, </span><span style="text-align: center;"> </span><span style="text-align: center;">csi0(7e800000), cs1(7e801000) </span><span style="text-align: center;">controller의</span><span style="text-align: center;"> status 값이 둘다 disabled되어 있음을 알 수 있다. 즉, 현재 linux kernel 상에서는 사용하지 않는다는 뜻이다.</span></div><div><span style="text-align: center;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcy4N4v4FpRa9k0MKMmFWsatyZ2Sdj5e0haxtdp-EX0f4ZE1FubW6ik-AI7iT9zW9SHK4XKhO1uQ6UmTzqfD-OjgPSKZBIy0TZq4oIsYuabglHhmNABd4Gg2MMtt3PYBxJoRCvIy8gJqYI/s495/rpi_unicam_disabled.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="258" data-original-width="495" height="209" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcy4N4v4FpRa9k0MKMmFWsatyZ2Sdj5e0haxtdp-EX0f4ZE1FubW6ik-AI7iT9zW9SHK4XKhO1uQ6UmTzqfD-OjgPSKZBIy0TZq4oIsYuabglHhmNABd4Gg2MMtt3PYBxJoRCvIy8gJqYI/w400-h209/rpi_unicam_disabled.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhnV0Dq-kmvJiq9knQXdraUkjoQvUC_7wZ1LZ0eKDvPJHbAEg9LHcowHUDWmELXA2IgMrQPUPbxjcMu5k-LvmwOvo-XVFm7cpNZr2UIpfKmvHOwyJWH4V66qDIvCI3kDsxTuZEZcG6MTyC/s492/rpi_unicam_disabled2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="384" data-original-width="492" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhnV0Dq-kmvJiq9knQXdraUkjoQvUC_7wZ1LZ0eKDvPJHbAEg9LHcowHUDWmELXA2IgMrQPUPbxjcMu5k-LvmwOvo-XVFm7cpNZr2UIpfKmvHOwyJWH4V66qDIvCI3kDsxTuZEZcG6MTyC/s320/rpi_unicam_disabled2.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.10] csi (controller) device tree 내용 중 csi controller 내용 발췌</div><div><br /></div><div>다음으로 imx219 camera sensor에 대한 MIPI CSI-2용 device tree node를 살펴 본 결과, 앞서 추출한 device tree 내용에는 관련 내용이 어디에도 보이질 않는다.</div><div><br /></div><div style="text-align: center;"><b>arch/arm/boot/dts/overlays/imx219-overlay.dts</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpCJlgvUxUIRn0ZPmku399kOVbbKdLPKbx9ApMUzKLJyCgJE-WrzTI5dmxmLs62Y26yJdiXmskX6W5TKYwU7E6nHvd_DTrqFiTKJLs_fEtGMHho3aPKE3AUmn2yoJlMYkZgeoBKMv-jnrB/s931/mx219_overlay_fragment.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="931" data-original-width="557" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpCJlgvUxUIRn0ZPmku399kOVbbKdLPKbx9ApMUzKLJyCgJE-WrzTI5dmxmLs62Y26yJdiXmskX6W5TKYwU7E6nHvd_DTrqFiTKJLs_fEtGMHho3aPKE3AUmn2yoJlMYkZgeoBKMv-jnrB/w239-h400/mx219_overlay_fragment.png" width="239" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.11] imx219 camera sensor에 대한 device tree overlay 내용</div><div><font color="#b51200" size="2"><br /></font></div><div><font color="#b51200" size="2">[Tip] 뒤에서 다시 설명하겠지만, 아래 두 부분이 서로를 연결(MIPI CSI-2)해 주고 있다.</font></div><div><br /></div><div><font size="2"><b><fragment@0 : i2c controller & device></b></font></div><div><div><font size="2"> port {</font></div><div><font size="2"> <b><font color="#3367d6"> imx219_0</font></b>: endpoint {</font></div><div><font size="2"> remote-endpoint = <b><font color="#b51200"><&csi1_ep>;</font></b></font></div><div><font size="2"> clock-lanes = <0>;</font></div><div><font size="2"> data-lanes = <1 2>;</font></div><div><font size="2"> clock-noncontinuous;</font></div><div><font size="2"> link-frequencies =</font></div><div><font size="2"> /bits/ 64 <297000000>;</font></div><div><font size="2"> };</font></div><div><font size="2"> };</font></div></div><div><font size="2"><br /></font></div><div><font size="2"><b><fragment@1: cs1 controller></b></font></div><div><div><font size="2"> port {</font></div><div><font size="2"> <b><font color="#b51200">csi1_ep</font></b>: endpoint {</font></div><div><font size="2"> remote-endpoint = <b><font color="#3367d6"><&imx219_0></font></b>;</font></div><div><font size="2"> };</font></div><div><font size="2"> };</font></div></div><div>-------------------</div><div><br /></div><div>따라서 이상의 두가지 내용(dmesg, device tree 내용)으로 미루어 볼 때, <b><font color="#7b1fa2">drivers/staging/vc04_services/bcm2835-camera</font></b> 드라이버가 사용되는 것이 확실하다고 말할 수 있다.</div><div><br /></div></div><div><b style="background-color: #f7cb4d;"><여기서 잠깐 !></b></div><div><i> => video receiver and transmitter interface(MIPI CSI-2, parallel interface 등)를 위한 device tree 작성과 관련하여 ...</i></div><div><br /></div><div>이 부분은 생각보다 좀 복잡해 보이는데, 우선 아래 두가지 파일을 면밀히 검토할 필요가 있어 보인다.</div><div><br /></div><div style="text-align: center;"><b>Documentation/devicetree/bindings/media/video-interfaces.txt</b></div><div style="text-align: center;"><b>Documentation/devicetree/bindings/media/</b><span style="text-align: left;"><b>bcm2835-unicam.txt</b></span></div><div><br /></div><div>먼저, Video receiver & transmitter interface를 위한 device tree(controller node)는 일반적으로 아래와 같은 형식으로 작성해야 한다. 내용을 보니 ports, port@0, port@1, endpoint 등 그 동안 보지 못했던 표현들이 눈에 들어온다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho2zTTF1Mg1Dtilser5x2xNe1t2_z88ELduKfvBeLfioemp4dah51fFm_SRS2UL-o1mAUiX88FSgX9ecrmBSzLIUHN0jYMobQqg-RjsHD_CYJOr-t-debWavqSh9I1zQsjr59s4dhEAoIn/s309/video_interface_dt.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="270" data-original-width="309" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho2zTTF1Mg1Dtilser5x2xNe1t2_z88ELduKfvBeLfioemp4dah51fFm_SRS2UL-o1mAUiX88FSgX9ecrmBSzLIUHN0jYMobQqg-RjsHD_CYJOr-t-debWavqSh9I1zQsjr59s4dhEAoIn/" /></a></div><div class="separator" style="clear: both; text-align: center;"><b><span style="text-align: left;"><</span><span style="text-align: left;">video-interfaces.txt></span></b></div><div><br /></div><div>구체적인 예(두번째 파일)를 하나 들어 보도록 하자. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXmZcSrNiYskOLmnapiNC4RiaIf3HDMhv73lG-EO6IruThj5s4fuSiCtAMaoOnhOkeEv3lBWMy5K9UPBF7E9RLmoiZCEpSwI4dPIU0gBQDJgecAizt8jf4MFetwZxnYr3nsqUrxFbMssdN/s760/csi2_uncam.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="760" data-original-width="426" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXmZcSrNiYskOLmnapiNC4RiaIf3HDMhv73lG-EO6IruThj5s4fuSiCtAMaoOnhOkeEv3lBWMy5K9UPBF7E9RLmoiZCEpSwI4dPIU0gBQDJgecAizt8jf4MFetwZxnYr3nsqUrxFbMssdN/w358-h640/csi2_uncam.png" width="358" /></a></div><div class="separator" style="clear: both; text-align: center;"><controller: bcm2835-unicam.txt></div><div><div style="text-align: center;"><b><br /></b></div><div style="text-align: center;"><b>cs1 controller(bcm2835-unicam) <== MIPI CSI-2 bus ==> tc358734(HDMI device)</b></div><div style="text-align: center;"><b>i2c0 controller <== i2c0 bus ==> tc358734(HDMI device)</b></div><div style="text-align: center;"><br /></div><div style="text-align: justify;"><span style="text-align: left;">위의 내용에는 앞서 설명한 imx219 camera sensor 대신 tc358743 hdmi device가 예제로 소개되고 있다.</span></div><div style="text-align: justify;"><span style="text-align: left;">이 중 눈여겨 볼 부분은 <b><font color="#7b1fa2">cs1 controller port node의 child endpoint 정보는 tc358743_0 노드(i2c0 controller의 child node 내에 표현되어 있음)를 가리키고 있으며, i2c0 controller의 child node 즉, tc358734 device의 endpoint는 반대로 cs1_ep node를 가리키고 있는 대목</font></b>이라 말할 수 있다.</span></div><div><br /></div><div><b><csi1 controller></b></div><div><div><b><font color="#3367d6">csi1_ep</font></b>: endpoint {</div><div> <b style="color: #b51200;">remote-endpoint = <&tc358743_0>; </b>/* 아래 tc358743_0 node를 가리킴 */</div><div> data-lanes = <1 2>;</div><div>};</div></div><div><br /></div><div><b><cs1 device, i20 device></b></div><div><div><b><font color="#b51200">tc358743_0</font></b>: endpoint {</div><div> <font color="#4285f4" style="font-weight: bold;">remote-endpoint = <&csi1_ep>; </font>/* 위의 csi1_ep node를 가리킴 */</div><div> clock-lanes = <0>;</div><div> data-lanes = <1 2>;</div><div> clock-noncontinuous;</div><div> link-frequencies =</div><div> /bits/ 64 <297000000>;</div><div>};</div></div><div><br /></div><div>물론, 그 밖에도 MIPI CSI-2 interface를 표현하기 위해 clock-lanes, data-lanes 등의 property가 추가된 부분도 중요하다고 하겠다.</div><div>-------------------</div></div><div><br /></div><div><b><font color="#0b8043" size="5">d) VideoCore IV GPU</font></b></div><div>앞 절에서 이미 언급했던 MMAL은 과연 무엇일까 ? 이절에서는 MIPI CSI-2 interface의 host(application processor) 쪽 endpoint인 VideCore IV GPU와 이를 Linux에서 이용하기 위한 MMAL interface에 관하여 살펴 보기로 하겠다.</div><div><br /></div><div>아래 두개의 그림은 RPi 3 Camera 동작과 관련한 전체 구조를 아주 쉽게 표현해 주고 있다.</div><div><br /></div><div style="text-align: center;"><b>Linux(myscript.py -> picamera -> MMAL) => VCHI => VideoCore IV GPU(VCOS) => MIPI CSI2 bus => Camera sensor</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf5dYLjmt3Pa08qkQANxIC3_OM5reI_YjGp6XLSuiiUNtjsr8hjUHFpKAIA5Y7WOAU9Jmxqg0WIoHeNH0aCg4fiGK3UVq9008rdIDc6_P_wMsvFNETXhStL5VqckS7uGf8YaJP_r4eV_Sc/s622/bcm2835_videocore_gpu.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="622" data-original-width="558" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf5dYLjmt3Pa08qkQANxIC3_OM5reI_YjGp6XLSuiiUNtjsr8hjUHFpKAIA5Y7WOAU9Jmxqg0WIoHeNH0aCg4fiGK3UVq9008rdIDc6_P_wMsvFNETXhStL5VqckS7uGf8YaJP_r4eV_Sc/s320/bcm2835_videocore_gpu.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.12] BCM2835 SoC 내의 VideoCore IV GPU 동작 원리 1 <b>[참고문헌 6]</b></div><div><font color="#b51200" size="2">[Tip] 위의 그림은 Pi camera python project에서 발췌한 것이다. 그림 내용 중 picamera library는 MMAL API를 사용하여 VideoCore firmware(VCOS)와 통신한다.</font></div><div><br /></div><div><span style="background-color: #f7cb4d;"><동작 원리></span></div><div><i><font size="2"> => 원문의 내용을 그대로 전달하는 편이 이해하는데 도움이 될 듯하여, 아래 site에서 원문을 그대로 옮겼다.</font></i></div><div><i><font size="2"> => <a href="https://picamera.readthedocs.io/en/release-1.13/fov.html#">https://picamera.readthedocs.io/en/release-1.13/fov.html#</a></font></i></div><div><br /></div><div><ol class="arabic simple" style="background-color: #fcfcfc; box-sizing: border-box; color: #404040; font-size: 16px; line-height: 24px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 24px; padding: 0px;"><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">The camera’s sensor has been configured and is continually streaming frame lines over the CSI-2 interface to the GPU.</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">The GPU is assembling complete frame buffers from these lines and performing post-processing on these buffers (we’ll go into further detail about this part in the next section).</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">Meanwhile, over on the CPU, <code class="docutils literal notranslate" style="background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); box-sizing: border-box; color: #e74c3c; font-size: 12px; max-width: 100%; overflow-x: auto; padding: 2px 5px; white-space: nowrap;"><span class="pre" style="box-sizing: border-box;">myscript.py</span></code> makes a <code class="docutils literal notranslate" style="background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); box-sizing: border-box; color: #e74c3c; font-size: 12px; max-width: 100%; overflow-x: auto; padding: 2px 5px; white-space: nowrap;"><span class="pre" style="box-sizing: border-box;">capture</span></code> call using picamera.</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">The picamera library in turn uses the MMAL API to enact this request (actually there’s quite a lot of MMAL calls that go on here but for the sake of simplicity we represent all this with a single arrow).</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">The MMAL API sends a message over VCHI requesting a frame capture (again, in reality there’s a lot more activity than a single message).</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">In response, the GPU initiates a <a class="reference external" href="https://en.wikipedia.org/wiki/Direct_memory_access" style="box-sizing: border-box; color: #9b59b6; cursor: pointer; text-decoration-line: none;">DMA</a> transfer of the next complete frame from its portion of RAM to the CPU’s portion.</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">Finally, the GPU sends a message back over VCHI that the capture is complete.</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">This causes an MMAL thread to fire a callback in the picamera library, which in turn retrieves the frame (in reality, this requires more MMAL and VCHI activity).</li><li style="box-sizing: border-box; list-style: decimal; margin-left: 24px;">Finally, picamera calls <code class="docutils literal notranslate" style="background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); box-sizing: border-box; color: #e74c3c; font-size: 12px; max-width: 100%; overflow-x: auto; padding: 2px 5px; white-space: nowrap;"><span class="pre" style="box-sizing: border-box;">write</span></code> on the output object provided by <code class="docutils literal notranslate" style="background: rgb(255, 255, 255); border: 1px solid rgb(225, 228, 229); box-sizing: border-box; color: #e74c3c; font-size: 12px; max-width: 100%; overflow-x: auto; padding: 2px 5px; white-space: nowrap;"><span class="pre" style="box-sizing: border-box;">myscript.py</span></code>.</li></ol></div><div><br /></div><div style="text-align: center;"> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbCfBs-6Fyd7qqzUrg4_JAeLOd8HgxdpWXwOh60uL4yOWtamQY17PmoSYA8UK7hmxctoz4bltRN05ubciGYsCSGqlshEl4BeG9r2UerKtrb39oOgRH2d-l4X1fRu6uZocxvjVbjT0iMEmx/s626/rpi_gpu.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="626" data-original-width="516" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbCfBs-6Fyd7qqzUrg4_JAeLOd8HgxdpWXwOh60uL4yOWtamQY17PmoSYA8UK7hmxctoz4bltRN05ubciGYsCSGqlshEl4BeG9r2UerKtrb39oOgRH2d-l4X1fRu6uZocxvjVbjT0iMEmx/w330-h400/rpi_gpu.png" width="330" /></a></div><div style="text-align: center;">[그림 3.13] BCM2835 SoC 내의 VideoCore IV GPU 동작 원리 2 <b>[참고문헌 6]</b></div><div><br /></div><div><div><br /></div></div><div><div><b><font color="#0b8043" size="5">e) bcm2835_v4l2 driver</font></b></div><div>끝으로 bcm2835_v4l2 driver의 초기화 부분을 capture하는 것으로 이장을 정리할까 한다. 드라이버에 대한 상세 코드 분석은 독자 여러분의 몫으로 남긴다. 😙</div></div><div><br /></div><div style="text-align: center;"><b>drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB-kBNqV4UjVU-Zs8nrdjecSZX3PSnK26-EXIsCg58I2V9SCjmCLRswbjalJp8h9g71J-lnWRzofjDXIEJGUfkpGL7PvRswiCL1VhoA1RHpEKIVjtamrMDVpQb4fzRct4kydDcPsxGvFQ-/s517/bcm2835_v4l2_main1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="301" data-original-width="517" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB-kBNqV4UjVU-Zs8nrdjecSZX3PSnK26-EXIsCg58I2V9SCjmCLRswbjalJp8h9g71J-lnWRzofjDXIEJGUfkpGL7PvRswiCL1VhoA1RHpEKIVjtamrMDVpQb4fzRct4kydDcPsxGvFQ-/s320/bcm2835_v4l2_main1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG_S2wlY5-cx2ilJZclP4xnJIX_O14PoBLkNWNHzz5oWdu3pikkwwb6JDhk6qXcrz99I96LHMG-MMm18tKVmDBRFjsNG-9aUt2c5GWc5qDi63rNdA3B8CDtaW7MbE49WPBsUCS506Am4Dt/s879/bcm2835_v4l2_main2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="879" data-original-width="675" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG_S2wlY5-cx2ilJZclP4xnJIX_O14PoBLkNWNHzz5oWdu3pikkwwb6JDhk6qXcrz99I96LHMG-MMm18tKVmDBRFjsNG-9aUt2c5GWc5qDi63rNdA3B8CDtaW7MbE49WPBsUCS506Am4Dt/s320/bcm2835_v4l2_main2.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.14] <span style="text-align: left;">bcm2835_v4l2 driver의 초기화 부분</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div>-----------</div><div><br /></div><div><i>이번 blog post의 처음 취지는 <font color="#0b8043">MIPI CSI-2를 알아본 후, 이를 사용하는 linux camera device driver(platform driver <=> sensor driver, device tree)를 분석</font>해 보는데 있었다. 하지만, 내용을 살펴본 결과 뜻하지 않게 linux camera device driver 관련 부분은 사용되지 않고, 모든 기능은 GPU 상의 VCOS에서 처리되고 있었으며, linux kernel에서는 이와의 interface(MMAL interface)용 driver만이 사용되고 있었다. 😂</i></div><div><br /></div><div><i>(좀 아쉽지만) 이상으로 RPi 3 보드 상에서 Pi Camera와 관련 Camera S/W가 어떻게 동작하는지를 대략적으로 살펴 보았다. 늘 느끼는 거지만, 당초 계획했던 것 보다 최종 결과물이 항상 뭔가 2% 부족한 것 같다. 다음 번에는 보다 수준 높은 내용을 선보일 것을 약속드리며, 이번 posting을 마치고자 한다. 끝까지 읽어 주신 독자 여러분께 감사의 마음을 전한다. </i>😎</div></div><div><br /></div><div><br /></div><div><div><b><font color="#b45f06" size="6">4. Raspberry Pi 4와 Pi Camera</font></b></div><div><span style="color: #b45f06;"><i>[나중에 정리한 내용임]최근에 Raspberry Pi 4 B 보드를 하나 입수했다. Camera 관련 동작 방식에도 많은 변화가 있는 듯하다. (다른 일로 바쁜 관계로) 간략하게나마 Pi4에서의 Camera 영상 출력 시험을 해보기로 한다.</i></span></div></div><div><div><br /></div><div>얼마 전에 여러가지 면에서 성능이 향상된 <a href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/">Raspberry Pi 4 B</a>가 출시된 바 있다. 이번 장에서는 Pi 4와 Pi Camera를 사용하는 방법을 간략히 소개해 보고자 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4LtEC-McpPeaIQqIDp-1RZ79lyJXCkKNmxzQCZOIzFOH9_pkLSyZdaS85uFKz_ga-lzRaQrIi37XFWTJAi66lDj4VuqAoF9fPDDCif7-Qv486sGG2-C5kbWVOAIe3ej6xEikSztvuTQ5E/s619/rpi4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="394" data-original-width="619" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4LtEC-McpPeaIQqIDp-1RZ79lyJXCkKNmxzQCZOIzFOH9_pkLSyZdaS85uFKz_ga-lzRaQrIi37XFWTJAi66lDj4VuqAoF9fPDDCif7-Qv486sGG2-C5kbWVOAIe3ej6xEikSztvuTQ5E/s320/rpi4.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.1] Raspberry Pi 4 Model B</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQd-cn6AQON5aonknvZ82Md8qKyAgbwALtBvOn_xMhT7sqFl71RACjmrBt3m3FfI4LgsZaIX9bRe0vAyXSGBTaYzdG4hIdiFWpUIo4s9CNKgNPC4JfO5WUgi7CHS3cvf0b4nUldzX5uy4h/s614/rpi4_spec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="607" data-original-width="614" height="395" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQd-cn6AQON5aonknvZ82Md8qKyAgbwALtBvOn_xMhT7sqFl71RACjmrBt3m3FfI4LgsZaIX9bRe0vAyXSGBTaYzdG4hIdiFWpUIo4s9CNKgNPC4JfO5WUgi7CHS3cvf0b4nUldzX5uy4h/w400-h395/rpi4_spec.png" width="400" /></a></div><div><br /></div><div>Raspberry Pi 4의 h/w적인 변화 못지 않게, Pi OS도 그동안 많은 변화를 거쳐왔다.</div><div><br /></div><div><div><b style="background-color: #b7e1cd;"><br class="Apple-interchange-newline" /><에필로그></b></div><div><font size="2">내용을 정리하다 보니, linux media community(핵심 개발자: Laurent Pinchart)를 중심으로 (현재까지) 매우 복잡한 시스템인 camera를 보다 효율적으로 관리/제어하기 위해 <a href="https://libcamera.org/">libcamera</a>라는 project가 최근(2018)에 결성되었고, Raspberry Pi 진영에서도 이를 기반으로 camera s/w를 porting하는 작업이 진행되었다고 한다. libcamera project가 목표로 하는 대상은 linux, android, chromOS 등이다. 관심있는 분들은 아래 내용을 참고하시기 바란다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlOHM2kT9Dk-mUUEvfzfWT_VwglMvq1w0T987OSqkI1fplvjif6hBU29kUPf8XclkvqPJlGK8l5GBH15Tv875_xPuuNVjTWYek_Kg4cBWBz0N0fSIuoWCg0g45cCmcBav9FeDLiiqYZhyphenhyphenD/s1499/libcamera.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="962" data-original-width="1499" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlOHM2kT9Dk-mUUEvfzfWT_VwglMvq1w0T987OSqkI1fplvjif6hBU29kUPf8XclkvqPJlGK8l5GBH15Tv875_xPuuNVjTWYek_Kg4cBWBz0N0fSIuoWCg0g45cCmcBav9FeDLiiqYZhyphenhyphenD/s320/libcamera.png" width="320" /></a></div><div><br /></div><div><div style="text-align: center;"><a href="https://www.raspberrypi.org/blog/an-open-source-camera-stack-for-raspberry-pi-using-libcamera/"><font size="2">https://www.raspberrypi.org/blog/an-open-source-camera-stack-for-raspberry-pi-using-libcamera/</font></a></div><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtyGy9_UDViPw37PHkqxpQK3BrMcePNuQim5az1Gfwg1Dj-J8nj9_Ac2RI6s1Wdmh9pFDYU_6GDIBtixOQSvbov5GLXxCbBKo9Keu6WvSA6PoaaoeJSI1Js2iS958CSht5-J63W4JBVU79/s500/Libcamera-Diagrams-01-500x334.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="334" data-original-width="500" height="268" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtyGy9_UDViPw37PHkqxpQK3BrMcePNuQim5az1Gfwg1Dj-J8nj9_Ac2RI6s1Wdmh9pFDYU_6GDIBtixOQSvbov5GLXxCbBKo9Keu6WvSA6PoaaoeJSI1Js2iS958CSht5-J63W4JBVU79/w400-h268/Libcamera-Diagrams-01-500x334.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.2] libcamera project</span></div><div>---------------</div></div><div><br /></div><div>먼저 Raspi OS bullseye를 설치한 후, libcamera app(아래 site 참조)을 이용하여 camera 영상을 출력해 보도록 하자.</div><div><br /></div><div style="text-align: center;"><a href="https://github.com/raspberrypi/libcamera-apps">https://github.com/raspberrypi/libcamera-apps</a></div><div><br /></div><div><br /></div><div><b><span style="color: #6aa84f;"><Ubuntu 18.04 PC></span></b></div><div>$ <b>sudo dd if=./2022-01-28-raspios-bullseye-armhf-lite.img of=/dev/sdc bs=4M conv=fsync status=progress</b></div><div><div><span style="font-size: x-small;">479+0 레코드 들어옴</span></div><div><span style="font-size: x-small;">479+0 레코드 나감</span></div><div><span style="font-size: x-small;">2009071616 bytes (2.0 GB, 1.9 GiB) copied, 136.377 s, 14.7 MB/s</span></div></div><div><br /></div><div>$ cd /media/chyi/boot</div><div>$ <b>sudo vi /boot/config.txt</b></div></div><div>...</div><div><b>enable_uart=1</b> #Serial console 출력을 위해 옆의 한 줄을 추가해 주도록 한다.</div><div>~</div><div><br /></div><div>microSD 카드를 RPi4 board에 장착 후, 부팅을 시도해 본다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgu9JZPbrwNDXNIriZELsOjQ0rbz5p2BWu0gaV_sSl0cfIMw9JrrJ_9ybyPX9kQTKG9xxqu4wN0dN03qtgqBZcSV17PNAD8Is55Qp8AoUehhn1brZLN8tMLDY-A8Eg8UwZg3o9BjljffjNyqbWZWp-mjFVrp0jA3ZgQgSOkPw7ydhnHIMOH_U_fsoGIzQ=s959" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="746" data-original-width="959" height="311" src="https://blogger.googleusercontent.com/img/a/AVvXsEgu9JZPbrwNDXNIriZELsOjQ0rbz5p2BWu0gaV_sSl0cfIMw9JrrJ_9ybyPX9kQTKG9xxqu4wN0dN03qtgqBZcSV17PNAD8Is55Qp8AoUehhn1brZLN8tMLDY-A8Eg8UwZg3o9BjljffjNyqbWZWp-mjFVrp0jA3ZgQgSOkPw7ydhnHIMOH_U_fsoGIzQ=w400-h311" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.3] RPi4 부팅 모습(minicom)</span></div><br /><div>$ <b>sudo raspi-config</b></div><div><i> => ssh를 enable 하고, update 메뉴를 선택한다.</i></div><div><i> => 주의: legacy pi camera 메뉴는 enable해 주어서는 안된다(motion daemon 등을 사용하고자 하는 경우 선택).</i></div><div><br /></div><div>마지막으로 아래 명령을 실행하여 camera에서 찍은 영상을 stream 형태로 출력하도록 하자.</div><div>$ <b>libcamera-vid -t 0 --width 1280 --height 720 --codec h264 --vflip -n -l -o tcp://0.0.0.0:5001 &</b></div><div><span style="color: #b51200; font-size: x-small;">[Tip1] 1장에서 사용했던 motion 및 mjpg-streamer는 RaspiOS bullseye에서는 제대로 동작하지 않는다(실제로는 raspi-config에서 Legacy Camera를 enable하면 동작하기는 한다. 단, 완벽하게 동작하지는 않는다.)</span></div><div><span style="color: #b51200; font-size: x-small;">[Tip2] --vflip option을 지정하면 영상이 반대로 뒤집혀 출력된다.</span></div><div><br /></div><div>영상이 제대로 출력되고 있는지, VLC를 통해 확인해 보도록 하자.</div><div><br /></div><div style="text-align: center;"><b><span style="color: #38761d;">VLC 미디어 메뉴 => 네트워크 스트림 열기 => tcp/h264://192.168.8.161:5001 입력</span></b></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgvKvBh-7oWLeDm8Zr4JGsH2cKNAU0w1spfK-14QWplfIgMII_c2nB4CywDF-OA2TkxHfnMCF_4jBNcjIRg133BtJ2zcOPADrMffrsffhgDbL8L0uE3PoglPESGRQ1Yl7f4jrgg_TsLo8lh0O8mKKPsifUNHWamB9Ljw2alWYV0GBuvqoQ80a4n-asGFw=s1141" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="698" data-original-width="1141" height="245" src="https://blogger.googleusercontent.com/img/a/AVvXsEgvKvBh-7oWLeDm8Zr4JGsH2cKNAU0w1spfK-14QWplfIgMII_c2nB4CywDF-OA2TkxHfnMCF_4jBNcjIRg133BtJ2zcOPADrMffrsffhgDbL8L0uE3PoglPESGRQ1Yl7f4jrgg_TsLo8lh0O8mKKPsifUNHWamB9Ljw2alWYV0GBuvqoQ80a4n-asGFw=w400-h245" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.4] Ubuntu 18.04에서 VLC 실행 모습(1)</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEixCk88gG_I0055g-I8EQVhyOd4NjnZpWA8U0G79snAyRVEmEg_KViN0LC6D9d5sCUF2FnjqyE3CXzNkOXi7zok5jlsKjaaVazH4hrjKyzr0mAc4ncktTOc-ftGmtn4YxOXwclf7dbhQy3vOU8T9pC_ykXXaZdLecib0LgV00q7sd8gtkZLTa_PIPwC1Q=s1280" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="825" data-original-width="1280" height="206" src="https://blogger.googleusercontent.com/img/a/AVvXsEixCk88gG_I0055g-I8EQVhyOd4NjnZpWA8U0G79snAyRVEmEg_KViN0LC6D9d5sCUF2FnjqyE3CXzNkOXi7zok5jlsKjaaVazH4hrjKyzr0mAc4ncktTOc-ftGmtn4YxOXwclf7dbhQy3vOU8T9pC_ykXXaZdLecib0LgV00q7sd8gtkZLTa_PIPwC1Q=s320" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.5] Ubuntu 18.04에서 VLC 실행 모습(2)</span></div><div><br /></div>참고로, 아래 site의 내용을 잘 살펴 보면, RTSP를 이용하여 영상을 송출하고, VLC를 통해 확인하는 방법도 테스트해 볼 수 있다.</div><div><br /></div><div style="text-align: center;"><a href="https://www.raspberrypi.com/documentation/accessories/camera.html#getting-started">https://www.raspberrypi.com/documentation/accessories/camera.html#getting-started</a></div><div style="text-align: center;"><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><span style="color: #38761d;"><RPi4></span></b></div><div style="text-align: left;">$ <b>sudo apt-get install cvlc</b></div><div style="text-align: left;">$ <b>libcamera-vid -t 0 --inline -o - | cvlc stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554/stream1}' :demux=h264</b></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><span style="color: #38761d;"><PC VLC></span></b></div><div style="text-align: left;"><b>rtsp://192.168.8.194:8554/stream1</b></div></div><div><div style="text-align: left;"><br /></div><div style="text-align: left;">-------------</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">5. References</font></b></div><div>[1] <a href="https://linuxtv.org/downloads/v4l-dvb-apis/">https://linuxtv.org/downloads/v4l-dvb-apis</a><a href="https://linuxtv.org/downloads/v4l-dvb-apis/">/</a></div></div><div>[2] <a href="https://wiki.st.com/stm32mpu/wiki/V4L2_camera_overview">https://wiki.st.com/stm32mpu/wiki/V4L2_camera_overview</a></div><div>[3] <a href="https://bootlin.com/pub/conferences/2016/elce/ripard-v4l/ripard-v4l.pdf">https://bootlin.com/pub/conferences/2016/elce/ripard-v4l/ripard-v4l.pdf</a></div><div><i> => V4L2 subsystem</i></div><div>[4] <a href="https://www.raspberrypi.org/documentation/hardware/camera/">https://www.raspberrypi.org/documentation/hardware/camera/</a></div><div>[5] <a href="https://publiclab.org/system/images/photos/000/023/294/original/RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF">https://publiclab.org/system/images/photos/000/023/294/original/RASPBERRY_PI_CAMERA_V2_DATASHEET_IMX219PQH5_7.0.0_Datasheet_XXX.PDF</a></div><div>[6] <a href="https://picamera.readthedocs.io/en/release-1.13/fov.html#">https://picamera.readthedocs.io/en/release-1.13/fov.html#</a></div><div><i> => Pi Camera</i></div><div>[7] Camera Serial Interface_CSI2_CSI3_Overview.pdf, mipi alliance</div><div><i> => mipi CSI</i></div><div>[8] <a href="https://www.raspberrypi.org/documentation/configuration/device-tree.md">https://www.raspberrypi.org/documentation/configuration/device-tree.md</a></div><div><i> => device tree and overlay</i></div><div>[9] <a href="https://www.raspberrypi.org/documentation/linux/kernel/building.md">https://www.raspberrypi.org/documentation/linux/kernel/building.md</a></div><div><i> => RPi kernel build</i></div><div>[10] <a href="https://learn.adafruit.com/adafruits-raspberry-pi-lesson-5-using-a-console-cable/enabling-serial-console">https://learn.adafruit.com/adafruits-raspberry-pi-lesson-5-using-a-console-cable/enabling-serial-console</a></div><div> <i> => misc.</i></div><div>[11] <a href="https://www.techdesignforums.com/practice/technique/advantages-of-mipi-specifications-in-mobile-automotive-and-multimedia-applications/">https://www.techdesignforums.com/practice/technique/advantages-of-mipi-specifications-in-mobile-automotive-and-multimedia-applications/</a></div><div>[12] <a href="https://www.nxp.com/docs/en/application-note/AN5305.pdf">https://www.nxp.com/docs/en/application-note/AN5305.pdf</a></div><div>[13] <a href="https://stackoverflow.com/questions/56731704/where-does-linux-call-a-camera-driver-for-image-delivery">https://stackoverflow.com/questions/56731704/where-does-linux-call-a-camera-driver-for-image-delivery</a></div><div>[14] <a href="https://yannik520.github.io/v4l2_framework.html">https://yannik520.github.io/v4l2_framework.html</a></div><div>[15] <a href="https://www.arducam.com/docs/cameras-for-raspberry-pi/raspberry-pi-libcamera-guide/">https://www.arducam.com/docs/cameras-for-raspberry-pi/raspberry-pi-libcamera-guide/</a></div><div><br /></div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div><div><br /></div><div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com2tag:blogger.com,1999:blog-6346200245600677355.post-17392873363899996802020-06-22T16:59:00.001+09:002020-07-16T10:11:18.220+09:00Linux Device Drivers for Embedded Processors 에피소드 3 - STM32MP157C Discovery Kit 소개(6)지난 시간에 이어 <b>STM32MP157C Discovery Kit</b> 분석, 여섯번 째 시간이다. 😊<div><br /></div><div>이번 시간에는 이제까지 살펴 보지 않았던 <b><font color="#9c27b0">Cortex-M4 환경에서의 ST firmware 개발</font></b>과 관련한 내용을 <b>간략히</b> 소개해 보고자 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY34ySk_uOjykUH0MWUZw4jSy1nvn94vycwU88gesfJUTYtwyvK87_oURIrxrg4TbDAbYSb2fuCFSwTCF2CVs9VbgSHQDblV1SAeFz9vsxdJfciKiN-e-BihweVHKvlYez7R7jMMDHmQMl/s226/stm32cube.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="223" data-original-width="226" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY34ySk_uOjykUH0MWUZw4jSy1nvn94vycwU88gesfJUTYtwyvK87_oURIrxrg4TbDAbYSb2fuCFSwTCF2CVs9VbgSHQDblV1SAeFz9vsxdJfciKiN-e-BihweVHKvlYez7R7jMMDHmQMl/w200-h197/stm32cube.jpeg" width="200" /></a></div><div><br /></div><div><br /></div><div><div><b><font size="4">목차</font></b></div><div><div><i>1. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">STM32MP157C Discovery Kit 소개</a></i></div><div><i>2. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">Firmware(부팅 image) 설치하기</a></i></div><div><i>3. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">부팅 image 생성하기 - Yocto project, Buildroot</a></i></div><div><i>4. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">Qt application 개발 환경 설정 및 테스트해 보기</a></i></div><div><i>5. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">Device Tree 분석 및 Device Driver 시험하기 - i2c 예제 소개</a></i></div><div><i>6. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">온습도 센서 결과 확인용 Qt application 만들기</a></i></div></div><div><i><b><font color="#7b1fa2">7. Cortex-M4 환경에서의 firmware 개발하기</font></b></i></div><div><i>8. References</i></div><div><font color="#b51200" size="2">(*) 목차는 처음 예정했던 내용과 차이가 날 수도 있다.</font></div><div><br /></div><div><br /></div><div><font color="#9e9e9e" size="2">DK2 보드에는 Cortex-A7(CPU1)과 Cortex-M4(CPU2) 두개의 CPU(정확히는 SoC)가 장착되어 있다. 따라서 부팅 시점이나 부팅 후 적당한 시점에 둘간의 상호 통신이 필요한 상황이 발생할 수 있는데, 이번 blog post에서는 Cortex-M4에 ST firmware를 올리는 방법과 두 CPU(CPU1 <-> CPU2) 간의 IPCC(Inter Processor Communication Channel) 상황에 대해서 간략하게 짚어 보고자 한다.</font></div><div><br /></div><div><br /></div><div><b style="background-color: #b7e1cd;"><확장 편></b></div></div><div><div><b><font color="#3367d6" size="6">7. Cortex-M4 환경에서의 firmware 개발</font></b></div><div>앞선 장(1-6장)에서는 Cortex-A7 MPU 환경(main processor, OS: Linux)에 대해서만 이야기하였다. 하지만 이번 장에서는 DK2 보드에 존재하는 또 다른 CPU인 Cortex-M4(coprocessor, OS: ST firmware/bare-metal application)에 관하여 이야기하고자 한다. 사실 이 부분이 DK2를 개발한 ST Microelectronics 사의 주력 분야라고 말할 수 있다. 즉, 소규모 embedded system 개발에 관한한 ST Microelectronics가 업계 1위(<font color="#9e9e9e">정확한 근거가 있는 얘기는 아님</font>)라고 말할 수 있을 정도로 널리 사용되는게 사실이다.</div></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ5PkBrH0QRsLnZVo-ikKVR5eS-jses4aHUjlg9MLMFJxpSRFqpIUbkUCDgraEg97GebuLe6HK-5fDxI2_4RHGEHybkD_vNBx59l0RPxlgcq4236F6FNgLRLax2VOmu3xlW6PLyI0ASml/s754/stm32mp1_arch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="754" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZZ5PkBrH0QRsLnZVo-ikKVR5eS-jses4aHUjlg9MLMFJxpSRFqpIUbkUCDgraEg97GebuLe6HK-5fDxI2_4RHGEHybkD_vNBx59l0RPxlgcq4236F6FNgLRLax2VOmu3xlW6PLyI0ASml/w640-h253/stm32mp1_arch.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.1] STM32MP1 Architecture</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9sHT8pdMAypCTm8QhRCirRdO9728tHpwynar0YIUAkn5kINZvoXvOD0kF7XVyFD3HKdRHu1ENAfKAE0mf5P06Ag-CmrDknnR3JfNbOA8fGbr20Zp_fWKniO4QyL1nA6QjeOYKLOTyNIG8/s835/stm32mpu_ipcc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="423" data-original-width="835" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9sHT8pdMAypCTm8QhRCirRdO9728tHpwynar0YIUAkn5kINZvoXvOD0kF7XVyFD3HKdRHu1ENAfKAE0mf5P06Ag-CmrDknnR3JfNbOA8fGbr20Zp_fWKniO4QyL1nA6QjeOYKLOTyNIG8/w640-h325/stm32mpu_ipcc.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.2] STM32MP1 Coprocessor Management</div><div><br /></div><div><br /></div><div>이장에서 소개하는 내용 대부분은 STM32 MPU wiki(<a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-M4">참고 문헌 [1]</a>)를 참조하여 작성하였다.</div><div><br /></div><div><b><font color="#0b8043">a) STM32CubeIDE 설치</font></b></div><div>먼저 아래 내용을 참조하여 STM32Cube IDE를 설치해 보도록 하자</div><div><br /></div><div style="text-align: justify;"> <a href="https://www.st.com/en/development-tools/stm32cubeide.html#getsoftware-scroll" style="text-align: right;"><span style="text-align: center;">https://www.st.com/en/development-tools/stm32cubeide.html#getsoftware-scrol</span><span style="text-align: right;">l</span></a></div><div><br /></div><div><font color="#b51200" size="2">[Tip] Cortex-M 계열의 firmware를 개발하기 위해서는 (유료 버젼인) IAR Embedded Workbench(EWARM)나 KEIL MDK(MDK-ARM) 등이 많이 쓰인다. STM32CubeIDE는 무료 버젼이므로 나름의 가치가 있다고 생각된다.</font></div><div style="text-align: center;"><br /></div><div style="text-align: justify;"><span style="text-align: left;">지금부터 소개하는 내용은 모두 Ubuntu 18.04를 기준으로 하였다(참고: Windows, MacOS 사용자의 경우는 해당 버젼을 설치하시기 바람).</span></div><div><br /></div><div>$ unzip en.st-stm32cubeide_1.3.0_5720_20200220_1053_amd64.deb_bundle.sh.zip</div><div>$ <b>sudo sh ./st-stm32cubeide_1.3.0_5720_20200220_1053_amd64.deb_bundle.sh</b></div><div><i> => super user 권한으로 설치하고, 몇가지 license에 관한 물음에 yes로 응답해 주면 된다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhcrRN3CrXDitvRvIyXzyqcgDVM1EsnE0o2vSu55hWed8iCe7Fe007MELATYq7fWtrMDjymEyU2LzSY9kS1jw3YT0S5qtRmwxkN0fwKA6Q1hQ2XbYLZs4rzWDvb11P4Qe-gmKf0ZlI08ec/s953/stm32cube_ide_install.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="953" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhcrRN3CrXDitvRvIyXzyqcgDVM1EsnE0o2vSu55hWed8iCe7Fe007MELATYq7fWtrMDjymEyU2LzSY9kS1jw3YT0S5qtRmwxkN0fwKA6Q1hQ2XbYLZs4rzWDvb11P4Qe-gmKf0ZlI08ec/w400-h145/stm32cube_ide_install.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.3] STM32CubeIDE 설치 - Ubuntu용 shell script 실행</div><div><br /></div><div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3TzLrkSyiwKMD9zc4W9TA-8_7UF3CkZgvG5NLXPvCwujvWBxAulyVOdLPxz61Dqj1-RmahHyD0a6umpKMS2CNQVCNg9Cqj615L5uJuNZYbvgGJVO-EWR3bx3FyWTZo4B1VIvWMchtWosP/s1018/stm32_cubeide1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="769" data-original-width="1018" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3TzLrkSyiwKMD9zc4W9TA-8_7UF3CkZgvG5NLXPvCwujvWBxAulyVOdLPxz61Dqj1-RmahHyD0a6umpKMS2CNQVCNg9Cqj615L5uJuNZYbvgGJVO-EWR3bx3FyWTZo4B1VIvWMchtWosP/w400-h303/stm32_cubeide1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMC0WLUEPDHvkew1ttrstRa74Ft2_0tSVoEW99iz0bWyWrUXLi36vrEE7sBNj2CoLaBd2LrH0pEaWkd2xOflqWp2lsbLWWbGwqocvU32foRcf4VWE4rQEPHfx2KWLLg2fzWSoK8mgmMIgt/s800/800px-STM32CubeIDE_Default.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="424" data-original-width="800" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMC0WLUEPDHvkew1ttrstRa74Ft2_0tSVoEW99iz0bWyWrUXLi36vrEE7sBNj2CoLaBd2LrH0pEaWkd2xOflqWp2lsbLWWbGwqocvU32foRcf4VWE4rQEPHfx2KWLLg2fzWSoK8mgmMIgt/w400-h213/800px-STM32CubeIDE_Default.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.4] STM32CubeIDE 실행 화면</div><div><span style="text-align: center;"><font color="#b51200" size="2">[Tip] STM32CubeIDE는 eclipse를 기반으로 하고 있다.</font></span></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">다음으로 할 일은, 아래 위치에서 STM32Cube MP1 package를 download 받아 설치하는 것이다.</span></div><div><span style="text-align: center;"><br /></span></div><div style="text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-M4/Install_STM32Cube_MP1_package">https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-M4/Install_STM32Cube_MP1_package</a></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">$ <b>unzip </b></span><b>en.stm32cubemp1_v1-2-0.zip</b></div><div>$ cd STM32Cube_FW_MP1_V1.2.0</div><div><font color="#b51200" size="2">[Tip] 버젼이 여러 개가 있는데 가장 최신 버젼을 내려 받으면 된다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjj2D1oN7pQwMZ6SkxEAoFFlkVlSgG9lskZKZ9B4xKTzPaMSZGA-tv4mIGBR3QfnAWYjacThJp4StxLSRTeS7hbN9V_V25ig0mnsxTCkYNMzsJykzpiY_QlGROvFE_zGbNY5Nn1YDdX6U/s819/stm32cube_mp1_package.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="243" data-original-width="819" height="119" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjj2D1oN7pQwMZ6SkxEAoFFlkVlSgG9lskZKZ9B4xKTzPaMSZGA-tv4mIGBR3QfnAWYjacThJp4StxLSRTeS7hbN9V_V25ig0mnsxTCkYNMzsJykzpiY_QlGROvFE_zGbNY5Nn1YDdX6U/w400-h119/stm32cube_mp1_package.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.5] STM32Cube MP1 package 내용</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">아래 내용은 STM32Cube MP1 package를 구성하는 디렉토리 구조를 간략히 보여준다(ST code는 실로 오래 간만에 보는 것 같다 😁).</div><div><pre style="background-color: #f9f9f9; border-radius: 0px; border: 1px dotted rgb(221, 221, 221); box-sizing: inherit; color: #58585a; font-family: courier, monospace; font-size: 14px; line-height: 1.42857; margin-bottom: 2em; margin-top: 2em; max-height: 25em; overflow-wrap: normal; overflow: auto; padding: 1em; word-break: break-all;"><span style="box-sizing: inherit; color: green;">STM32Cube_FW_MP1_V1.2.0</span>
├── <span style="box-sizing: inherit; color: green;">Drivers</span>
│ ├── <span style="box-sizing: inherit; color: green;"><span class="mw-lingo-term" data-hasqtip="0" data-lingo-term-id="db55f5a9e3472e08cf5af25914d2c94a" style="border-bottom: 1px dotted rgb(187, 187, 255); box-sizing: inherit; cursor: default;">BSP</span></span> <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;"><span class="mw-lingo-term" data-hasqtip="1" data-lingo-term-id="db55f5a9e3472e08cf5af25914d2c94a" style="border-bottom: 1px dotted rgb(187, 187, 255); box-sizing: inherit; cursor: default;">BSP</span> drivers for the supported STM32MP1 boards</span>
│ │ └── [...]
│ ├── <span style="box-sizing: inherit; color: green;"><span class="mw-lingo-term" data-hasqtip="2" data-lingo-term-id="c61d595888f85f6d30e99ef6cacfcb7d" style="border-bottom: 1px dotted rgb(187, 187, 255); box-sizing: inherit; cursor: default;">CMSIS</span></span>
│ │ └── [...]
│ └── <span style="box-sizing: inherit; color: green;">STM32MP1xx_<span class="mw-lingo-term" data-hasqtip="3" data-lingo-term-id="ee465b6fa3ae0152ffa45d36cc7180d1" style="border-bottom: 1px dotted rgb(187, 187, 255); box-sizing: inherit; cursor: default;">HAL</span>_Driver</span> <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;"><span class="mw-lingo-term" data-hasqtip="4" data-lingo-term-id="ee465b6fa3ae0152ffa45d36cc7180d1" style="border-bottom: 1px dotted rgb(187, 187, 255); box-sizing: inherit; cursor: default;">HAL</span> drivers for the supported STM32MP1 devices</span>
│ └── [...]
├── <span style="box-sizing: inherit; color: green;">_htmresc</span>
│ └── [...]
├── License.md
├── <span style="box-sizing: inherit; color: green;">Middlewares</span>
│ └── [...]
├── package.xml
├── <span style="box-sizing: inherit; color: green;">Projects</span>
│ ├── STM32CubeProjectsList.html <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;">List of examples and applications for STM32CubeMP1 Package</span>
│ ├── <span style="box-sizing: inherit; color: green;">STM32MP157C-DK2</span> <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;">Set of examples and applications → STM32MP15 Discovery kits</span>
│ │ └── [...]
│ └── <span style="box-sizing: inherit; color: green;">STM32MP157C-EV1</span> <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;">Set of examples and applications → STM32MP15 Evaluation boards</span>
│ └── [...]
├── Readme.md
├── Release_Notes.html <span style="box-sizing: inherit; color: #d4007a; font-weight: bold;">Release note for STM32CubeMP1 Package</span>
└── <span style="box-sizing: inherit; color: green;">Utilities</span>
└── [...]</pre></div><div><br /></div><div><b><font color="#0b8043">b) 예제 Application(OpenAMP_TTY_echo) 돌려 보기</font></b></div><div><span style="text-align: center;">STM32Cube MP1 package에는 몇가지 example이 포함되어 있다. 따라서 지금 부터는 이 중 하나를 선택하여 돌려 보도록 하겠다.</span></div><div><span style="text-align: center;"><font color="#b51200" size="2">[Tip] 시작에 앞서 1-6장에서 사용했던 Buildroot를 버리고(?) ST에서 배포한 image(yocto image)로 테스트를 진행하기로 한다. (그 이유는) Buildroot 환경에서 테스트를 해 보니, 무언가 빠져 있는지 Cortext-M4 상에서 program 구동이 안된다.</font></span></div><div><span style="text-align: center;"><br /></span></div><div><div><div class="separator" style="clear: both; text-align: left;">먼저, File -> Import => General => Existing Projects into Workspace => Browse 버튼 선택하여 OpenAMP_TTY_echo Application을 open하도록 한다.</div></div></div><div><br /></div><div style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzzsmPAr7PPPcs_3F-tVk1jaU7JJ8VSRL1_hg8_glfaxtJ1WVIqSY6SWEJdH0QqOB8_DsbethJY0Omo0fyvILoqtn1EGl467X8il2mbdc0GoLaS5WKpnZAbo85IFJAXqDRNWloRt55QONw/s607/stm32cube_ide_file_import.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="551" data-original-width="607" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzzsmPAr7PPPcs_3F-tVk1jaU7JJ8VSRL1_hg8_glfaxtJ1WVIqSY6SWEJdH0QqOB8_DsbethJY0Omo0fyvILoqtn1EGl467X8il2mbdc0GoLaS5WKpnZAbo85IFJAXqDRNWloRt55QONw/s320/stm32cube_ide_file_import.png" width="320" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 7.6] File -> Import => General => Existing Projects into Workspace => Browse 버튼 선택</div></div><div><span style="text-align: center;"><div style="text-align: left;"><font color="#b51200" size="2">참고: OpenAMP_TTY_echo application은 아래 위치에 있다.</font></div><div><font color="#b51200" size="2">STM32Cube_FW_MP1_V1.2.0/Projects/STM32MP157C-DK2/Applications/OpenAMP/OpenAMP_TTY_echo</font></div></span></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">정상적으로 open할 경우, 아래와 같은 파일 들이 보이게 될 것이다.</span></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-VtVr-B5izW6Vz4YvIPqECz8D9OYUgwK_m7l8FnaydO94fd1AZIid3KaxXXmReO6MOxjM86TxAl-dBuozRL8JVNfEYZNc4cq2RAw5uVF1UbCgmnkeZ9veXDI6ZMJZFvpmQV4v6z45nV8/s1524/stm32cubeide_openamp1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="923" data-original-width="1524" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-VtVr-B5izW6Vz4YvIPqECz8D9OYUgwK_m7l8FnaydO94fd1AZIid3KaxXXmReO6MOxjM86TxAl-dBuozRL8JVNfEYZNc4cq2RAw5uVF1UbCgmnkeZ9veXDI6ZMJZFvpmQV4v6z45nV8/w400-h243/stm32cubeide_openamp1.png" width="400" /></a></div></div><div class="separator" style="clear: both; text-align: center;">[그림 7.7] OpenAMP_TTY_echo Application</div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">OpenAMP_TTY_echo가 무엇을 하는 program인지를 따져 보는 것은 뒤에서 하기로 하고, 일단은 무조건 build 부터 해 보도록 하겠다.</span></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">좌측 상단의 Project Explorer 창에서 OpenAMP_TTY_echo_CMD4를 선택한 상태에서 toolbar에 있는 작은 망치(해머) 버튼을 누르면 build가 진행된다.</span></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRPqo77kCIzMqQnsOFf4uN2QdPr_1iIQMIdwUufkyQDa6g_2EMowW6s8Why9syU_jCOsfGXf1RA3c1IFqPMFtvZQsIye_hy54oLThY8VjIUd9YaxR2iXI0TIuZqrxqWuGqmbgdQXvBwgC5/s50/eclipse_hammer.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="50" data-original-width="46" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRPqo77kCIzMqQnsOFf4uN2QdPr_1iIQMIdwUufkyQDa6g_2EMowW6s8Why9syU_jCOsfGXf1RA3c1IFqPMFtvZQsIye_hy54oLThY8VjIUd9YaxR2iXI0TIuZqrxqWuGqmbgdQXvBwgC5/" /></a><i><font size="2"><= 작은 망치(해머) 버튼</font></i></div></div><div><span style="text-align: center;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN13MbvTmEgrZyDB7HatJ1TVaZwd_KtL7-JZsXHKzYTFYnNbVLmP6pd7f3hSmo9ijPvpTb_Y7jphRNY5SpJ7r8ifMvrd9wZaSTLVsNHBs1I_4TWXnrJwqZ9LP4b01_jJgcq6cUXt3-vfsH/s1524/openamp_tty_echo_build.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="923" data-original-width="1524" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN13MbvTmEgrZyDB7HatJ1TVaZwd_KtL7-JZsXHKzYTFYnNbVLmP6pd7f3hSmo9ijPvpTb_Y7jphRNY5SpJ7r8ifMvrd9wZaSTLVsNHBs1I_4TWXnrJwqZ9LP4b01_jJgcq6cUXt3-vfsH/w400-h243/openamp_tty_echo_build.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.8] OpenAMP_TTY_echo Application build(1) - 화면 하단 중앙에 build 과정 출력</div><span style="text-align: center;"><br /></span></div><div style="text-align: left;">Eclipse IDE(STM32Cube IDE) 화면 하단 중앙에 build 과정이 출력되게 되는데, 정상적으로 build가 될 경우, OpenAMP_TTY_echo_CM4.bin 파일이 생성됨을 알 수 있다.</div><div style="text-align: center;"><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZUgouBJz2EoGRX4y6qbKr-5KbSDSfDNtQHY7U81Yv6qbNU0jLK6voVtzvbwdjwbsgnS0LjwD45ubil9Cr2YCS75IUOM_7DZq7FgaLlVfjJjcOxkFdH-3No47pc4YRMUWvIS2zgpVMX4UU/s755/openamp_tty_echo_build2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="355" data-original-width="755" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZUgouBJz2EoGRX4y6qbKr-5KbSDSfDNtQHY7U81Yv6qbNU0jLK6voVtzvbwdjwbsgnS0LjwD45ubil9Cr2YCS75IUOM_7DZq7FgaLlVfjJjcOxkFdH-3No47pc4YRMUWvIS2zgpVMX4UU/w400-h188/openamp_tty_echo_build2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.9] OpenAMP_TTY_echo Application build(2)</div></div><div><br /></div><div>실제 source code가 위치한 디렉토리로 이동해 build 결과를 확인해 보니, bin 파일 외에도 <a href="https://ko.wikipedia.org/wiki/ELF_%ED%8C%8C%EC%9D%BC_%ED%98%95%EC%8B%9D">elf 파일</a> 등이 보인다.</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid4bq2nf3QkErWhFVJlaH2tKysLls2gnU7p8j03O2bCNz9ylFDvPXpb8BnESPMkhJy01nTH-zz7bpCY4__Z8dbAfbl2qr1hF6oB7veyWzN0cHdn8GIPlIcMlN46FwyBqsetTPpiABDQWHj/s928/openamp_tty_echo_bin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="289" data-original-width="928" height="125" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEid4bq2nf3QkErWhFVJlaH2tKysLls2gnU7p8j03O2bCNz9ylFDvPXpb8BnESPMkhJy01nTH-zz7bpCY4__Z8dbAfbl2qr1hF6oB7veyWzN0cHdn8GIPlIcMlN46FwyBqsetTPpiABDQWHj/w400-h125/openamp_tty_echo_bin.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.10] OpenAMP_TTY_echo Application build(3)</div></div><div><span style="text-align: center;"><font color="#b51200" size="2">[Tip] bin 파일은 flash memory에 writing할 때 사용하고, elf는 memory에 loading하여 곧 바로 실행할 때 사용된다.</font></span></div><div><span style="text-align: center;"><br /></span></div><div>자, 그러면 지금부터는 방금 전에 build 한 파일(<b>OpenAMP_TTY_echo_CM4.elf</b>)을 Cortex-M4에서 돌려보도록 하겠다.</div><div><br /></div><div>Run -> Debug Configurations -> STM32 Cortex-M C/C++ Applications를 선택하고, 아래와 같이 Debugger tab을 선택한 후, 필요한 정보(<font color="#f4a900">실제로는 target board의 IP 주소만 입력하면 됨</font>)를 입력하도록 한다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicpK6xURZp37F-AcBeTpixOe5PWtGeCT1BRWigqHdcvGLD-g7Cl4E5-msPgh_vLEhvBIc-ZRgV-z9NQWDdoFJxS03ZJyQ_gU7qlHhDAT4afrsIQGIcsUrfXkkP_OLj0LJjquP-osIeaxBS/s1192/eclipse_debug_configurations.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="703" data-original-width="1192" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicpK6xURZp37F-AcBeTpixOe5PWtGeCT1BRWigqHdcvGLD-g7Cl4E5-msPgh_vLEhvBIc-ZRgV-z9NQWDdoFJxS03ZJyQ_gU7qlHhDAT4afrsIQGIcsUrfXkkP_OLj0LJjquP-osIeaxBS/w400-h236/eclipse_debug_configurations.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.11] Debug Session 설정하기</div><div><br /></div><div>이 상태에서 Debug 버튼을 누르면, <b>OpenAMP_TTY_echo_CM4.elf </b>파일이 linux로 copy되면서, 대략적으로 아래의 (예상) 절차를 따라 Cortex-M4 CPU에서 실행되게 된다.</div><div><font color="#b51200" size="2">[Tip] Cortex-M4 SoC 내에는 별도의 flash memory가 존재할 것이고, 여기에 bin 파일을 writing하는 방법이 분명 있을 텐데, 이와 관련해서는 추후 확인해 보도록 하겠다(보통은 ST에서 설치 전용 program을 제공).</font></div><div><br /></div><div><div><div><b style="background-color: #b7e1cd;"><OpenAMP_TTY_echo_CM4.elf writing 예상 절차></b></div><div style="text-align: center;">STM32CubeIDE => network(SSH) => Linux => <span style="background-color: #e1bee7;">remoteproc driver</span> => SRAM/IPCC => Run it on Cortex-M4</div></div><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIl4DyWSFryv1ghzfKipeYpzkFk8avyuvWAGlurZteJcTwGqGmZcFUSF8Qw2Ltrv4z0-BF2EccbrGIhIYjZyYmwbK0zEzlb4l-oCNokuQox-D32XO8CV0XuNXcR0PRwKIO5_JoyZhPbEon/s693/openamp_elf_list.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="106" data-original-width="693" height="98" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIl4DyWSFryv1ghzfKipeYpzkFk8avyuvWAGlurZteJcTwGqGmZcFUSF8Qw2Ltrv4z0-BF2EccbrGIhIYjZyYmwbK0zEzlb4l-oCNokuQox-D32XO8CV0XuNXcR0PRwKIO5_JoyZhPbEon/w640-h98/openamp_elf_list.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.12] <span style="text-align: left;">OpenAMP_TTY_echo_CM4.elf 파일이 복사된 위치 - linux file system</span></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZy-KHGYbVqbw3ya7Urxf3rM8hUyLZzU1RzRVNcAufeZcEfeYuRU5SR10tVvhgRcGABlzE9PfPtiNn4unBygxUZNHxZa0xL6Cr_5UzJK8dXQTGFqScN67_3yX0J4NYNEechb1gMM2DHUi4/s859/openamp_kernel_dmesg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="196" data-original-width="859" height="146" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZy-KHGYbVqbw3ya7Urxf3rM8hUyLZzU1RzRVNcAufeZcEfeYuRU5SR10tVvhgRcGABlzE9PfPtiNn4unBygxUZNHxZa0xL6Cr_5UzJK8dXQTGFqScN67_3yX0J4NYNEechb1gMM2DHUi4/w640-h146/openamp_kernel_dmesg.png" width="640" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 7.13] <span style="text-align: left;">OpenAMP_TTY_echo_CM4.elf 파일이 Cortex-M4에서 실행되는 과정을 보여주는 linux kernel message(dmesg 출력 결과)</span></div><div><br /></div></div><div><font color="#b51200" size="2">참고: linux driver인 remoteproc에 관해서는 별도로 분석이 필요해 보인다.</font></div><div><br /></div><div style="text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/Linux_remoteproc_framework_overview">https://wiki.st.com/stm32mpu/wiki/Linux_remoteproc_framework_overview</a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU4J9lsYKiUfDOuEIVTBtjIHS6eZ0jfI5s7I02aljZobkTzL2-fRjXj3P9mKL17goXsFMExBLBjCEAa8AQfrYyAVJcYNrRBe4S7X2dg2S_cpM_RFOO_DaiKTaeMaznrUwKt1Ncgypwbohn/s947/remoteproc_dd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="110" data-original-width="947" height="74" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU4J9lsYKiUfDOuEIVTBtjIHS6eZ0jfI5s7I02aljZobkTzL2-fRjXj3P9mKL17goXsFMExBLBjCEAa8AQfrYyAVJcYNrRBe4S7X2dg2S_cpM_RFOO_DaiKTaeMaznrUwKt1Ncgypwbohn/w640-h74/remoteproc_dd.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkr7GhJ3zBMcevDgjmtf118-FvQwJi7pXUcHbyipMKZ7oSvVANqXW-Jz1Av9cF7eKHyB5XkqsMZbbIdrJZy1ZTluPxBO8nvSPC94ZrBlBwEBWi3W3sgjDRyLBsSBzq5apcNcLCh3TPv8ZY/s949/remoteproc_devicetree.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="510" data-original-width="949" height="344" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkr7GhJ3zBMcevDgjmtf118-FvQwJi7pXUcHbyipMKZ7oSvVANqXW-Jz1Av9cF7eKHyB5XkqsMZbbIdrJZy1ZTluPxBO8nvSPC94ZrBlBwEBWi3W3sgjDRyLBsSBzq5apcNcLCh3TPv8ZY/w640-h344/remoteproc_devicetree.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 7.14] remoteproc linux device driver & device tree 예</span></div><div><br /></div><div><br /></div><div><b><font color="#0b8043">c) IPCC(Inter Processor Communication Channel)의 이해</font></b></div><div>지금부터는 OpenAMP_TTY_echo program이 무엇을 하는 녀석(?)인지 살펴볼 생각인데, 이를 이해하기 위해서는 사전에 몇가지 개념을 이해하고 넘어갈 필요가 있어 보인다.</div><div><br /></div><div style="text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/Coprocessor_management_overview">https://wiki.st.com/stm32mpu/wiki/Coprocessor_management_overview</a></div><div><br /></div><div>먼저 아래 그림 7.15는 STM32MPU1을 구성하는 Cortex-A 쪽의 Linux와 Cortex-M 쪽의 ST firmware 간의 상호 통신에 관한 전반적인 개요도가 되겠다. 그림을 보면 알 수 있는 바와 같이 mailbox, rpmsg, remoteproc 등등의 아주 신기한(?) 녀석들이 눈에 들어온다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-7tU7IgeKJkAsYEzLq8YGNg9HuMzv77_dpd2mkkYSLwHUx6u2um9GF2AffCGh1WK26f1n1KBgNV8GTSgPp0fvwgqjFCAhsNOSM9hQGph3xGBB6eTPWNV5PoffOofkjsZsyv9SvI2LuBW1/s960/stm32mpu_remoteproc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="720" data-original-width="960" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-7tU7IgeKJkAsYEzLq8YGNg9HuMzv77_dpd2mkkYSLwHUx6u2um9GF2AffCGh1WK26f1n1KBgNV8GTSgPp0fvwgqjFCAhsNOSM9hQGph3xGBB6eTPWNV5PoffOofkjsZsyv9SvI2LuBW1/w640-h480/stm32mpu_remoteproc.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.15] <span style="text-align: left;">STM32MPU1 remoteproc and rpmsg framework</span></div><div><br /></div><div>다음 그림은 Linux 쪽의 rpmsg와 ST firmware 쪽의 OpenAMP program 간의 inter processor 통신에 관한 부분이 되겠다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhATnwuuUh2PS9I8mEAEsGd_ROiJJjZzCmx0HZ5d949xSrl5Jmvoy1Op4lgzpheeom8stjr9pQTmHksZ3YBsM-3uwPz2F9W5sHUsCarMHGycbbsUOo2g810ATSfyUbx1nzgUrJuKPVdzYgf/s768/stmp32mpu_ipc.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="768" height="422" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhATnwuuUh2PS9I8mEAEsGd_ROiJJjZzCmx0HZ5d949xSrl5Jmvoy1Op4lgzpheeom8stjr9pQTmHksZ3YBsM-3uwPz2F9W5sHUsCarMHGycbbsUOo2g810ATSfyUbx1nzgUrJuKPVdzYgf/w640-h422/stmp32mpu_ipc.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.16] <span style="text-align: left;">STM32MPU1 Inter Processor Communication Channel</span></div><div><br /></div><div>마지막으로 아래 그림은 remote processor(여기서는 Cortex-M4)를 제어(power on/off, load firmware)하기 위해 linux에서 제공(물론 stm32에 맞게 개선)하는 <b><font color="#0f9d58">remote processor framework</font></b>을 소개한다.</div><div><br /></div><div><remoteproc의 역할></div><div><i><font size="2"> - ELF firmware를 remote processor 메모리에 적재하고, </font></i></div><div><i><font size="2"> - firmware resource table을 parsing 하며,</font></i></div><div><i><font size="2"> - remote processor의 start/stop을 제어하고,</font></i></div><div><i><font size="2"> - remote firmware를 모니터링하거나 debugging하기 위해 서비스를 제공한다.</font></i></div><div><stm32_rproc의 역할></div><div><i><font size="2"> - RPROC framework에 callback function(vendor specific codes)을 등록하고,</font></i></div><div><i><font size="2"> - remote processor와 관련된 platform resource 즉, register, watchdog, reset, clock 및 메모리 등을 handling 한다.</font></i></div><div><i><font size="2"> - 또한, mailbox를 통해 remote processor에게 noti를 날려준다.</font></i></div><div><br /></div><div style="text-align: right;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDkXIfqSTf8Kptas3p6r-In2QPEQOryjIk6Zl1Zh3rx4Wb6ppTHDt1bKYMoTSgD0gUXdYqprx-6FcqLQYvanxeG8pHteavT_u3fYC9X425Gn_FNJDKXPM-Ii9eLt8AWz_fIy4UC9BtQEVo/s960/Remoteproc_overview.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="720" data-original-width="960" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDkXIfqSTf8Kptas3p6r-In2QPEQOryjIk6Zl1Zh3rx4Wb6ppTHDt1bKYMoTSgD0gUXdYqprx-6FcqLQYvanxeG8pHteavT_u3fYC9X425Gn_FNJDKXPM-Ii9eLt8AWz_fIy4UC9BtQEVo/w640-h480/Remoteproc_overview.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.17] <span style="text-align: left;">STM32MPU1 RPROC(Remote Processor) framework</span></div><div><br /></div><div><span style="background-color: #f7cb4d;">사실 위에 소개한 내용을 모두 상세히 이해하기는 쉽지 않아 보이는데, 여기에서는 일단 이 정도까지만 살펴 보기로 하고, OpenAMP_TTY_echo program 분석으로 넘어가기로 하자.</span></div><div><br /></div><div><span style="text-align: center;"><b style="text-align: left;"><font color="#0b8043">d) 예제 Application</font></b></span><b><font color="#0b8043">(OpenAMP_TTY_echo)</font></b><b><font color="#0b8043"> 코드 분석</font></b></div><div style="text-align: left;">OpenAMP의 동작 시험을 해 보면, OpenAMP가 무엇을 하려는 것인지 대략 이해할 수가 있다. Target board에서 아래 명령을 하나씩 수행해 보도록 하자.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><Target board></b></div><div style="text-align: left;">root@stm32mp1:~# <b>stty -onlcr -echo -F /dev/ttyRPMSG0</b></div><div style="text-align: left;"><i> => /dev/ttyRPMSG0를 초기화(open) 한다.</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;">root@stm32mp1:~# <b>cat /dev/ttyRPMSG0 &</b></div><div style="text-align: left;"><div><i> => /dev/ttyRPMS0 channel로 값이 들어오기를 기다린다.</i></div><div><i> => &(background 실행) 대신, 별도의 terminal을 띄우고 실행해도 된다.</i></div><div><br /></div><div>root@stm32mp1:~# <b>echo "Hello Virtual UART0" > /dev/ttyRPMSG0</b></div><div><i> => /dev/ttyRPMSG0 channel로 string을 내보낸다.</i></div><div>Hello Virtual UART0</div></div><div style="text-align: left;"><i> => 앞서 cat /dev/ttyRPMSG0 &를 통해 수신한 내용이 출력된다.</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;">OpenAMP는 linux와 두개의 채널(/dev/ttyRPMSG0, ttyRPMSG1)을 열어 두고 있다. 따라서 /dev/ttyRPMSG1에 대해서도 동일한 실험이 가능하다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdkY0KjbhZo_TlRbln_0h_UXYsY_N2HCiM6dKUSpNUraEtGtkQkrkv9KM69CrYV9G0jmNLXQbl8ySf5aoi-dzyhvDUT_mfGHjVFMuE_QczyjuNYQxRaQnwBCyN8slcvhPGIEiz7gzHFYOh/s562/stm32mp_rpmsg_test.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="350" data-original-width="562" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdkY0KjbhZo_TlRbln_0h_UXYsY_N2HCiM6dKUSpNUraEtGtkQkrkv9KM69CrYV9G0jmNLXQbl8ySf5aoi-dzyhvDUT_mfGHjVFMuE_QczyjuNYQxRaQnwBCyN8slcvhPGIEiz7gzHFYOh/w400-h249/stm32mp_rpmsg_test.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.18] RPMSG를 통해 OpenAMP와 통신(<=> linux)하는 모습</div><div style="text-align: left;"><br /></div><div style="text-align: left;">다음 코드는 OpenAMP main 함수의 흐름을 대략적으로 정리해 본 것이다. 앞서 테스트한 내용과 비교해 보면, 그 의미를 파악하는 것이 크게 어렵지 않다는 것을 알 수 있을 것이다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b style="background-color: #e1bee7;"><main.c 흐름도></b></div><div style="text-align: left;">main() <font color="#e1bee7">// loop을 돌면서 uart0, uart1으로 message가 들어오는지를 기다렸다가 메신지가 있으면 응답 메시지를 내보내는 routine</font></div><div style="text-align: left;">{</div><div style="text-align: left;"> HAL_Init( ); <font color="#e1bee7">//HAL code 초기화</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> if (boot mode)</div><div style="text-align: left;"> SystemClock_Config();</div><div style="text-align: left;"><br /></div><div style="text-align: left;"> MX_IPCC_Init( ); <font color="#e1bee7">// IPCC code 초기화</font></div><div style="text-align: left;"> MX_OPENAMP_Init( ); <font color="#e1bee7">// OPENAMP code(mailbox, shmem 등) 초기화</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> VIRT_UART_Init(&huart0); <font color="#e1bee7">// uart0 초기화</font></div><div style="text-align: left;"> </div><div style="text-align: left;"> VIRT_UART_Init(&huart1); <font color="#e1bee7">// uart1 초기화</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> VIRT_UART_RegisterCallback(&huart0, ..., VIRT_UART0_RxCpltCallback); <font color="#e1bee7">// uart0에 대한 callback 함수 등록</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> VIRT_UART_RegisterCallback(&huart1, ..., VIRT_UART1_RxCpltCallback); <font color="#e1bee7">// uart1에 대한 callback 함수 등록</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> while (1) <font color="#e1bee7">// 무한 loop</font></div><div style="text-align: left;"> {</div><div style="text-align: left;"> OPENAMP_check_for_message(); <font color="#e1bee7">// OPENAMP message가 도착했는지 체크</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"> if (VirtUart0RxMsg) <font color="#e1bee7">//uart0를 통해 message send(transmit)</font></div><div style="text-align: left;"> VIRT_UART_Transmit(&huart0, VirtUart0ChannelBuffRx, VirtUart0ChannelRxSize);</div><div style="text-align: left;"> if (VirtUart1RxMsg) <font color="#e1bee7">//uart1를 통해 message send(transmit)</font></div><div style="text-align: left;"> VIRT_UART_Transmit(&huart1, VirtUart1ChannelBuffRx, VirtUart1ChannelRxSize);</div><div style="text-align: left;"> }</div><div style="text-align: left;">}</div><div style="text-align: left;"><br /></div><div style="text-align: left;">아래 내용은 OpenAMP_TTY_echo <b>readme.txt </b>파일에서 발췌한 내용으로, 위의 main() 함수에서 하는 일을 요약해 주고 있다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSRttvPN2BCRyFvWRiJ2X0wu0O8E_J9Rha3tes2lRzDVtZLroaTUT2YQ4LFCZRG8BTGQXU0fVamoHDHnF8MuhuNWZZeAU1hV65J7qmOwmVLFdJNZ8TnEgwxqE-XbLnt7zNcwimmvka67zS/s874/openamp_overview.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="143" data-original-width="874" height="104" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSRttvPN2BCRyFvWRiJ2X0wu0O8E_J9Rha3tes2lRzDVtZLroaTUT2YQ4LFCZRG8BTGQXU0fVamoHDHnF8MuhuNWZZeAU1hV65J7qmOwmVLFdJNZ8TnEgwxqE-XbLnt7zNcwimmvka67zS/w640-h104/openamp_overview.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 7.19] STM32Cube_FW_MP1_V1.2.0/Projects/STM32MP157C-DK2/Applications/OpenAMP/OpenAMP_TTY_echo/readme.txt에서 발췌한 내용</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;">사실 main 함수에서 호출하는 함수 하나 하나를 다 따져 가면서, ST firmware code를 깊게 설명하자면 할 말이 더 많이 있겠지만, 내용이 지나치에 길어질 수 있으므로 이쯤에서 이번 blog post를 마무리 지을까 한다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;">여기에 미쳐 소개하지 못한 내용은 <a href="https://wiki.st.com/stm32mpu/wiki/">STM32 MPU wiki</a>를 통해 독자 여러분이 직접 파악해 보시기를 권해 드린다. 😅</div><div style="text-align: left;"><span style="text-align: center;"><br /></span></div><div style="text-align: left;"><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;"><br /></span></div><div><div><b><font color="#3367d6" size="6">8. References</font></b></div></div><div>[1] <a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-M4">https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Develop_on_Arm%C2%AE_Cortex%C2%AE-M4</a></div><div>[2] <a href="https://wiki.st.com/stm32mpu/wiki/Coprocessor_management_overview">https://wiki.st.com/stm32mpu/wiki/Coprocessor_management_overview</a></div><div>[3] <a href="https://wiki.st.com/stm32mpu/wiki/Linux_remoteproc_framework_overview">https://wiki.st.com/stm32mpu/wiki/Linux_remoteproc_framework_overview</a></div><div>[4] STM32CubeIDE installation guide - User manual</div></div><div>[5] <a href="https://blog.st.com/stm32mp1-mpu-stm32mp157a-ev1-stm32mp157c-dk2/">https://blog.st.com/stm32mp1-mpu-stm32mp157a-ev1-stm32mp157c-dk2/</a></div><div><br /></div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div><div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-75737334689054454682020-06-18T16:14:00.004+09:002020-07-16T10:10:51.269+09:00Linux Device Driver for Embedded Processors 에피소드 3 - STM32MP157C Discovery Kit(소개5)지난 시간에 이어 <b>STM32MP157C Discovery Kit</b> 분석, 다섯번 째 시간이다. 😊<div><br /></div><div>이번 시간에는 HTU21D 온/습도 센서의 결과를 확인해 볼 수 있는 <b><font color="#ba67c8">아주 간단한 Qt application</font></b>을 하나 만들어 보도록 하겠다. <font color="#9e9e9e">또한 온습도 센서의 결과를 외부 서버로 전송(client & server)하고, 이를 암호화하는 방법에 대해서도 소개해 보고자 한다.</font></div><div class="separator" style="clear: both; text-align: center;"><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCi1CUaL8KQ31Sxvp7RDQ4bjK6yCll12KK8_a6xfeVh7LdHzJwAmrSzx3Glx5fFfEnrSiRIz3SYDJxZ4RYXw1I6r86XYT1XcMXp_lQeoaKlPyT4F_AQ2XRcga1Fc2yAHZeNfnXmVvM16Fk/s4096/20200618_110830.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4096" data-original-width="3072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCi1CUaL8KQ31Sxvp7RDQ4bjK6yCll12KK8_a6xfeVh7LdHzJwAmrSzx3Glx5fFfEnrSiRIz3SYDJxZ4RYXw1I6r86XYT1XcMXp_lQeoaKlPyT4F_AQ2XRcga1Fc2yAHZeNfnXmVvM16Fk/w150-h200/20200618_110830.jpg" width="150" /></a></div></blockquote><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><div><b><font size="4">목차</font></b></div><div><i>1. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">STM32MP157C Discovery Kit 소개</a></i></div><div><i>2. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">Firmware(부팅 image) 설치하기</a></i></div><div><i>3. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">부팅 image 생성하기 - Yocto project, Buildroot</a></i></div><div><i>4. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">Qt application 개발 환경 설정 및 테스트해 보기</a></i></div><div><i>5. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">Device Tree 분석 및 Device Driver 시험하기 - i2c 예제 소개</a></i></div><div><i><b>6. 온습도 센서 결과 확인용 Qt application 만들기</b></i></div><div><i>7. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">Cortex-M4 환경에서의 firmware 개발하기</a></i></div><div><i>8. References</i></div><div><font color="#b51200" size="2">(*) 목차는 처음 예정했던 내용과 차이가 날 수도 있다.</font></div></div><div><br /></div><div><br /></div><div><font color="#9e9e9e">이번 blog post의 목적은 Qt app 작성 방법을 소개(본 저자는 Qt 전문가가 아님^^)하는 것이 아니라, 온/습도 센서의 측정 결과를 UI 형태로 보여주거나, network을 통해 외부 서버로 전달하는 예를 소개하는데에 있다.</font></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">6. 온습도 센서 결과 확인용 Qt application 만들기</font></b></div><div>앞선 blog post에서 HTU21D 온/습도 센서를 i2c bus에 붙여 동작을 확인한 바 있다. 따라서 이번에서는 HTU21D 온/습도 센서의 결과를 읽어 들여 화면에 출력하는 간단한 application을 하나 만들어 보겠다.</div><div><br /></div><div><div><i><font color="#f57c00"><이번 장에서 다룰 내용></font></i></div><div><i>1. 온/습도 센서 결과를 화면에 출력하는 (간단한) app 만들기</i></div><div><i> => <font color="#b51200">참고 문험 [4] 14장의 예제를 참조하였음.</font></i></div><div><i>2. 온/습도 센서를 외부 서버로 전송하는 (역시 간단한) client & server 만들기</i></div><div><i><font color="#9e9e9e">3. WireGuard로 암호 통신하기</font></i></div><div><br /></div><div><b><font color="#0b8043">a) 온/습도 센서 결과를 화면에 출력하는 app 만들기</font></b></div><div><b><온/습도 센서 app의 개요></b></div><div>1) <font color="#9e9e9e">(향후 확장을 위해) </font>QMainWindow style로 만든다</div><div>2) 온도와 습도 값을 각각 아래 파일에서 주기적(3초 간격)으로 읽어 화면에 출력한다.</div><div><i><font color="#4285f4"> => /sys/bus/iio/devices/iio:device0/in_temp_input</font></i></div><div><i><font color="#4285f4"> => /sys/bus/iio/devices/iio:device0/in_humidityrelative_input</font></i></div><div>3) 주기적으로 온/습도 값을 읽어 들이기 위해 QTimer class를 사용한다.</div><div> <i> => timeout 시 signal 발생. 이후 해당 slot 함수 호출 </i></div><div>4) 온도와 습도 값은 LCD Number widget으로 표현하도록 한다.</div><div>5) "Get Sensor Data" Pushbutton widget을 하나 추가하여, 버튼 선택 시 곧 바로 온/습도 센서 값을 읽어 화면에 출력한다.</div><div>6) 하단에 Status bar를 추가하여 간단한 상태 정보(시작, 날짜 정보 등)를 출력하도록 한다.</div><div>-----------------------</div><div><br /></div><div>이상의 내용을 Qt designer를 통해 구성한 전체 화면은 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH7LKx1bdHC9_2inUHD_jo8MneH-FHKbseIwvn4uoFiJUKuBWzCqumdSQwe2zUQrFB6sFSIFR36t2_X3SLLO4Jn3Rme9tB-jzGhGlStA7ZxaV8U7U2tfXPWVqBFVIi3jVjp89-XFh8hSmd/s522/qtsensor3_ui.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="522" data-original-width="444" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH7LKx1bdHC9_2inUHD_jo8MneH-FHKbseIwvn4uoFiJUKuBWzCqumdSQwe2zUQrFB6sFSIFR36t2_X3SLLO4Jn3Rme9tB-jzGhGlStA7ZxaV8U7U2tfXPWVqBFVIi3jVjp89-XFh8hSmd/s320/qtsensor3_ui.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 6.1] 화면 디자인</span></div><div><span style="color: #b51200; font-size: small;">[Tip] LCD 화면이 smart phone 형태(가로 보다 세로가 긺)로 되어 있고, 화면 크기(4인치 TFT - 480 x 800)가 작은 점을 고려하여 font size를 작게하였다.</span></div><div><br /></div><div>먼저 main.cpp 파일을 살펴 보면 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRIOAvZH0TrIk7urMY9GlgVw1tZvHdWo5UWg_F7QMBGlUKuZNI4ayB8sknDtEQmZDqTOm-twNQhYBRPBB3F3Nk7F2sAIeWsX9q17yAfpKOb2Npt8-Qt6qHJ343BbpA47vyoM8nZDJc8e7G/s1248/qtsensor1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="787" data-original-width="1248" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRIOAvZH0TrIk7urMY9GlgVw1tZvHdWo5UWg_F7QMBGlUKuZNI4ayB8sknDtEQmZDqTOm-twNQhYBRPBB3F3Nk7F2sAIeWsX9q17yAfpKOb2Npt8-Qt6qHJ343BbpA47vyoM8nZDJc8e7G/w400-h253/qtsensor1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.2] main.cpp</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><font size="2"><pre style="margin-bottom: 0px; margin-top: 0px;">#<span style="color: navy;">include</span><span style="color: silver;"> </span><span style="color: green;">"mainwindow.h"</span></pre><pre style="margin-bottom: 0px; margin-top: 0px;">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QApplication</span>></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><br /></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: olive;">int</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">main</span>(<span style="color: olive;">int</span><span style="color: silver;"> </span><span style="color: #092e64;">argc</span>,<span style="color: silver;"> </span><span style="color: olive;">char</span><span style="color: silver;"> </span>*<span style="color: #092e64;">argv</span>[])</pre><pre style="margin-bottom: 0px; margin-top: 0px;">{</pre><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: silver;"> </span><span style="color: purple;">QApplication</span><span style="color: silver;"> </span><span style="color: #092e64;">a</span>(<span style="color: #092e64; font-style: italic;">argc</span>,<span style="color: silver;"> </span><span style="color: #092e64;">argv</span>); //QApplication의 instance를 하나 생성한다.</pre><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: silver;"> </span><span style="color: purple;">MainWindow</span><span style="color: silver;"> </span><span style="color: #092e64;">w</span>; // QMainWindow를 상속한 MainWindow라는 이름의 class에 대한 instance를 하나 생성한다.</pre><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: silver;"> </span><span style="color: #092e64;">w</span>.<span style="color: #00677c;">show</span>(); // 화면에 내용을 출력한다.</pre><pre style="margin-bottom: 0px; margin-top: 0px;"><br /></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: silver;"> </span><span style="color: olive;">return</span><span style="color: silver;"> </span><span style="color: #092e64;">a</span>.<span style="color: #00677c;">exec</span>(); // loop을 돌면 대기한다(발생하는 event를 처리).</pre><pre style="margin-bottom: 0px; margin-top: 0px;">}</pre></font></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">다음으로 소개하는 파일은 MainWindow class를 위한 헤더 파일 mainwindow.h이다.</span></div><div><br /></div><div><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">ifndef</span><span style="color: silver;"> </span><span style="color: navy;">MAINWINDOW_H</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">define</span><span style="color: silver;"> </span><span style="color: navy;">MAINWINDOW_H</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QMainWindow</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QTimer</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">namespace</span><span style="color: silver;"> </span><span style="color: purple; font-weight: 600;">Ui</span><span style="color: silver;"> </span>{ // namespace Ui</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">class</span><span style="color: silver;"> </span><span style="color: purple; font-weight: 600;">MainWindow</span>; // MainWindow는 Ui scope하에 있음을 뜻함.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">class</span><span style="color: silver;"> </span><span style="color: purple; font-weight: 600;">MainWindow</span><span style="color: silver;"> </span>:<span style="color: silver;"> </span><span style="color: olive;">public</span><span style="color: silver;"> </span><span style="color: purple;">QMainWindow</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: navy;">Q_OBJECT</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">public</span>:</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">explicit</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">MainWindow</span>(<span style="color: purple;">QWidget</span><span style="color: silver;"> </span>*<span style="color: #092e64;">parent</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: navy;">0</span>);</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span>~<span style="color: #00677c; font-style: italic; font-weight: 600;">MainWindow</span>();</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">private</span><span style="color: silver;"> </span><span style="color: navy;">slots</span>:</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">on_getSample_clicked</span>(); // "Get Sensor Data" Pushbutton을 누를 경우 발생하는 signal을 처리하는 slot 함수</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">on_timerUpdate</span>(); // QTimer timeout event(signal) 발생 시 처리하는 slot 함수</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">private</span>:</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">float</span><span style="color: silver;"> </span><span style="color: maroon;">temperature</span>,<span style="color: silver;"> </span><span style="color: maroon;">humidity</span>; // 온도, 습도를 저장하는 private 변수</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">QTimer</span><span style="color: silver;"> </span>*<span style="color: maroon;">timer</span>; // QTimer class member 변수(pointer)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">updateDisplay</span>(); // 화면에 온도, 습도 값을 출력해 주는 함수로 on_timerUpdate( ) 등의 함수에서 주기적으로 호출함.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">int</span><span style="color: silver;"> </span><span style="color: #00677c; font-weight: 600;">readHTU21DSensor</span>(); // HTU21D 온/습도 센서의 출력 결과를 읽어 들이는 함수(위의 온도, 습도를 저장하는 private 변수에 값 저장)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">Ui</span>::<span style="color: purple;">MainWindow</span><span style="color: silver;"> </span>*<span style="color: maroon;">ui</span>; //Ui::MainWindow의 private member 변수(pointer)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">};</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">endif</span><span style="color: silver;"> </span><span style="color: green;">//</span><span style="color: silver;"> </span><span style="color: green;">MAINWINDOW_H</span></font></pre></div><div><br /></div><div>다음으로 소개하는 파일은 MainWindow class cpp 파일이다.</div><div><br /></div><div><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><span style="color: green;">"mainwindow.h"</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><span style="color: green;">"ui_mainwindow.h"</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QDateTime</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QtCore</span>/<span style="color: green;">QFile</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">QDebug</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">#<span style="color: navy;">include</span><span style="color: silver;"> </span><<span style="color: green;">unistd</span>.<span style="color: green;">h</span>></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">using</span><span style="color: silver;"> </span><span style="color: olive;">namespace</span><span style="color: silver;"> </span><span style="color: purple;">std</span>;</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">MainWindow</span>::<span style="color: #00677c; font-weight: 600;">MainWindow</span>(<span style="color: purple;">QWidget</span><span style="color: silver;"> </span>*<span style="color: #092e64;">parent</span>)<span style="color: silver;"> </span>: // MainWindow class 생성자(constructor)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">QMainWindow</span>(<span style="color: #092e64;">parent</span>),</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: maroon;">ui</span>(<span style="color: olive;">new</span><span style="color: silver;"> </span><span style="color: purple;">Ui</span>::<span style="color: purple;">MainWindow</span>)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: maroon;">ui</span>-><span style="color: #00677c;">setupUi</span>(<span style="color: olive;">this</span>); // ui object의 setupUI( ) 함수 호출 즉, MainWinodw를 구성하는 widget, layout 등을 배치하는 역할을 함.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: #00677c;">statusBar</span>()-><span style="color: #00677c;">showMessage</span>(<span style="color: green;">"Sensor</span><span style="color: silver;"> </span><span style="color: green;">Application</span><span style="color: silver;"> </span><span style="color: green;">Started"</span>); // 하단 Status 바에 string 출력</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">temperature</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: navy;">0.0</span>; // temperature 변수 초기화</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">humidity</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: navy;">0.0</span>; // humidity 변수 초기화 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: #00677c;">updateDisplay</span>();</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">timer</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: olive;">new</span><span style="color: silver;"> </span><span style="color: purple;">QTimer</span>(<span style="color: olive;">this</span>); // QTimer class instance 생성 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: #00677c;">connect</span>(<span style="color: maroon;">timer</span>,<span style="color: silver;"> </span><span style="color: navy;">SIGNAL</span>(<span style="color: #00677c;">timeout</span>()),<span style="color: silver;"> </span><span style="color: olive;">this</span>,<span style="color: silver;"> </span><span style="color: navy;">SLOT</span>(<span style="color: #00677c;">on_timerUpdate</span>())); // QTimer timeout signal에 on_timerUpdate() slot 함수 mapping</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">timer</span>-><span style="color: #00677c;">start</span>(<span style="color: navy;">3000</span>);<span style="color: silver;"> </span>// 3초 간격으로 timer timeout (signal 발생)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: purple;">MainWindow</span>::<span style="color: #00677c; font-weight: 600;">on_getSample_clicked</span>() //"Get Sensor Data" Pushbutton을 누를 경우 발생하는 signal에 대한 처리</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">QDateTime</span><span style="color: silver;"> </span><span style="color: #092e64;">local</span>(<span style="color: purple;">QDateTime</span>::<span style="color: #00677c;">currentDateTime</span>());<span style="color: silver;"> </span><span style="color: green;">//</span><span style="color: silver;"> </span><span style="color: green;">display</span><span style="color: silver;"> </span><span style="color: green;">sample</span><span style="color: silver;"> </span><span style="color: green;">time</span></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: #00677c;">statusBar</span>()-><span style="color: #00677c;">showMessage</span>(<span style="color: purple;">QString</span>(<span style="color: green;">"Last</span><span style="color: silver;"> </span><span style="color: green;">update:</span><span style="color: silver;"> </span><span style="color: green;">"</span>).<span style="color: #00677c;">append</span>(<span style="color: #092e64;">local</span>.<span style="color: #00677c;">toString</span>())); // 상태 바에 현재 시간 정보 출력</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: #00677c;">readHTU21DSensor</span>(); // HTU21D 센서 값(온도/습도) 읽어 member 변수에 저장</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"> </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: #00677c;">updateDisplay</span>(); // 온/습도 정보를 화면에 출력 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: purple;">MainWindow</span>::<span style="color: #00677c; font-weight: 600;">on_timerUpdate</span>() // QTimer timeout 시 호출되는 slot 함수 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: #00677c;">on_getSample_clicked</span>();</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: #00677c;">updateDisplay</span>(); // 온/습도 정보를 화면에 출력</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">void</span><span style="color: silver;"> </span><span style="color: purple;">MainWindow</span>::<span style="color: #00677c; font-weight: 600;">updateDisplay</span>() // 화면을 갱신하는 함수 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: maroon;">ui</span>-><span style="color: maroon;">lcdTemperature</span>-><span style="color: #00677c;">display</span>((<span style="color: olive;">double</span>)<span style="color: maroon;">temperature</span>); // 온도 LCD Number widget에 값 표시</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: maroon;">ui</span>-><span style="color: maroon;">temperatureUnits</span>-><span style="color: #00677c;">setText</span>(<span style="color: green;">"C"</span>);</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: maroon;">ui</span>-><span style="color: maroon;">lcdHumidity</span>-><span style="color: #00677c;">display</span>((<span style="color: olive;">double</span>)<span style="color: maroon;">humidity</span>); // 습도 LCD Number widget에 값 표시</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">MainWindow</span>::~<span style="color: #00677c; font-style: italic; font-weight: 600;">MainWindow</span>() // MainWindow class 소멸자(destructor)</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">delete</span><span style="color: silver;"> </span><span style="color: maroon;">ui</span>;</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">int</span><span style="color: silver;"> </span><span style="color: purple;">MainWindow</span>::<span style="color: #00677c; font-weight: 600;">readHTU21DSensor</span>() // HTU21D 센서 정보를 읽어 들이는 함수 </font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">{</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">QFile</span><span style="color: silver;"> </span><span style="color: #092e64;">fd_temp</span>(<span style="color: green;">"/sys/bus/iio/devices/iio:device0/in_temp_input"</span>); // 옆의 파일 open</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: purple;">QFile</span><span style="color: silver;"> </span><span style="color: #092e64;">fd_humidity</span>(<span style="color: green;">"/sys/bus/iio/devices/iio:device0/in_humidityrelative_input"</span>); // 옆의 파일 open</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">if</span><span style="color: silver;"> </span>(!<span style="color: #092e64;">fd_temp</span>.<span style="color: #00677c; font-style: italic;">open</span>(<span style="color: purple;">QIODevice</span>::<span style="color: purple;">ReadOnly</span><span style="color: silver;"> </span><span style="color: #00677c;">|</span><span style="color: silver;"> </span><span style="color: purple;">QIODevice</span>::<span style="color: purple;">Text</span>))</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">return</span><span style="color: silver;"> </span>-<span style="color: navy;">1</span>;</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">if</span><span style="color: silver;"> </span>(!<span style="color: #092e64;">fd_humidity</span>.<span style="color: #00677c; font-style: italic;">open</span>(<span style="color: purple;">QIODevice</span>::<span style="color: purple;">ReadOnly</span><span style="color: silver;"> </span><span style="color: #00677c;">|</span><span style="color: silver;"> </span><span style="color: purple;">QIODevice</span>::<span style="color: purple;">Text</span>))</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">return</span><span style="color: silver;"> </span>-<span style="color: navy;">1</span>;</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">temperature</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: purple;">QString</span>(<span style="color: #092e64;">fd_temp</span>.<span style="color: #00677c;">readAll</span>()).<span style="color: #00677c;">toDouble</span>()<span style="color: silver;"> </span>/<span style="color: silver;"> </span><span style="color: navy;">1000</span>; // 파일 내용(string)을 읽어 들여 double 값으로 변경 후, 1000으로 나눔.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">humidity</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span><span style="color: purple;">QString</span>(<span style="color: #092e64;">fd_humidity</span>.<span style="color: #00677c;">readAll</span>()).<span style="color: #00677c;">toDouble</span>()<span style="color: silver;"> </span>/<span style="color: silver;"> </span><span style="color: navy;">1000</span>; // 파일 내용(string)을 읽어 들여 double 값으로 변경 후, 1000으로 나눔.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: navy;">qDebug</span>()<span style="color: silver;"> </span><span style="color: #00677c;"><<</span><span style="color: silver;"> </span><span style="color: green;">"Temperature:</span><span style="color: silver;"> </span><span style="color: green;">"</span><span style="color: silver;"> </span><span style="color: #00677c;"><<</span><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">temperature</span><span style="color: silver;"> </span><span style="color: #00677c;"><<</span><span style="color: silver;"> </span><span style="color: green;">"Humidity:</span><span style="color: silver;"> </span><span style="color: green;">"</span><span style="color: silver;"> </span><span style="color: #00677c;"><<</span><span style="color: silver;"> </span><span style="color: olive;">this</span>-><span style="color: maroon;">humidity</span>; // 디버그 용</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: silver;"> </span><span style="color: olive;">return</span><span style="color: silver;"> </span><span style="color: navy;">0</span>;</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">}</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><br /></pre></div><div><br /></div><div>마지막으로 IoTSensor.pro 파일을 소개하면 다음과 같다.</div><div><pre style="margin-bottom: 0px; margin-top: 0px;"><br /></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><pre style="margin-bottom: 0px; margin-top: 0px;"><span style="color: purple;">QT</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>core<span style="color: silver;"> </span>gui</pre><pre style="margin-bottom: 0px; margin-top: 0px;"><br /></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: olive;">greaterThan</span>(<span style="color: purple;">QT_MAJOR_VERSION</span>,<span style="color: silver;"> </span>4):<span style="color: silver;"> </span><span style="color: purple;">QT</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>widgets</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">TARGET</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span>IoTSensor</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">TEMPLATE</span><span style="color: silver;"> </span>=<span style="color: silver;"> </span>app</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">SOURCES</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>main.cpp<span style="color: silver;"> </span>mainwindow.cpp</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">HEADERS</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>mainwindow.h</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">FORMS</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>mainwindow.ui</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><br /></font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2"><span style="color: purple;">INSTALLS</span><span style="color: silver;"> </span>+=<span style="color: silver;"> </span>target // 이 두 줄을 적어 주어야, target board의 원하는 위치로 파일이 복사될 것임.</font></pre><pre style="margin-bottom: 0px; margin-top: 0px;"><font size="2">target.path=/root/workspace</font></pre></pre></div><div><br /></div><div>여기까지 해서 모든 코드가 준비되었으니, target board에서 돌려 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjs-uik50SQH9yRU71r_oum7u0saRyWv2GECjQUoHV4n6Ssa86u7kNxq_JpuBbTg04Su-uqW-JHZzkqHK4ze_Wz2-qunmuU-yesRMst6EShr0a4kts8xz3gpnzb_QET21FQEEuozl2zzAM/s1305/qtsensor4_build.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="933" data-original-width="1305" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjs-uik50SQH9yRU71r_oum7u0saRyWv2GECjQUoHV4n6Ssa86u7kNxq_JpuBbTg04Su-uqW-JHZzkqHK4ze_Wz2-qunmuU-yesRMst6EShr0a4kts8xz3gpnzb_QET21FQEEuozl2zzAM/w400-h286/qtsensor4_build.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiit-6I4XjReQT9vchJLRbp3rYLwGzO64MhjR9X6GWzfw7jfyEDsKC57Qu84t0KaojL8OSCvwiBr_i3DoKcut2cHRUGcXQ3G-If8ZLn8jcJjtFa5H4j66ZcULQ5kUOGHtkMwjdpcQ1d3wt0/s1305/qtcreater_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="933" data-original-width="1305" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiit-6I4XjReQT9vchJLRbp3rYLwGzO64MhjR9X6GWzfw7jfyEDsKC57Qu84t0KaojL8OSCvwiBr_i3DoKcut2cHRUGcXQ3G-If8ZLn8jcJjtFa5H4j66ZcULQ5kUOGHtkMwjdpcQ1d3wt0/w400-h286/qtcreater_run.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.3] Build & Run - Buildroot ARM => Build & Run</div><div><br /></div><div>좌측 하단의 실행 버튼을 선택하면, (최초 실행 시)target board에 로긴하기 위해 root password를 확인하는 popup 창이 뜨게 된다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0FvppgpK5Sfe1rS3Mn6h_e_Nr5_65X1OGXFAhHPsVYsy_DPyip5p2DwP7Hf5AHMy5L-okIR8RkSrReJ5E5-JJ-Kk61yq7xCcQgW4exbireTXyEmgiHgqN1tvZRonMzOpw6LeBhGQ81q8c/s248/qtsensor_popup.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0FvppgpK5Sfe1rS3Mn6h_e_Nr5_65X1OGXFAhHPsVYsy_DPyip5p2DwP7Hf5AHMy5L-okIR8RkSrReJ5E5-JJ-Kk61yq7xCcQgW4exbireTXyEmgiHgqN1tvZRonMzOpw6LeBhGQ81q8c/" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.4] Target board로의 SSH login 화면</div><div><br /></div><div>정확한 root password 값을 입력하고 나면, 아래와 같은 화면이 보이게 될 것이다. 😎</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicJ8FW19kaa9r88F_l5jF5f7i_Jt5iyz9Tf7C8gJsIe79A_RZRx-KkTnQNww7ZisugrARVOG7K-9RxKDQopErO4MWSNZSh3aOMWykUlNsP6OT2b8CJD4gxhzfPJQsbDpw2b2le1eoQ4uHH/s4096/20200618_110830.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4096" data-original-width="3072" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicJ8FW19kaa9r88F_l5jF5f7i_Jt5iyz9Tf7C8gJsIe79A_RZRx-KkTnQNww7ZisugrARVOG7K-9RxKDQopErO4MWSNZSh3aOMWykUlNsP6OT2b8CJD4gxhzfPJQsbDpw2b2le1eoQ4uHH/s320/20200618_110830.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.5] 센서 app 실행 모습</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijH1tjSwwJBCjAVj4rs9fOvbiFEEQU7F0uFktJhLCWVxRGTSCG-x0Lqp47Mq_n64lpGona-0Loch0qV3rFtAJZbpgoqqZH6Gw8v5ZfJnwAiVBFtVtHbV4JGsxulcHEJ_WdJUJSySUPYaxi/s609/qtsensor_ls.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="227" data-original-width="609" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijH1tjSwwJBCjAVj4rs9fOvbiFEEQU7F0uFktJhLCWVxRGTSCG-x0Lqp47Mq_n64lpGona-0Loch0qV3rFtAJZbpgoqqZH6Gw8v5ZfJnwAiVBFtVtHbV4JGsxulcHEJ_WdJUJSySUPYaxi/s320/qtsensor_ls.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.6] target board에 upload된 파일(IoTSensor) 확인</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisZJZRM00ftaMw6Vj67LfEbArbeJGSBFxCoyGfeG7osJQNKoT52yTSDbDt_ajOkZ9x3uSjEoNMl-WvUcWlXOuuIid3YMamfQTPVM5oAAPPeC-ev9CJDe9YMI5R8BrzrhtMqSdWclXW0MZx/s547/qtserver_ps2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="547" height="109" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisZJZRM00ftaMw6Vj67LfEbArbeJGSBFxCoyGfeG7osJQNKoT52yTSDbDt_ajOkZ9x3uSjEoNMl-WvUcWlXOuuIid3YMamfQTPVM5oAAPPeC-ev9CJDe9YMI5R8BrzrhtMqSdWclXW0MZx/w400-h109/qtserver_ps2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 6.7] 센서 app 실행 상태에서 ps 명령 실행 모습</div><div><br /></div><div><b><font color="#0b8043">b) 온/습도 센서 결과를 외부로 전송하는 client & server 만들기</font></b></div><div>온/습도 센서로 부터 읽어 들인 정보를 Cloud server로 전달하는 경우를 가정하고 아래와 같은 간단한 client & server program을 만들어 보도록 하겠다.</div><div><br /></div><div style="text-align: center;"><b>DK2 board(client daemon) ========> internet ======> AWS EC2(Amazon cloud server, Ubuntu 18.04)</b></div><div><br /></div><div>아주 간단한 내용이니, 이 부분은 독자 여러분의 몫으로 남기도록 하겠다. 😜</div><div><br /></div><div><br /></div><div><b><font color="#0b8043">c) 암호 통신하기</font></b></div><div>이 절에서는 open source VPN solution인 <a href="https://www.wireguard.com/">WireGuard</a>를 이용해 client와 server 간에 암호 통신하는 과정을 소개하고자 하였으나, 내용이 너무 길어지는 듯하여 지난 번에 소개했던 내용으로 대신하고자 한다. 관심있는 분들은 아래 blog post의 내용을 참조해 주기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/04/">https://slowbootkernelhacks.blogspot.com/2020/04/</a></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html">https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html</a></div><div><br /></div><div><br /></div><div>============</div><div><br /></div><div><div>지금까지 다섯 차례에 걸쳐 STMP32MP157C Discovery Kit를 가지고 다양한 시도를 해 보았다. 사실 이번 blog post를 작성하는데 결정적인 역할을 한 것은 Thomas Petazzoni @ bootlin의 아래 글이다. </div><div><br /></div><div style="text-align: center;"><a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/</a> 1-7</div><div><br /></div><div>이 자리를 빌어 다시한번 감사의 마음을 전한다. <b style="background-color: #f7cb4d;">Thank you so much, Thomas !</b></div><div><b style="background-color: #f7cb4d;"><br /></b></div><div>물론, <font color="#9e9e9e">(약간의 첨언을 하자면) </font>전반적인 내용을 참조한 것은 맞지만, 내용을 그대로 베끼지는 않았으며, 국내 현실에 맞게 새로운 느낌의 blog post로 재 탄생시키려 노력하였다.</div><div><br /></div><div>끝으로, 이 글이 Embedded Linux 개발자 혹은 개발자를 꿈꾸는 이들(특히 국내 개발자)에게 조금이나마 보탬이 되었기를 희망해 본다. 👏</div></div><div><br /></div><div><br /></div><div><div class="separator" style="clear: both; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 14.85px; text-align: center;"><b><span style="background-color: #c6dafc; font-family: verdana, sans-serif; font-size: large;"><font color="#9c27b0">May the source be with you</font></span></b></div><div class="separator" style="clear: both; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 14.85px; text-align: center;"><b><span style="background-color: #c6dafc; font-family: verdana, sans-serif; font-size: large;"><font color="#9c27b0">(소스가 그대와 함께 하길 ~)</font></span></b></div></div><div><br /></div><div><br /></div><div><br /></div><div><b style="background-color: #b7e1cd;"><확장 편></b></div><div><div><b><font color="#3367d6" size="6">7. Cortex-M4 환경에서의 firmware 개발</font></b></div><div>앞선 장에서는 Cortex-A7 MPU 환경(Linux)에 대해서만 이야기하였다. 하지만 이번 장에서는 DK2 보드에 존재하는 또 다른 CPU인 Cortex-M4(ST firmware)에 관하여 이야기하고자 한다. 사실 DK2를 개발한 ST Microelectronics의 (지금까지의) 주력 분야는 이 부분이었다. 즉, 소규모 embedded system 개발에 관한한 ST Microelectronics의 chip과 s/w(firmware)가 업계 1위(<font color="#9e9e9e">정확한 근거가 있는 것은 아님</font>)라고 말할 수 있을 정도로 널리 사용되고 있다.</div></div><div><br /></div><div><b><font color="#f57c00">To be continued ...</font></b></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">8. References</font></b></div><div>[1] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-enabling-qt5-for-graphical-applications/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-enabling-qt5-for-graphical-applications/</a></div><div>[2] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-setting-up-a-qt5-application-development-environment/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-setting-up-a-qt5-application-development-environment/</a></div><div>[3] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-developing-a-qt5-graphical-application/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-developing-a-qt5-graphical-application/</a></div><div>[4] Exploring Raspberry Pi, Derek Molloy</div><div>[5] Application Development with Qt Creator, 2nd edition, Ray Rischpater</div><div>[6] <a href="http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html" style="text-align: center;">http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html</a></div><div><br /></div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div><div><br /></div></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com1tag:blogger.com,1999:blog-6346200245600677355.post-86705300482810042122020-06-17T13:15:00.010+09:002020-07-16T10:09:28.186+09:00Linux Device Driver for Embedded Processors 에피소드 3 - STM32MP157C Discovery Kit 소개(4)지난 시간에 이어 <b>STM32MP157C Discovery Kit</b> 분석, 네번째 시간이다. 😙<div><br /></div><div>이번 시간에는 <b style="color: #9c27b0;">HTU21D 온/습도 센서를 DK2 보드에 연결(i2c interface)하고, 관련 device tree와 device driver를 작성하는 방법</b>을 소개할 것이다.</div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><img border="0" data-original-height="173" data-original-width="184" height="188" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXIVb7QUB5z4OvoE_hnJ8OuwG0P849X64m_NNPVm-IDlV4TMHry7hN9RaIBLwP3eVjUZUF__Gr45NOPMH17VE8wL183B7hRZJBoAmEQOnIhSMpNh1tdHRcTs70BGuxYYKZH4lejuoMjXfh/w200-h188/htu21d_2.jpeg" style="text-align: left;" width="200" /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVpSpdDY2BheaLplEsuxUUwfavfXREkHIoNnVBD9O9hkj0Ik2L85pY34Un5weuBVVM2YFLYXSEl0bpQq4vHwZbmVTwfGaVf8SvQ5Saoyi32qcjlVrF1-tHULW0PuwUbn3rliKj_XIc8kGN/s4128/20200612_150355.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVpSpdDY2BheaLplEsuxUUwfavfXREkHIoNnVBD9O9hkj0Ik2L85pY34Un5weuBVVM2YFLYXSEl0bpQq4vHwZbmVTwfGaVf8SvQ5Saoyi32qcjlVrF1-tHULW0PuwUbn3rliKj_XIc8kGN/w200-h150/20200612_150355.jpg" width="200" /></a></div></div><div><br /></div><div><br /></div><div><div><b><font size="4">목차</font></b></div><div><i>1. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">STM32MP157C Discovery Kit 소개</a></i></div><div><i>2. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">Firmware(부팅 image) 설치하기</a></i></div><div><i>3. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">부팅 image 생성하기 - Yocto project, Buildroot</a></i></div><div><div><i>4. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">Qt application 개발 환경 설정 및 테스트해 보기</a></i></div></div><div><i><b>5. Device Tree 분석 및 Device Driver 시험하기</b> - <font color="#f57c00">i2c 예제 소개</font></i></div><div><i>6. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">온습도 센서 결과 확인용 Qt application 만들기</a></i></div><div><i>7. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">Cortex-M4 환경에서의 firmware 개발하기</a></i></div><div><i>8. References</i></div><div><font color="#b51200" size="2">(*) 목차는 처음 예정했던 내용과 차이가 날 수도 있다.</font></div><div><br /></div><div><br /></div></div><div><font color="#9e9e9e" size="2"><i>Raspberry Pi나 Arduino를 가지고 응용 program(python, C ...) 수준에서 HTU21D 온/습도 센서를 제어하는 작업은 크게 어렵지 않다. 하지만, 이를 linux device driver(w/ device tree)로 작업하는 것은 생각보다 험난한(?) 과정을 겨쳐야 한다. 하지만, 한번 해 보면 다른 유형의 device driver 개발에도 많은 도움이 될 것이다. 자, 그럼 시작할 준비가 되었는가 ?</i></font></div><div><br /></div><div><b><font color="#3367d6" size="6">5. Device Tree 분석 및 Device Driver 시험하기</font></b></div><div>이번 장에서 소개하고자 하는 내용은 대략 다음과 같다. </div><div><i> 1) DK2 board의 전체 device tree 구조 분석(특히 i2c를 중심으로..)</i></div><div><i> 2) HTU21D 온습도 센서와 DK2 보드 연결 방법 소개</i></div><div><i> 3) device tree 수정 사항 소개</i></div><div><i> 4) 관련 </i><i>device driver 분석</i></div><div><i> 5) 동작 시험</i></div><div><br /></div><div><font color="#0b8043" size="4"><b>a) DK2 보드의 device tree 구조 분석</b></font></div><div>사실, 특정 SoC & board의 device tree를 한번에 이해하기는 쉬운 일이 아니다. 특히나 h/w를 전문적으로 다루지 않는 경우라면 더더욱 그렇다. 하지만 device driver 개발 관점에서만 생각해 본다면 모든 것을 속속들이 다 이해해야 하는 것도 아니다. 이번 posting에서는 i2c device를 하나 장착하고 이를 올바르게 동작시키는 게 목적인 만큼, 그 취지에 맞에 제한된 범위 내에서 device tree 분석을 시작해 보도록 하겠다. </div><div><br /></div><div><font color="#0b8043" size="2"><b>[Tip] </b>Device Tree의 기초적인 내용을 파악할 필요가 있는 분들은 본 저자가 오래전에 작성한 아래 blog post를 한번 훑어 보시기 바란다.</font></div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html"><font size="2">https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html</font></a></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div>먼저 DK2 보드의 device tree 계층 구조를 대략적으로 살펴 보자. 파일 위치는 우리가 익히 알고 있는 바와 같이 arch/arm/boot 이다. </div><div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><b><font color="#f4a900">stm32mp151.dtsi</font></b></div><div class="separator" style="clear: both; text-align: center;">^</div><div class="separator" style="clear: both; text-align: center;">|</div><div class="separator" style="clear: both; text-align: center;">stm32mp153.dtsi</div><div class="separator" style="clear: both; text-align: center;">^</div><div class="separator" style="clear: both; text-align: center;">|</div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><b>stm32mp157.dtsi</b></div><div class="separator" style="clear: both; text-align: center;"><b><br /></b></div><div class="separator" style="clear: both; text-align: center;">stm32mp15xc.dtsi</div><div class="separator" style="clear: both; text-align: center;"><b>stm32mp15-pinctrl.dtsi</b></div><div class="separator" style="clear: both; text-align: center;">stm32mp15xxac-pinctrl.dtsi</div><div class="separator" style="clear: both; text-align: center;"><b><font color="#b51200">stm32mp15xx-dkx.dtsi</font></b></div><div class="separator" style="clear: both; text-align: center;">^</div><div class="separator" style="clear: both; text-align: center;">|</div><div class="separator" style="clear: both; text-align: center;"><b><font color="#3367d6">stm32mp157c-dk2.dts</font></b></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaMDHJxXgH828BKtJQAQQlKfgA90cg2nChu-UHc10rNkb6DXRbl2XpSzHLFD2KWya7wU2oHzxXu341Q2ZIYUBuSdAwGMU4OSd_UOlS04NMPJERHHy3l8wIC_10qEKW5MEiPp6LAbUUeMae/s842/dk2_device_tree.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="755" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaMDHJxXgH828BKtJQAQQlKfgA90cg2nChu-UHc10rNkb6DXRbl2XpSzHLFD2KWya7wU2oHzxXu341Q2ZIYUBuSdAwGMU4OSd_UOlS04NMPJERHHy3l8wIC_10qEKW5MEiPp6LAbUUeMae/s320/dk2_device_tree.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.1] output/build/linux-5.7.1/arch/arm/boot/<b>stm32mp157c-dk2.dts</b></span></div><div><br /></div><div style="text-align: justify;">아래 그림은 STM32MP157 MPU의 memory map이다. Memory map은 memory mapped system(요즘 대부분의 embedded system의 유형, i/o device도 memory 주소로 인식)에서 다양한 장치의 register 주소 등을 파악하는데 도움을 준다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTyg1JGNfWrplFWHBDk6d6mVHaWH3a41t27fgDGkxPs6XeTTWCWb4F7N-azfkJJgkKdF_zB9OMaQhepLz5K_mhs9l40wX396GxZoDcy2LRx3nsZzVZLDfIENIe8r9fPeC4CVOip-LabKTn/s773/stm32mp157_memory_map.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="773" data-original-width="615" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTyg1JGNfWrplFWHBDk6d6mVHaWH3a41t27fgDGkxPs6XeTTWCWb4F7N-azfkJJgkKdF_zB9OMaQhepLz5K_mhs9l40wX396GxZoDcy2LRx3nsZzVZLDfIENIe8r9fPeC4CVOip-LabKTn/w319-h400/stm32mp157_memory_map.png" width="319" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.2] Memory map</span></div><div><br /></div><div><div style="text-align: justify;">이중, 우측 하단에 그려져 있는 i2c controller node의 종류 및 각각의 주소를 파악해 볼 필요가 있는데, 이를 device tree 파일 내용과 매뉴얼 내용(그림 5.3)을 토대로 정리해 보면 다음과 같다.</div><div style="text-align: justify;"><br /></div></div><div style="text-align: center;"><b style="background-color: #c6dafc;"><DK2 보드에서 사용하는 i2c controller></b></div><div style="text-align: center;"><b>i2c1: i2c@40012000</b></div><div style="text-align: center;"><b>i2c2: i2c@40013000</b></div><div style="text-align: center;"><b>i2c3: i2c@40014000</b></div><div style="text-align: center;"><font color="#9e9e9e"><b>i2c4: i2c@5c002000</b></font></div><div style="text-align: center;"><b>i2c5: i2c@40015000</b></div><div style="text-align: center;"><font color="#9e9e9e"><b>i2c6: i2c@5c009000</b></font></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh-4PnYzqU6ewiRI3d068XDpi0wJkDzQ98R01mNdJ1XOECOt_KvOIaCIMuH57uhh-6Ne5rVOE3bP8lvvjzQEZEbi3vAqwhB8nn2ZARjbHPmkhpo7Xsnke9mjk45D2maEhKs1lBUcJsQJ-q/s615/stm32mp1_memory_map_i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="528" data-original-width="615" height="344" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgh-4PnYzqU6ewiRI3d068XDpi0wJkDzQ98R01mNdJ1XOECOt_KvOIaCIMuH57uhh-6Ne5rVOE3bP8lvvjzQEZEbi3vAqwhB8nn2ZARjbHPmkhpo7Xsnke9mjk45D2maEhKs1lBUcJsQJ-q/w400-h344/stm32mp1_memory_map_i2c.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.3] i2c register 주소</div><div><span style="text-align: justify;"><br /></span></div><div><span style="text-align: justify;">DK2 보드의 block도를 살펴 보면 i2c device로는 어떤 것들이 있는지 한눈에 알 수가 같다. Device Tree 내용 분석에 앞서 아래 그림의 의미를 숙지할 필요가 있다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlu8GP7Q_WLbPns_jCHz6nlg7Mu5DvCa715JJH9FAooY88x4SGoUf13bN2QK1ergOZ6Zw-Uysb2glHptj34mXZTLBZxeZORTUl5jHaamMEq6e5WBIAmZcB7EmdwUokTp4DogdoqPzvRe0/s848/stm32mp157x_block_diagram2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="848" height="637" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlu8GP7Q_WLbPns_jCHz6nlg7Mu5DvCa715JJH9FAooY88x4SGoUf13bN2QK1ergOZ6Zw-Uysb2glHptj34mXZTLBZxeZORTUl5jHaamMEq6e5WBIAmZcB7EmdwUokTp4DogdoqPzvRe0/w640-h637/stm32mp157x_block_diagram2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.4] DK2 보드의 block diagram</div><div><br /></div><div>i2c controller node & device node와 관련해서는 여러 device tree file에 걸쳐 기술되어 있으므로, 각각의 내용을 하나씩 따져 보도록 하자.</div><div><br /></div><div>먼저 그림 5.5(<span style="text-align: center;"><b>stm32mp151.dtsi</b>)</span>에서 i2c controller node의 status 값을 확인해 본 결과, 모두 disabled되어 있는데, status="okay"로 정의하기 시작한 곳은 아래 그림 5.6-5.7<b>(<span style="text-align: center;">stm32mp15xx-dkx.dtsi)</span></b>에서 부터임을 알 수 있다. <span style="text-align: center;">stm32mp15xx-dkx.dtsi 파일은 i2c1과 i2c4 controller node와 그에 연결되어 있는 device node 만을 기술하고 있다.</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoMDEUy-D4EVFL2kxwecfOBJ5bHz1XKM_c8gqwZEx3ikSY6tIP9nyf6b3KfHh6YiIxnxcpRzlcYpFkXNvGVRlARWBpdmSSJ17RrC5XnKxJ0F5Y-vJ9We6rG43Z2AoNvB90moWTuDwrCKFK/s756/stm32mp151_dtsi.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="756" data-original-width="507" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoMDEUy-D4EVFL2kxwecfOBJ5bHz1XKM_c8gqwZEx3ikSY6tIP9nyf6b3KfHh6YiIxnxcpRzlcYpFkXNvGVRlARWBpdmSSJ17RrC5XnKxJ0F5Y-vJ9We6rG43Z2AoNvB90moWTuDwrCKFK/s320/stm32mp151_dtsi.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.5] <span style="text-align: center;">stm32mp151.dtsi 파일 내용 중 i2c controller node 부분(</span><font style="background-color: #f7cb4d; text-align: center;">모두 status="disabled"로 설정되어 있음)</font></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwfleSMoh3P0z70T8hqu6Leu1jIjEQh47XGyHismxYgeR92YLOlQwTXadg6ATWoacGhyS1idBD11eJJWjC9qn14_NJJXVcio0bOhyphenhyphenfI-ZhXQVHQyTgQv5P0mkBsRTdOnmdSXAdNfyxlrBO/s947/dk2_i2c1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="947" data-original-width="541" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwfleSMoh3P0z70T8hqu6Leu1jIjEQh47XGyHismxYgeR92YLOlQwTXadg6ATWoacGhyS1idBD11eJJWjC9qn14_NJJXVcio0bOhyphenhyphenfI-ZhXQVHQyTgQv5P0mkBsRTdOnmdSXAdNfyxlrBO/s320/dk2_i2c1.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.6] i2c1 controller node - <b><font color="#f57c00">stm32mp15xx-dkx.dtsi </font></b>파일에서 발췌</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><i2c1 controller & device node 내용 추출></b></div><div class="separator" style="clear: both; text-align: left;"><i> => i2c1 controller와 여기에 붙어 있는 i2c device를 요약해 보면 다음과 같다.</i></div><div class="separator" style="clear: both; text-align: left;"><i> => i2c1 controller에는 hdmi transceiver와 audio codec이 연결되어 있다.</i></div><div class="separator" style="clear: both; text-align: center;"><table border="1" bordercolor="#888" cellspacing="0" style="border-collapse: collapse; border-color: rgb(136, 136, 136); border-width: 1px;"><tbody><tr><td style="min-width: 60px;"><div style="text-align: justify;"><span style="text-align: center;"> &i2c1 {</span></div><div style="text-align: justify;"> status = "okay";</div><div style="text-align: justify;"> </div><div style="text-align: justify;"> hdmi-transmitter@39 { <b><font color="#0b8043">/* sii90022 HDMI transceiver */</font></b></div><div style="text-align: justify;"> compatible = "sil,sii9022";</div><div style="text-align: justify;"> reg = <0x39>;</div><div style="text-align: justify;"> }; </div><div style="text-align: justify;"><br /></div><div><div style="text-align: justify;"> cs42l51: cs42l51@4a { <b><font color="#0b8043">/* cs42151 audio codec */</font></b></div><div style="text-align: justify;"> compatible = "cirrus,cs42l51";</div><div style="text-align: justify;"> reg = <0x4a>;</div></div><div style="text-align: justify;"> };</div><div style="text-align: justify;">};</div></td></tr></tbody></table></div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: left;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEFApjH3cxQ6ManTxw5-EvlnhFL3-qOkw_nuauq2Noy1-o8mJQViKXDrZlOfw6YlsAD9m7F_fYdaf40Hw_06aHt7aYa0983i1LNxTIv_Up-FNfISCSgyoZM-fDOsylYnmFrM5P6AkOYm6u/s948/dk2_i2c4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="948" data-original-width="581" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEFApjH3cxQ6ManTxw5-EvlnhFL3-qOkw_nuauq2Noy1-o8mJQViKXDrZlOfw6YlsAD9m7F_fYdaf40Hw_06aHt7aYa0983i1LNxTIv_Up-FNfISCSgyoZM-fDOsylYnmFrM5P6AkOYm6u/s320/dk2_i2c4.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.7] i2c4 controller node - </span><b style="text-align: left;"><font color="#f57c00">stm32mp15xx-dkx.dtsi</font></b><span style="text-align: left;"> 파일에서 발췌</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div><div><div class="separator" style="clear: both; text-align: center;"><b><div style="text-align: left;"><b><i2c4 controller & device node 내용 추출></b></div></b></div><div class="separator" style="clear: both; text-align: left;"><i> => i2c4 controller node에는 PMIC device가 연결되어 있다.</i></div><div class="separator" style="clear: both; text-align: center;"><table border="1" bordercolor="#888" cellspacing="0" style="border-collapse: collapse; border-color: rgb(136, 136, 136); border-width: 1px;"><tbody><tr><td style="min-width: 60px;"><div style="text-align: justify;"><span style="text-align: center;"> &i2c4 {</span></div><div style="text-align: justify;"> status = "okay";</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"> <span style="text-align: center;">pmic: stpmic@33 {</span></div><div style="text-align: justify;"> compatible = "st,stpmic1"; <b style="text-align: center;"><font color="#0b8043">/* stpmic1 PMIC */</font></b></div><div style="text-align: justify;"> reg = <0x33>;</div><div style="text-align: justify;"> };</div><div style="text-align: justify;">};</div></td></tr></tbody></table><font color="#b51200" size="2"><div style="text-align: left;">[Tip] 그림 5.4의 block도와는 다르게 USB type-C용 device node(???)와 관련된 내용은 어디에도 보이질 않는다. 이는 아무래도 STM32MP157A-DK1 Discovery Board와 관련된 내용인 듯 싶다(stm32mp157a-dk1.dts 파일에는 관련 내용이 보임).</div></font></div></div><div><br /></div></div><div>마지막으로 <b>stm32mp157c-dk2.dts</b> 파일에는 i2c1 controller에 touch device(focaltech ft6236)를 추가한 내용(&i2c1의 & 표시는 override를 의미함)이 보인다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpqJEk101cyZzykCv2810B0cu7vHnO_V9BE-SXSHtTmmxGQQHo7rs3-6VYHk-NPfGmeMOurwC_AEX3SZLrOoQk8FeIpvUjFKFC-G-P86j-EueuQ9rcmW3k_gCIzjY7cUXwqnk-nLycippy/s375/dk2_i2c1_again.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="236" data-original-width="375" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpqJEk101cyZzykCv2810B0cu7vHnO_V9BE-SXSHtTmmxGQQHo7rs3-6VYHk-NPfGmeMOurwC_AEX3SZLrOoQk8FeIpvUjFKFC-G-P86j-EueuQ9rcmW3k_gCIzjY7cUXwqnk-nLycippy/s320/dk2_i2c1_again.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.8] i2c1 controller node - </span><span style="text-align: left;"><b><font color="#f57c00">stm32mp157c-dk2.dts</font></b> 파일에서 추출</span></div><div><br /></div><div>이상의 내용을 정리해 보면, 다음과 같다.</div><div> i2c1 controller <-------i2c bus--------> hdmi(<span style="text-align: justify;">sii9022, 0x39) | audio codec(</span><span style="text-align: justify;">cs42l51, 0x4a</span><span style="text-align: justify;">) | touch panel(f6236, 0x38)</span></div><div><span style="text-align: justify;"> i2c4 controller <-------i2c bus--------> pmic(stpmic1, 0x33)</span></div><div><span style="text-align: justify;"><br /></span></div><div><span style="text-align: justify;"><font color="#b51200" size="2">[Tip] i2c device는 reg=<0x38>과 같이 7bit i2c slave address(장치 구분용 주솟값)가 중요한 역할을 한다.</font></span></div><div><span style="text-align: justify;"><br /></span></div><div><span style="background-color: #f7cb4d;">i2c2, i2c3, i2c5 controller에는 아무런 device도 연결되어 있지 않음을 알 수가 있다. 따라서 얘네 들 </span><span style="background-color: #f7cb4d;"><span style="background-color: #f7cb4d;">중 하나에 HTU21D 온/습도 센서를 연결하면 좋을 것 같다는 생각이 든다.</span><span style="background-color: white;"> 물론 </span><span style="background-color: white;">이 중에서 확장 pin으로 정의된 녀석이어야 하지만 말이다.</span></span></div><div><br /></div><div><b style="color: #0b8043; font-size: large;">b) HTU21D 온/습도(temperature/humidity) 센서 연결</b></div><div>이번 절에서는 Measurement Specialties사가 제조하여 판매하는 HTU21D 온/습도 센서를 살펴 보고, 이를 DK2 보드와 어떻게 연결하는게 좋을지 살펴 보고자 한다.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj8nX3R4Sx2C1laM8MRAb62kKUsK9ImZhkdvBcqR09H-6UXtwT_xQJQ21muyY6VnMrBXm2iDJKNVQyXSl3wHvMnQ-jZ7a6unI0n1xzLYSu_At9weEvYfoSmbBgc5-I7W09Vv55TXDfYort/s320/htu21d_sensor_board.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="206" data-original-width="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj8nX3R4Sx2C1laM8MRAb62kKUsK9ImZhkdvBcqR09H-6UXtwT_xQJQ21muyY6VnMrBXm2iDJKNVQyXSl3wHvMnQ-jZ7a6unI0n1xzLYSu_At9weEvYfoSmbBgc5-I7W09Vv55TXDfYort/" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.9] HTU21D 온/습도 센서 외관</span></div><div><br /></div><div>아래 그림은 HTU21D의 회로도인데, HTU21D 센서 모듈은 Vdd(3.3V power), GND(ground), DATA(SDA), SCK(SCL) 4개의 pin이 외부로 표출되어 있다. 따라서 이를 DK2 board의 해당 pin에 1대1일로 연결해 주면 된다. 참고로, 회로도 아래 부분의 7 bit I2C address 0x40은 device tree 구현시 꼭 필요한 내용이다.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYzIo4MdKn9EYEkTKlRhMTOKP_3jhvo_m06JSeJXMp-MEHgiXmXCkhIfB8xWo02bhtXHBULSqhIo_fN93gIFPwNdj3Wa-pii2pCgradYXS16EjpFIBirPrIVHjT71tkvGxL5xDu49lrTIk/s442/htu21d_schematic.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="290" data-original-width="442" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYzIo4MdKn9EYEkTKlRhMTOKP_3jhvo_m06JSeJXMp-MEHgiXmXCkhIfB8xWo02bhtXHBULSqhIo_fN93gIFPwNdj3Wa-pii2pCgradYXS16EjpFIBirPrIVHjT71tkvGxL5xDu49lrTIk/w400-h263/htu21d_schematic.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.10] HTU21D 온/습도 센서 회로도</span></div><div class="separator" style="clear: both; text-align: center;"><div><br style="text-align: left;" /></div><div style="text-align: left;"><font color="#b51200" size="2">[Tip] 아주 당연한 얘기지만, HTU21D 센서 모듈은 VDD로 3.3V의 전원이 인가된다. 따라서 </font><span style="color: #b51200; font-size: small;">DK2의 5V VDD pin에 연결하지 않도록 주의하자.</span></div></div><div><br /></div><div>그럼, 이번에는 DK2 보드 확장 pin 중 i2c pin으로 사용 가능한 녀석을 찾아 보도록 하자.</div><div><br /></div><div>DK2 확장 pin에는 크게 다음과 같이 두 종류가 있다.</div><div> - Raspberry Pi 호환 connector(<b>CN2</b>) ....................................................... board top에 위치</div><div> - Arduino UNO 호환 connector(<b>CN13, CN14, C17, CN18</b>)가 있다. ........ board bottom에 위치</div><div><br /></div><div>먼저 아래 그림 5.11 ~ 5.12는 Raspberry Pi 호환 connector를 보여준다.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEOClVj1DW9kzIo9qxZ5sIPI03FPIvFDhTgn2VWHqzJHK2R9kHVTfO8WOZ5JdE-WvwdDhhtV6gHA7claGi4AIIIaZOCaZ8rffyOc1f57t6kkqaBB1tZr0J50-bxhG_bJbjHbEp6mda9vtY/s835/dk2_cn2_gpio_pin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="364" data-original-width="835" height="174" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEOClVj1DW9kzIo9qxZ5sIPI03FPIvFDhTgn2VWHqzJHK2R9kHVTfO8WOZ5JdE-WvwdDhhtV6gHA7claGi4AIIIaZOCaZ8rffyOc1f57t6kkqaBB1tZr0J50-bxhG_bJbjHbEp6mda9vtY/w400-h174/dk2_cn2_gpio_pin.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.11] CN2(Raspberry Pi 호환 pin) - 40 pin connector</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb_OdSWPIfsU2Yf130ATETPZfUheN8jVDXs24sl4AfkrNz5o1-eCi07d5KSvoHTkk2b3CJJEEInSuNN51jc24Y2YTzJfjsIzgDmy-8_PwSd-g7wisbKEbJUc7hCjbfF33k6Msh-HMT4xre/s955/dk2_gpio_i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="537" data-original-width="955" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhb_OdSWPIfsU2Yf130ATETPZfUheN8jVDXs24sl4AfkrNz5o1-eCi07d5KSvoHTkk2b3CJJEEInSuNN51jc24Y2YTzJfjsIzgDmy-8_PwSd-g7wisbKEbJUc7hCjbfF33k6Msh-HMT4xre/w640-h360/dk2_gpio_i2c.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.12] CN2 pin 중 I2C로 사용 가능한 pin - <b>pin 3, 5 &</b> <b>pin 27, 28</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">CN2 pin에서 i2c로 사용 가능한 pin을 살펴 보면, 다음과 같다</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: #f7cb4d; text-align: left;"><b>pin 3, 5 </b>= PA12, PA11 (i2c5 용) ..................................................................................... <b>(A)</b></span></div><div class="separator" style="clear: both; text-align: justify;"><span style="background-color: #f7cb4d; text-align: left;"><b>pin 27, 28</b> = PF15, PD12 (i2c1 용) ................................................................................. <b>(B)</b></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">다음으로 Arduino 호환 connector를 살펴 보도록 하자.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjblaBq9yjqnzAh5omjGuwTcZh_-_GaiRAbMDl-aE0b7-pf2UUuSfdjpzrv8HFpDqOVUA0ZuC3Get-n2urRpKGBquKr1oaglxyE4nF3xq979qQcOUIpfI_7lTegQiIP5Pa6Ku-lXSuvC8F7/s666/dk2_arduino.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="666" data-original-width="569" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjblaBq9yjqnzAh5omjGuwTcZh_-_GaiRAbMDl-aE0b7-pf2UUuSfdjpzrv8HFpDqOVUA0ZuC3Get-n2urRpKGBquKr1oaglxyE4nF3xq979qQcOUIpfI_7lTegQiIP5Pa6Ku-lXSuvC8F7/s320/dk2_arduino.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.13] CN13, CN14, CN17, CN18 Arduino connector</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8BD1BBGcc0fh7h6VfJTgaQNlN8iA1sjK4ZIF9F2aP0tHg7pbPYd42glvQfqdvHWqZAnkOgVccs6AiW5bDGc7_CkmOKHka9eoUwa9m_MIZDf2KeqMQSUZmfKAhg1arvWStHj9df4o9AgS7/s860/dk2_arduino_i2c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="68" data-original-width="860" height="50" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8BD1BBGcc0fh7h6VfJTgaQNlN8iA1sjK4ZIF9F2aP0tHg7pbPYd42glvQfqdvHWqZAnkOgVccs6AiW5bDGc7_CkmOKHka9eoUwa9m_MIZDf2KeqMQSUZmfKAhg1arvWStHj9df4o9AgS7/w640-h50/dk2_arduino_i2c.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDlzQeHEyi_rBm8XLcM6qRrcii7wBdpReI4RzzAqaTVMxD6COtn_bAvoihrifL8FYul99_7SpKpdcfITbcwyyxls7okL8dNf3FZU8t_tP8dgzbpWbFqzwwnBIWATCMVsTDimLuc1kCTiwV/s953/dk2_cn13_pin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="953" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDlzQeHEyi_rBm8XLcM6qRrcii7wBdpReI4RzzAqaTVMxD6COtn_bAvoihrifL8FYul99_7SpKpdcfITbcwyyxls7okL8dNf3FZU8t_tP8dgzbpWbFqzwwnBIWATCMVsTDimLuc1kCTiwV/w640-h246/dk2_cn13_pin.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.14] <font color="#b51200">Arduino connector 중 I2C로 사용 가능한 pin</font></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNOb6jHnd6p701-Wqky0rusZthboriD_o-qzc1-71BuPNjrVb9tW6Lt-T0DURZGg64TtKm01CBg8uBGlrHpvJMz4mAWigohVSSUwehd2tMBxqXbxSYeNtIR4sU8vHPUbKdI65t7ocyTaA6/s842/dk2_arduino_vcc_ground.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="238" data-original-width="842" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNOb6jHnd6p701-Wqky0rusZthboriD_o-qzc1-71BuPNjrVb9tW6Lt-T0DURZGg64TtKm01CBg8uBGlrHpvJMz4mAWigohVSSUwehd2tMBxqXbxSYeNtIR4sU8vHPUbKdI65t7ocyTaA6/w640-h180/dk2_arduino_vcc_ground.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.15] Arduino connector 중 VIN(Vcc), GND pin</div><div><br /></div><div><br /></div><div>Arduino pin 중 i2c 용으로 사용 가능한 pin은 딱 한쌍 뿐이다.</div><div><br /></div><div><span style="background-color: #f7cb4d;">CN13 pin 9, 10 = PA12, PA11(I2C5 용) ................................................................... <b>(C)</b></span></div><div><br /></div><div>이 세쌍의 pin(노락색으로 표시) 중, 어느 것을 사용해도 무방하나, 여기서는 (C) pin을 사용하도록 하겠다.</div><div><font color="#d52c1f" size="2">[Tip] CN2 pin은 불행하게도 (아래 그림과 같이) LCD screen 바로 아래에 위치하고 있어, jumper cable을 연결하기가 좀 불편해 보인다.</font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQ4RksksW1djhm44NNcF7fXs7wO9YOV_o8Vch-WVce_UzpdYTSIlOsdLrRtPCh9Dlib2md0BID15gXS8QvxCDDT5MU0LKugn1YAnQou2sYNkdZHxD5bI70pUs7jGuT8ryGN-MkSFydzr1/s4128/20200616_151716.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQ4RksksW1djhm44NNcF7fXs7wO9YOV_o8Vch-WVce_UzpdYTSIlOsdLrRtPCh9Dlib2md0BID15gXS8QvxCDDT5MU0LKugn1YAnQou2sYNkdZHxD5bI70pUs7jGuT8ryGN-MkSFydzr1/s320/20200616_151716.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.16] CN2 connector의 위치(<font color="#9e9e9e">jumper cable을 연결하기 좀 불편함</font>)</div><div><br /></div><div>======</div><div>드디어 센서 모듈이 도착했다. 😎 생각했던 것보다 크기가 작다(엄지 손톱 정도 크기다).</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTPZHpHQMo-CjU8ny6c_DNs_tuvVYqmBwTpEiX1fG_Wf_Z5ox843mnR6kg6gjcSKZ-nxfP_jfNRQZ_EJ8M-DmBJK814l_JXLEgUd52OdpeFFkUHiuN4GJRrirX-t3YB3HrxYuW4_CVAq68/s4128/20200616_163509.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4128" data-original-width="3096" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTPZHpHQMo-CjU8ny6c_DNs_tuvVYqmBwTpEiX1fG_Wf_Z5ox843mnR6kg6gjcSKZ-nxfP_jfNRQZ_EJ8M-DmBJK814l_JXLEgUd52OdpeFFkUHiuN4GJRrirX-t3YB3HrxYuW4_CVAq68/s320/20200616_163509.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.17] HTU21D 온습도 센서 모듈</div><div><br /></div><div>먼저 센서 모듈 쪽에 jumper cable을 연결해 보자.</div><div><br /></div><div><b>빨간색</b>: <font color="#b51200"><b>3.3V</b></font></div><div><b>갈색</b>(보통 검정색으로 연결): <b>GND</b></div><div><b>노란색</b>: <b><font color="#f7cb4d">SDA</font></b></div><div><b>녹색</b>: <font color="#0b8043"><b>SCL</b></font></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAgg1XgjsZ6BN2DNOPkC8eaynXFQYBeT0rjMKfr0Xw_q-HQyHSwDqim8b8KrTa4QWD0QEWKjTqMj2SOQDQd0Spu5T1y7j1xSBizFOEAa_fEEro6SDtjKB5Wr40Ft_Xn4JMf9Zq_i9kJVTc/s4128/20200616_165015.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAgg1XgjsZ6BN2DNOPkC8eaynXFQYBeT0rjMKfr0Xw_q-HQyHSwDqim8b8KrTa4QWD0QEWKjTqMj2SOQDQd0Spu5T1y7j1xSBizFOEAa_fEEro6SDtjKB5Wr40Ft_Xn4JMf9Zq_i9kJVTc/s320/20200616_165015.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.18] DK2 보드에 HTU21D 온/습도 센서 연결 모습(1)</div><div><br /></div><div><font color="#b51200" size="2">[Tip] 집에 납땜 용 인두가 없는 관계로, (좀 허접하지만) 스카치 테이프로 고정해 보았다.</font></div><div><br /></div><div>다음으로 해당 jumper cable을 (<font color="#9e9e9e">board 전원을 off한 상태에서</font>) target board에 연결해 보도록 하자.</div><div><br /></div><div><div style="text-align: left;"><b>빨간색</b>: <font color="#b51200" style="font-weight: bold;">3.3V </font><==================><font color="#b51200" style="font-weight: bold;"> </font><font style="font-weight: bold;">CN16 pin 4(V3.3)</font></div><div style="text-align: left;"><b>갈색</b>(보통 검정색으로 연결): <b>GND</b> <=============><b> CN16 pin 6(GND)</b></div><div style="text-align: left;"><b>노란색</b>: <font color="#f7cb4d" style="font-weight: bold;">SDA </font> <===============> <b>CN13 pin 9(ARD_D14)</b></div><div style="text-align: left;"><b>녹색</b>: <font color="#0b8043" style="font-weight: bold;">SCL </font> <===============> <b>CN13 pin 10(ARD_D15)</b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbuPyN-Kipveub_omMytXtADyBg8NoX_ej_vRpN_NQfWWxW03BDHZ6cVDaIr37-TzOQK1KpKifJNf2h4VIBEHPas0W1vziVTmiZCrSrNBuYtPfpinm5ATXGUA6iw6Xj45k0w5Q6Tu_uk9R/s4128/20200616_192844.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbuPyN-Kipveub_omMytXtADyBg8NoX_ej_vRpN_NQfWWxW03BDHZ6cVDaIr37-TzOQK1KpKifJNf2h4VIBEHPas0W1vziVTmiZCrSrNBuYtPfpinm5ATXGUA6iw6Xj45k0w5Q6Tu_uk9R/w400-h300/20200616_192844.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.19] DK2 보드에 HTU21D 온/습도 센서 연결 모습(2)</div><div><br /></div><div>전원을 켜고 동작을 확인하기 위해서는 device tree 및 device driver 관련 작업을 해야 한다. 따라서 아래 내용을 계속 살펴 보도록 하자.</div><div><br /></div><div><div><b style="color: #0b8043; font-size: large;">c) HTU21D 온/습도 센서 연결을 위한 device tree 작업</b></div><div>앞 절에서 HTU21D 센서를 DK2 보드의 i2c5 controller에 연결하는 것까지 설명하였다. 따라서 이 절에서는 이를 device tree로 구현하는 내용을 소개해 본다.</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOfEnByOvA2oQYT1OoP-U-t3TbzriuFQlppYqTXlUIbxSjlRNQEgZ0robZDDQQOGU7Vpr_RwRHsTdyMZnYm3t7sllzaqTIliiKzwwK2zsuvqkm8WRYgldqHCk3Q3He8sXJRqO7LXJqR4uH/s460/dk2_i2c_device_tree.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="251" data-original-width="460" height="219" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOfEnByOvA2oQYT1OoP-U-t3TbzriuFQlppYqTXlUIbxSjlRNQEgZ0robZDDQQOGU7Vpr_RwRHsTdyMZnYm3t7sllzaqTIliiKzwwK2zsuvqkm8WRYgldqHCk3Q3He8sXJRqO7LXJqR4uH/w400-h219/dk2_i2c_device_tree.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.20] linux-5.7.1/arch/arm/boot/dts/<b>stm32mp157c-dk2.dts</b> 파일 수정 내용</div><div><br /></div><div>먼저 <b>status = "okay"</b>로 해야 i2c5 controller node를 사용할 수 있다.</div><div><b>clock-frequency = <100000></b> 는 i2c5 bus speed를 100kHz로 지정한 것이다. 이는 "STM32MP157 advanced Arm-based 32bit-bit MPUs" Reference manual(section 52.2)을 참조하여 결정하였다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMMcsTq3s65qoyW3CtpO9nAAKhzl5bUzJiCSjocMAXpIAYIHkQBa50-FpnMAeClSosegYVVoYAXYn8DEFXxDjxmFt1sMbY6ocx7BFC8pMXx9_yTztE-6O2JN67ENEw-CqkeF0MtxfvNr0t/s708/dk2_i2c_feature.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="512" data-original-width="708" height="289" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMMcsTq3s65qoyW3CtpO9nAAKhzl5bUzJiCSjocMAXpIAYIHkQBa50-FpnMAeClSosegYVVoYAXYn8DEFXxDjxmFt1sMbY6ocx7BFC8pMXx9_yTztE-6O2JN67ENEw-CqkeF0MtxfvNr0t/w400-h289/dk2_i2c_feature.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><b>pinctrl </b>관련 3줄은 pin muxing과 관련된 것이다. 보통은 pinctrl-names와 pinctrl-0만 설정하면 되나, 다른 i2c controller를 참조하여 pinctrol-1(sleep mode 용)도 추가해 주었다.</div><div><br /></div><div><div><b> pinctrl-names = "default", "sleep";</b></div><div><b> pinctrl-0 = <&i2c5_pins_a>;</b></div><div><b> pinctrl-1 = <&i2c5_pins_sleep_a>;</b></div></div><div><br /></div><div><font color="#b51200" size="2">[Tip] 위의 설정은 해도 그만 안해도 그만인 설정이 아니라, 반드시 해 주어야 하는 설정이다. i2c5 controller를 위한 pin(SDA, SCK)은 다른 pin(예: GPIO)과 pin muxing이 되어 있기 때문에, 정확한 pinmux 설정을 통해 i2c 용으로 사용 가능하게 만들어야 한다.</font></div><div><br /></div><div>위의 i2c5_pins_a 및 i2c5_pins_sleep_a에 대한 정보는 아래 파일에 이미 정의되어 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijNw4govHn6vzIrSPUGsporloyBr6m-VSaNBOeelHqVyxqoQ1aGHpuqaiTnQJr44uyTN1mOz4DPLSqVd1ttiH72bZnXw3wqU0S2G-VR6XDnJNk-RVikKq6nFoWmCTISWf89ZIp7kESJ7BM/s613/dk2_i2c5_pinctrl.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="329" data-original-width="613" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijNw4govHn6vzIrSPUGsporloyBr6m-VSaNBOeelHqVyxqoQ1aGHpuqaiTnQJr44uyTN1mOz4DPLSqVd1ttiH72bZnXw3wqU0S2G-VR6XDnJNk-RVikKq6nFoWmCTISWf89ZIp7kESJ7BM/w400-h215/dk2_i2c5_pinctrl.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.21] <b>stm32mp15-pinctrl.dtsi</b> 파일에서 발췌</div><div><div><br /></div><div>위의 내용 중 <b><font color="#9c27b0">STM32_PINMUX</font></b> macro는 다시 아래 파일에 정의되어 있다. 아래 내용의 정확한 의미를 파악하기 위해서는 <a href="https://www.st.com/resource/en/datasheet/stm32mp157c.pdf">DK2 board user manual</a> 내용 중 pin mux 관련 테이블을 확인할 필요가 있다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirKgLFIxk-F8l7zvjpjq-OHy-bM-VGf7guncWRSgcJ7d9iCZA7RE_hWZWclypsUT4PlAZrUWBz3C2OM9IoXTljy3LpDlSYto-r5gzgCo-rT_4uiesTMXAczU1BKwxYDnAmL9JOemBbKZWM/s717/dk2_stm32_pinmux.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="646" data-original-width="717" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirKgLFIxk-F8l7zvjpjq-OHy-bM-VGf7guncWRSgcJ7d9iCZA7RE_hWZWclypsUT4PlAZrUWBz3C2OM9IoXTljy3LpDlSYto-r5gzgCo-rT_4uiesTMXAczU1BKwxYDnAmL9JOemBbKZWM/w400-h360/dk2_stm32_pinmux.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.22] include/dt-bindings/pinctrl/<b>stm32-pinfunc.h </b>파일 내용</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf8l5buEZysI_r0vDSHKJQr3W778kuDePIZuR3xZGi-ZkDOk3rwqCTxVCcxJjWm4bBiqLhepqXk1q2fQkZWXq-lovCYVp_hShLpqYMONH9ZHTecOONl_CnX5o4fXeo51aDp3Qhyphenhyphenh553daZ/s745/stm32mp157c_PA11.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="224" data-original-width="745" height="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf8l5buEZysI_r0vDSHKJQr3W778kuDePIZuR3xZGi-ZkDOk3rwqCTxVCcxJjWm4bBiqLhepqXk1q2fQkZWXq-lovCYVp_hShLpqYMONH9ZHTecOONl_CnX5o4fXeo51aDp3Qhyphenhyphenh553daZ/w640-h192/stm32mp157c_PA11.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTGwMLrferoknLWkdNWQjRqSrr-633Q2m04eWLSnT4E3I3o5yRZWHc4FhfE3ZTjCngKR_7M1rJEnpnOCURDNw-61KwPoJJC_d3gl2gQteQQz-T4dj6wEcO7iNXz5Ez0JCDtcXDIHgYyxuk/s746/stm23mp157c_PA12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="98" data-original-width="746" height="84" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTGwMLrferoknLWkdNWQjRqSrr-633Q2m04eWLSnT4E3I3o5yRZWHc4FhfE3ZTjCngKR_7M1rJEnpnOCURDNw-61KwPoJJC_d3gl2gQteQQz-T4dj6wEcO7iNXz5Ez0JCDtcXDIHgYyxuk/w640-h84/stm23mp157c_PA12.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: justify;"><span style="color: #b51200; font-size: small; text-align: left;">[Tip] 위의 내용에는 불행하게도 아래 코드(</span><span style="color: #b51200; font-size: small;">stm32-pinfunc.h)에 기술된 AFX 값에 대한 부분이 표시되어 있지 않다.</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">암튼, 여러가지 정황으로 봐서는 'A', 11 => PA11, 'A', 12 => PA12를 뜻하며, <span style="background-color: #f7cb4d;">AF4 = 0x5(mode 값)로 지정해야 i2c 용으로 사용 가능한 것 같다.</span> 참고로, AF4 자리에 0x0을 지정하면 GPIO로 사용된다.</div><div class="separator" style="clear: both; text-align: left;">-----------------------------------</div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;">pinmux = <STM32_PINMUX('A', 11, AF4)>, /* I2C5_SCL */</div><div class="separator" style="clear: both;"> <STM32_PINMUX('A', 12, AF4)>; /* I2C5_SDA */</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0yPcZ6CpRrWzCR2P58-GvqcHdbMv64_tqQJyMCYaaGHr3rJ0Z1e4F5AuBF7gxBQBS-b9-o0loffUHj80NDUXhRE26ojju2jqhuohW0Yx95OgIZzD9XWe209rgx3GN0edMV-0ab0wwoR8_/s798/dk2_cn13_pa11_12.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="67" data-original-width="798" height="54" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0yPcZ6CpRrWzCR2P58-GvqcHdbMv64_tqQJyMCYaaGHr3rJ0Z1e4F5AuBF7gxBQBS-b9-o0loffUHj80NDUXhRE26ojju2jqhuohW0Yx95OgIZzD9XWe209rgx3GN0edMV-0ab0wwoR8_/w640-h54/dk2_cn13_pa11_12.png" width="640" /></a></div><div>-----------------------------------</div><div><font color="#b51200" size="2">[Tip] AF는 Alternate Function을 뜻한다. stm32mpu pinctrl과 관련해서는 아래 문서를 참조할 필요가 있다.</font></div><div><br /></div><div style="text-align: center;">Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS8Gm3V3WJ31oMKYl8SerteOTR8oFMtlnWoLb2_5I8YSaArf7rc8YdEVBaAdnDP9F9r2O0BmB59jWaRF1XhtQOSw-jkp696NwadG-TYIWKt3tPHM13g0crudlSwgL-e-HoQ4ocbc9LANZg/s805/dk2_pintrl.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="765" data-original-width="805" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiS8Gm3V3WJ31oMKYl8SerteOTR8oFMtlnWoLb2_5I8YSaArf7rc8YdEVBaAdnDP9F9r2O0BmB59jWaRF1XhtQOSw-jkp696NwadG-TYIWKt3tPHM13g0crudlSwgL-e-HoQ4ocbc9LANZg/w400-h380/dk2_pintrl.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.23] st,stm32-pinctrl.yaml에서 발췌한 내용</div><div><br /></div><div><b style="background-color: #f7cb4d;"><여기서 잠깐 !></b></div><div>-----------------------------</div><div>아래 내용은 foo device(가상의 device)에 대해 pinctrl 설정을 어떻게 하는지를 소개하고 있다. 이 내용은 앞서 설명한 pinmux의 내용을 이해하는데 도움을 준다.</div><div><br /></div><div style="text-align: justify;"><a href="https://wiki.st.com/stm32mpu/wiki/Pinctrl_device_tree_configuration" style="text-align: center;">https://wiki.st.com/stm32mpu/wiki/Pinctrl_device_tree_configuration</a></div><div><br /></div><div>조건:</div><div><i> - foo device는 PC13, PG8, PI2 번 pin을 사용한다.</i></div><div><i> - AF2는 P13 pin의 alternate function이고,</i></div><div><i> - AF5는 PG8과 PI2의 alternate function 이다.</i></div><div><i> - 각 pin은 내부에 pull-up 저항을 필요로 한다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhmhRU861UNDDnadYJReyiVJG2yL5Bi6xmKHjLS8lvruAT2SUw6r48wuGyGxPfgJhSNbVyJfy2RL2x9HrPPugZes_fr7YsuMglI5c5Je4GSxnp5b__cYCUlkZ2dVEZRG-wyJCIyXlTe2cc/s780/stm32mpu_foo_device_pinctrl.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="272" data-original-width="780" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhmhRU861UNDDnadYJReyiVJG2yL5Bi6xmKHjLS8lvruAT2SUw6r48wuGyGxPfgJhSNbVyJfy2RL2x9HrPPugZes_fr7YsuMglI5c5Je4GSxnp5b__cYCUlkZ2dVEZRG-wyJCIyXlTe2cc/w640-h224/stm32mpu_foo_device_pinctrl.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIN15Vqo7EUcbCz7NHHnETIUiLhotTvSlg_tSrvXnid5CnvgWvC2UHbkQ1EzzlnK6Qq5Quee2QReQIbggXz7m9n1U4ALqDhUcfr6kAUqo9jEmhNCI6FWwBxMxMv-tDf5lCTiWzuqMGlS9F/s774/stm32mpu_foo_node.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="151" data-original-width="774" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIN15Vqo7EUcbCz7NHHnETIUiLhotTvSlg_tSrvXnid5CnvgWvC2UHbkQ1EzzlnK6Qq5Quee2QReQIbggXz7m9n1U4ALqDhUcfr6kAUqo9jEmhNCI6FWwBxMxMv-tDf5lCTiWzuqMGlS9F/w640-h124/stm32mpu_foo_node.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.24] foo device에 pinctrl 예제</div><div>-----------------------------</div><div><br /></div><div><font color="#9e9e9e">(다시 htu21d 관련 device tree 구현 내용으로 돌아와서) </font>마지막으로 추가된 부분은 i2c5 controller bus에 붙어 있는 htu21d 온/습도 센서 node에 관한 내용이다. 이를 위해서는 Documentation/devicetree/bindings/iio/humidity/htu21.txt 파일을 확인해 볼 필요가 있다.</div><div><br /></div><div><b> htu21: htu21@40 {</b></div><div><b> compatible = "<font color="#b51200">meas,htu21</font>";</b></div><div><b> reg = <<font color="#b51200">0x40</font>>;</b></div><div><b> };</b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcwQYEWRntyAWks6MEsn6E2lzV0CrSMkzCi-aiHFYS0oZgGzLJD5TuoiSFRehUVwQaFJssMetZUjzC4AIsyZndeZhc_1vCrYxLoqRAEwh1LikBHoYeP3dXJIRlhLZsE0sKnTeHqMseWaKd/s916/dk2_docu_binding_htu21.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="263" data-original-width="916" height="115" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcwQYEWRntyAWks6MEsn6E2lzV0CrSMkzCi-aiHFYS0oZgGzLJD5TuoiSFRehUVwQaFJssMetZUjzC4AIsyZndeZhc_1vCrYxLoqRAEwh1LikBHoYeP3dXJIRlhLZsE0sKnTeHqMseWaKd/w400-h115/dk2_docu_binding_htu21.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 5.25] <span style="text-align: left;">Documentation/devicetree/bindings/iio/humidity/htu21.txt 파일 내용</span></div><div><br /></div><div><br /></div><div><b style="color: #0b8043; font-size: large;">d) HTU21D 온/습도 센서 device driver 분석</b></div><div>앞서 HTU21D용 device tree 작업을 하였으니, 이제는 이를 기반으로 실제 동작을 담당하는 device driver 코드를 작성할 차례이다.</div><div><br /></div><div>HTU21D 온/습도 센서용 device driver는 이미 mainline kernel에 포함되어 있다(<font color="#9e9e9e">일부러 device driver가 구현되어 있는 센서를 찾았다</font>).</div><div><br /></div><div style="text-align: center;"><b>linux-5.7.1/drivers/iio/humidity/htu21.c</b></div><div><br /></div><div>HTU21D 온/습도 센서는 IIO(Industiral I/O) subsystem framework을 이용하여 구현되어 있는데, 이러한 범주에 속하는 device들에는 다음과 같은 것들이 있다.</div><div><br /></div><div><ul class="simple" style="background-color: #fcfcfc; box-sizing: border-box; font-family: serif; font-size: 16px; line-height: 24px; list-style-image: initial; list-style-position: initial; margin: 0px 0px 24px; padding: 0px;"><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">analog to digital converters (ADCs)</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">accelerometers</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">capacitance to digital converters (CDCs)</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">digital to analog converters (DACs)</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">gyroscopes</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">inertial measurement units (IMUs)</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">color and light sensors</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">magnetometers</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">pressure sensors</font></li><li style="box-sizing: border-box; list-style: disc; margin-left: 24px;"><font size="2">proximity sensors</font></li><li style="box-sizing: border-box; list-style: disc; margin-bottom: 12px; margin-left: 24px;"><font size="2">temperature sensors</font></li></ul></div><div style="text-align: center;"><a href="https://www.kernel.org/doc/html/v4.14/driver-api/iio/index.html">https://www.kernel.org/doc/html/v4.14/driver-api/iio/index.html</a></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjndWszc4XFWSKhgTyWPeQM7kN9eQ65r1EfTi5vOp0IWQm7o5nJ4OlIB25U3SdRkXLCahBpYjrVkuyhd2MqT5ETlknlaOhAR5pnDFxU3TogdfG32f32Vya3bjeW1OaaBt8dQvAxMZNH5waa/s776/iio_arch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="652" data-original-width="776" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjndWszc4XFWSKhgTyWPeQM7kN9eQ65r1EfTi5vOp0IWQm7o5nJ4OlIB25U3SdRkXLCahBpYjrVkuyhd2MqT5ETlknlaOhAR5pnDFxU3TogdfG32f32Vya3bjeW1OaaBt8dQvAxMZNH5waa/s320/iio_arch.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.26] Industrial I/O subsystem 아키텍쳐(1)</span></div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd2a7_uTnhQM1JoJBTzsPrKurSTPKU-ZFRXtEc00J24Lg9pKXUZvZuUouyOd1hoHxsXY38YPGoqqTjvsklPjObHOWgKDTJ5V5CVDH3imSRTk-BPLOR6avgi_2SMWTSGSJO-WMOTUOg6TEO/s654/iio_arch3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="654" data-original-width="308" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd2a7_uTnhQM1JoJBTzsPrKurSTPKU-ZFRXtEc00J24Lg9pKXUZvZuUouyOd1hoHxsXY38YPGoqqTjvsklPjObHOWgKDTJ5V5CVDH3imSRTk-BPLOR6avgi_2SMWTSGSJO-WMOTUOg6TEO/s320/iio_arch3.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.27] Industrial I/O subsystem 아키텍쳐(2)</span></div><div style="text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcXlrV4HLiDD22JuhPwFWLs_weQXdj_3f01Xl216VR5r4vvzgcLQ2OplydaTeS7mgaD4qGFlEdJUDYU4RrNXvCwpVTvNZIIbnj8A4Zd8sajZQTY2wcg0wRtttGCA1S3T1pmf9u1I5hY6oE/s763/htu21_driver1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="532" data-original-width="763" height="279" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcXlrV4HLiDD22JuhPwFWLs_weQXdj_3f01Xl216VR5r4vvzgcLQ2OplydaTeS7mgaD4qGFlEdJUDYU4RrNXvCwpVTvNZIIbnj8A4Zd8sajZQTY2wcg0wRtttGCA1S3T1pmf9u1I5hY6oE/w400-h279/htu21_driver1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.28] linux-5.7.1/drivers/iio/humidity/htu21.c</span></div><div><br /></div><div>probe 함수를 중심으로 주요 코드 흐름을 정리해 보면 다음과 같다.</div><div>==================</div><div><div><b>struct <font color="#d52c1f">ms_ht_dev</font></b> { </div><div> struct i2c_client *client; </div><div> struct mutex lock;</div><div> u8 res_index;</div><div>};</div></div><div><br /></div><div><div>static int <b><font color="#4285f4">htu21_read_raw</font></b>(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask)</div></div><div>{</div><div> <b><i> ...</i></b></div><div>}</div><div><br /></div><div><div>static int <b><font color="#4285f4">htu21_write_raw</font></b>(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)</div></div><div>{</div><div> <b><i> ...</i></b></div><div>}</div><div><br /></div><div><div>static const struct iio_info <b><font color="#f4a900">htu21_info</font></b> = {</div><div> .read_raw = <b><font color="#4285f4">htu21_read_raw</font></b>,</div><div> .write_raw = <b><font color="#4285f4">htu21_write_raw</font></b>,</div><div> .attrs = &htu21_attribute_group,</div><div>};</div></div><div><br /></div><div><div>static const struct iio_chan_spec <b><font color="#9c27b0">htu21_channels</font></b>[] = {</div><div> {</div><div> .type = IIO_TEMP,</div><div> .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),</div><div> .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),</div><div> },</div><div> {</div><div> .type = IIO_HUMIDITYRELATIVE,</div><div> .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_PROCESSED),</div><div> .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),</div><div> }</div><div>};</div></div><div><br /></div><div>static int <b><font color="#0b8043">htu21_probe</font></b>(struct i2c_client *client, const struct i2c_device_id *id)</div><div>{</div><div><div> <b> struct <font color="#d52c1f">ms_ht_dev</font> *dev_data;</b></div><div> <b>struct iio_dev *indio_dev;</b></div></div><div><br /></div><div> indio_dev = <b>devm_iio_device_alloc</b>(&client->dev, sizeof(*dev_data));</div><div><br /></div><div><div> dev_data = iio_priv(indio_dev);</div><div> dev_data->client = client;</div><div> dev_data->res_index = 0;</div><div> </div><div> indio_dev->info = &<font color="#f4a900"><b>htu21_info</b></font>;</div><div> indio_dev->name = id->name;</div><div> indio_dev->dev.parent = &client->dev;</div><div> indio_dev->modes = INDIO_DIRECT_MODE;</div></div><div> </div><div><div> indio_dev->channels = <b><font color="#9c27b0">htu21_channels</font></b>;</div><div> indio_dev->num_channels = ARRAY_SIZE(htu21_channels);</div></div><div><br /></div><div> <b> i2c_set_clientdata</b>(client, indio_dev);</div><div><br /></div><div> ms_sensors_reset(client, HTU21_RESET, 15000);</div><div><br /></div><div> ms_sensors_read_serial(client, &serial_number);</div><div><br /></div><div> return <b>devm_iio_device_register</b>(&client->dev, indio_dev);</div><div>}</div><div><br /></div><div><div>static struct i2c_driver htu21_driver = {</div><div> .probe = <b><font color="#0b8043">htu21_probe</font></b>,</div><div> .id_table = htu21_id,</div><div> .driver = {</div><div> .name = "htu21",</div><div> .of_match_table = of_match_ptr(htu21_of_match),</div><div> },</div><div>};</div></div><div>==================</div><div><br /></div><div>마지막으로 아래 앞서 정의한 device tree와 device driver를 연결 시켜 주는 코드는 아래(그림 5.29)와 같다.</div><div><br /></div><div><div> htu21: htu21@40 {</div><div> <font color="#b51200">compatible = "meas,htu21";</font></div><div> reg = <0x40>;</div><div> };</div></div><div><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Ri22TCqbFZLl3wMzySLBG8AwQVIWL26GiufSx07oRe_fsptsS5zoILWsb0FS_61RMrna0y0uokTk9500qKQYMVcGecf7wzRfZfbY185rQ6262gz_Mx7QhCJ8gMuf3IqrpN0OikKo01V5/s489/dk2_htu_device_driver_compat.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="126" data-original-width="489" height="103" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0Ri22TCqbFZLl3wMzySLBG8AwQVIWL26GiufSx07oRe_fsptsS5zoILWsb0FS_61RMrna0y0uokTk9500qKQYMVcGecf7wzRfZfbY185rQ6262gz_Mx7QhCJ8gMuf3IqrpN0OikKo01V5/w400-h103/dk2_htu_device_driver_compat.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.29] htu21 driver compatible 정보</span></div><div><br /></div><div><br /></div><div><b style="color: #0b8043; font-size: large;">e) HTU21D 온/습도 센서 동작 시험</b></div><div>자, 모든 것이 준비되었으니, 수정한 device tree를 포함한 상태에서 kernel을 재 build하여 보도록 하자.</div><div><br /></div><div>$ <b>make linux-menuconfig</b></div><div><i> => 먼저 앞절에서 설명한 htu21d device driver를 enable시켜야 한다.</i></div><div><i> => Device Drivers ==> Industrial I/O support ==> Humidity sensors ==></i></div><div><i> <font color="#f57c00"><*> Measurement Specialties HTU21 humidity & temperature sensor</font></i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQsa_upI-HfKnU6hS0ic7l5nk3VVXXxqho_q1q5BzW4D3ZvGMx0cFO4gPVVdOWKLaUYSABvjuCRgnNTRXDs5H0nwARTkWxBJJjPICZ1e1YalEbF_U2Eh7c2CZ7xGJs5q334VEkhbmK3U_j/s899/dk2_linux_menuconfig_htu21.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="612" data-original-width="899" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQsa_upI-HfKnU6hS0ic7l5nk3VVXXxqho_q1q5BzW4D3ZvGMx0cFO4gPVVdOWKLaUYSABvjuCRgnNTRXDs5H0nwARTkWxBJJjPICZ1e1YalEbF_U2Eh7c2CZ7xGJs5q334VEkhbmK3U_j/w400-h272/dk2_linux_menuconfig_htu21.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.30] HTU21 humidity sensor enable</span></div><div><br /></div><div>$ <b>make linux-update-defconfig</b></div><div><span><i> => 앞서 수정한 kernel config를 저장한다.</i></span><br /></div><div><span><i> => </i></span><i>board/stmicroelectronics/stm32mp157c-dk2/linux.config 파일에 관련 내용이 저장된다.</i></div><div><br /></div><div>$ <b>make</b></div><div><div><i> => 앞서 수정한 kernel config와 device tree 내용이 반영되어 build된다.</i></div><div><br /></div><div>$ cd output/images</div><div>$ ls -la</div><div><font size="2">합계 132180</font></div><div><font size="2">drwxr-xr-x 3 chyi chyi 4096 6월 16 17:03 .</font></div><div><font size="2">drwxr-xr-x 6 chyi chyi 4096 6월 16 17:03 ..</font></div><div><font size="2">-rw-r--r-- 1 chyi chyi 125829120 6월 16 17:03 rootfs.ext2</font></div><div><font size="2">lrwxrwxrwx 1 chyi chyi 11 6월 16 17:03 rootfs.ext4 -> rootfs.ext2</font></div><div><font size="2">-rw-r--r-- 1 chyi chyi 126822400 6월 16 17:03 sdcard.img</font></div><div><b><font size="2">-rwxr-xr-x 1 chyi chyi 49696 6월 16 17:02 stm32mp157c-dk2.dtb</font></b></div><div><font size="2">drwxr-xr-x 2 chyi chyi 4096 6월 12 15:37 tmp</font></div><div><font size="2">-rw-r--r-- 1 chyi chyi 75983 6월 12 10:30 u-boot-spl.stm32</font></div><div><font size="2">-rw-r--r-- 1 chyi chyi 806344 6월 12 10:29 u-boot.img</font></div><div><b><font size="2">-rw-r--r-- 1 chyi chyi 4155936 6월 16 17:02 zImage</font></b></div></div><div><br /></div><div>Target board의 zImage 및 stm32mp157c-dk2.dtb 파일(/boot 디렉토리에 있음)과 파일 크기를 비교해 보니, 차이가 나는 것으로 보아, 정상적으로 build가 된 것 같다.</div><div><br /></div><div>Build 결과물을 dd로 microSD에 full writing을 할게 아니라, 이번에는 zImage와 dtb 파일만 target board로 복사하여 사용해 보자.</div><div><br /></div><div><b><Desktop PC></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGAyG6JwYSZrmnHTqzIbe-uB75YwHuquo9khpo7O6YhGMjsGwPbHHjTsfhPAii5yQY6ChqYgf6iCpMDbXncygCfa2K4QXUXRwQ1VuH_RFPDlLFgQjI173VsCkeWQxqiWbaYxiyE2wXgDKN/s920/dk2_scp_zImage.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="158" data-original-width="920" height="110" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGAyG6JwYSZrmnHTqzIbe-uB75YwHuquo9khpo7O6YhGMjsGwPbHHjTsfhPAii5yQY6ChqYgf6iCpMDbXncygCfa2K4QXUXRwQ1VuH_RFPDlLFgQjI173VsCkeWQxqiWbaYxiyE2wXgDKN/w640-h110/dk2_scp_zImage.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.31] scp로 zImage와 dtb 파일 upload</span></div><div><br /></div><div><b><Target board></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3jxSyYpkf5zuyda4tzn0epXa9HN_OnuWivJJdkUX5p4EBHrhsEbslWi9ufvhaWNkGUwW10VpirEe3cV9OYezmBa_PCQk6AionDUK_pNVZ650VXQU0wafhRbQPOHFbQpBP6kXM5JyqOjdZ/s737/dk2_boot_copy.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="342" data-original-width="737" height="185" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3jxSyYpkf5zuyda4tzn0epXa9HN_OnuWivJJdkUX5p4EBHrhsEbslWi9ufvhaWNkGUwW10VpirEe3cV9OYezmBa_PCQk6AionDUK_pNVZ650VXQU0wafhRbQPOHFbQpBP6kXM5JyqOjdZ/w400-h185/dk2_boot_copy.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.32] zImage와 dtb 파일을 /boot 디렉토리로 복사</span></div><div><br /></div><div># sync; sync</div><div># <b>reboot</b></div><div><br /></div><div>자, 이제 target board가 재 부팅되었으니, htu21d 온/습도 센서가 정상 동작하는지를 확인해 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7jImDqQnDcY4c2bQs9cSq95RkaUQzAUqbeWh6ddEQf9ebSss_JLkol2LMYH6LRcgw8W_RDsbu7zsNlMwQHqpm6VSQNWUk5N0xYgIASMKqx3ZqhriZa29Apgc2GmRDLPzyVe0_5AcC0REt/s643/dk2_htu21d_dmesg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="237" data-original-width="643" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7jImDqQnDcY4c2bQs9cSq95RkaUQzAUqbeWh6ddEQf9ebSss_JLkol2LMYH6LRcgw8W_RDsbu7zsNlMwQHqpm6VSQNWUk5N0xYgIASMKqx3ZqhriZa29Apgc2GmRDLPzyVe0_5AcC0REt/w400-h148/dk2_htu21d_dmesg.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.33] kernel booting messages</span></div><div><br /></div><div>먼저 /sys/bus/i2c/devices 디렉토리 아래에서 <b style="text-align: center;">i2c5: i2c@40015000</b><span style="text-align: center;">가 i2c device 몇번 bus로 인식되지를 확인해 보자.</span></div><div><span style="text-align: center;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNPEbu8O3d592iUDDxOTfx4xXLTdIqj6HrY5n5E9Okoofl6M5VqgDemKX348iGBr0VuP_jIhirixATCEE0FKgiiaJ0pHGzQCBqQRDa3X_cXyuthYNuHTXIPZ84MOEY-eqLjBwJgXzeF8Cl/s1107/dk2_i2c_devices.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="287" data-original-width="1107" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNPEbu8O3d592iUDDxOTfx4xXLTdIqj6HrY5n5E9Okoofl6M5VqgDemKX348iGBr0VuP_jIhirixATCEE0FKgiiaJ0pHGzQCBqQRDa3X_cXyuthYNuHTXIPZ84MOEY-eqLjBwJgXzeF8Cl/w640-h166/dk2_i2c_devices.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.34] /sys/bus/i2c/devices 내용 확인</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div style="text-align: center;"><b>i2c-2 -> ../../../devices/platform/soc/<font color="#b51200">40015000</font>.i2c/i2c-2</b></div><div style="text-align: center;"><b><br /></b></div><div>두번째(i2c-<b><font color="#b51200">2</font></b>)로 인식되고 있다. 그러면 busybox에 기본으로 포함되어 있는 <b>i2cdetect</b> 명령으로 i2c5 controller에 i2c device가 붙어 있는지를 확인해 보자. 아래 그림을 보면 알 수 있는 바와 같이 1개의 i2c device가 보이는데, 0x40 번지를 사용하고 있다. 이는 앞서 DK2 보드에 장착한 HTU21D 센서 모듈에 해당한다. 이로써 센서 연결이 (1차적으로) 정상임을 알 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiku8DiDRrF-ZzWteIbPqAX_YFMFh__pBKUR4fS7w7evd1e-B4uVx1jxi0So8CzdmpEtrRMvx_GtS1q6nGDAl5AqrUqiWVwaTEfCOjOd8Iltx3r35PNfp_q_ub5QG4mkbNTZ1SQ36vxgYKg/s472/dk2_i2cdetect.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="199" data-original-width="472" height="169" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiku8DiDRrF-ZzWteIbPqAX_YFMFh__pBKUR4fS7w7evd1e-B4uVx1jxi0So8CzdmpEtrRMvx_GtS1q6nGDAl5AqrUqiWVwaTEfCOjOd8Iltx3r35PNfp_q_ub5QG4mkbNTZ1SQ36vxgYKg/w400-h169/dk2_i2cdetect.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.35] i2c-2(linux에서 인식하는 값 - 실제 DK2 보드의 I2C5 controller에 해당) bus에 붙어 있는 device 확인 모습</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">다음으로 확인할 사항은 실제 센서 data에 대한 것이다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;">2-0040 -> ../../../devices/platform/soc/<b>40015000</b>.i2c/i2c-2/2-00<b><font color="#b51200">40</font></b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"># <b>cd 2-0040</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgabUg-sWIvuourLHQJza3X4rKg9nC-iffWQietokUbgB7qoBYbO9vcuun5CY1ZogebDIKUCOKQCU_uWzt4o-XDsUmiRmsq4xFi86GsC_cBheLMyZKGWnowxR4JQ6Jj3aJeiO5zRLU1KjwW/s1239/dk2_sys_bus_i2c_device.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="255" data-original-width="1239" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgabUg-sWIvuourLHQJza3X4rKg9nC-iffWQietokUbgB7qoBYbO9vcuun5CY1ZogebDIKUCOKQCU_uWzt4o-XDsUmiRmsq4xFi86GsC_cBheLMyZKGWnowxR4JQ6Jj3aJeiO5zRLU1KjwW/w640-h133/dk2_sys_bus_i2c_device.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.36] i2c-2 bus(실제로는 I2C5 controller임)에 붙어 있는 0x40 주소 device 내용 확인</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">[Tip] /sys/bus/iio/devices 디렉토리로 이동해서 확인해도 된다(동일한 디렉토리임).</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">뭔가 많은 내용이 보인다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"># <b>cd iio\:devices/</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLlgc9yzLQvj2aRAkoaFSmRKhOx19BfzrdTZmbBIShA2IS81SvgRBx98XjNod1cSXkS9HktHT-F1ImaGOQVcYh-rBos5RfEozathTn8aPmZ0yUMRO_IrK9WGXfy1YhZq16wTpWnCrCr0os/s1260/dk2_i2c_iio.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="314" data-original-width="1260" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLlgc9yzLQvj2aRAkoaFSmRKhOx19BfzrdTZmbBIShA2IS81SvgRBx98XjNod1cSXkS9HktHT-F1ImaGOQVcYh-rBos5RfEozathTn8aPmZ0yUMRO_IrK9WGXfy1YhZq16wTpWnCrCr0os/w640-h160/dk2_i2c_iio.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.37] htu21 센서 모듈 정보</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">다시, 이 중에서 습도와 온도 값을 확인해 보면 다음과 같다. <span style="background-color: #f7cb4d;">Wow, 정상적으로 센서 data가 출력된다.</span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both;"># <b>cat in_humidityrelative_input </b></div><div class="separator" style="clear: both;">36480</div><div class="separator" style="clear: both;"><i>=> 습도 36.480%</i></div><div class="separator" style="clear: both;"># <b>cat in_temp_input </b></div><div class="separator" style="clear: both;">31142</div><div class="separator" style="clear: both;"><i>=> 섭씨 31.142도</i></div><div class="separator" style="clear: both;"><br /></div><div class="separator" style="clear: both;">위의 센서 data의 정확한 의미를 파악하기 위해서는 아래 파일을 참조할 필요가 있다.</div><div class="separator" style="clear: both;"><br /></div><div style="text-align: center;"><b>Documentation/ABI/testing/sysfs-bus-iio</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja_6_ggCsdsvvnSsqpVYEvA276tPzPbQbQqwNTwISYzh8NZpBoxfxoNgqJMKb5yRJxHDuU90olUl4Vqu8-OueksBg9ZgjtL05ZtKzQdpo2-KFrwOxcuGmQdz3zQaDRpr4RFbZFqfmS4mAX/s648/htu21d_humidity.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="112" data-original-width="648" height="69" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEja_6_ggCsdsvvnSsqpVYEvA276tPzPbQbQqwNTwISYzh8NZpBoxfxoNgqJMKb5yRJxHDuU90olUl4Vqu8-OueksBg9ZgjtL05ZtKzQdpo2-KFrwOxcuGmQdz3zQaDRpr4RFbZFqfmS4mAX/w400-h69/htu21d_humidity.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN5R6qmbOn0XLQ5Ue3WB7O5Pbuq2PmVH0-b0y89EGTZWPVwvqa1W-RFPmQOCDJk0RmRiUg4B-MRNRoT_fvnKEK6vUMtlnC2ylx79EoScSmGnjiOXnk9DD3E4OwWbCF6fRCG1G-7zCkUSOT/s585/htu21d_temp.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="108" data-original-width="585" height="74" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgN5R6qmbOn0XLQ5Ue3WB7O5Pbuq2PmVH0-b0y89EGTZWPVwvqa1W-RFPmQOCDJk0RmRiUg4B-MRNRoT_fvnKEK6vUMtlnC2ylx79EoScSmGnjiOXnk9DD3E4OwWbCF6fRCG1G-7zCkUSOT/w400-h74/htu21d_temp.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.38] htu21 센서 모듈 정보 - 단위 계산 방법</span></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">지금까지 작업한 내용을 buildroot에 반영하는 작업 등이 남아 있으나, 지면 관계상 생략하기로 한다.</div><div class="separator" style="clear: both; text-align: left;">자세한 사항은 reference [1] 문서를 참조해 주기 바란다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div><br /></div><div><br /></div><div><div class="separator" style="clear: both; text-align: left;"><b><font color="#3367d6" size="6">6. 온습도 센서 출력용 Qt application 만들기</font></b></div><div class="separator" style="clear: both; text-align: left;">이번 장에서는 앞서 5장에서 장착한 온습도 센서의 출력 결과를 확인할 수 있는 Qt application을 만드는 과정을 소개해 보고자 한다.</div><div class="separator" style="clear: both; text-align: left;"><div><span style="text-align: left;"><br /></span></div></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#f57c00">To be continued ...</font></b></div></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">8. References</font></b></div><div>[1] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-connecting-an-i2c-sensor/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-connecting-an-i2c-sensor/</a></div><div><i> => 위의 내용을 많이 참조하였음.</i></div><div>[2] <a href="https://cdn-shop.adafruit.com/datasheets/1899_HTU21D.pdf">https://cdn-shop.adafruit.com/datasheets/1899_HTU21D.pdf</a></div><div>[3] <a href="http://dlnmh9ip6v2uc.cloudfront.net/datasheets/BreakoutBoards/HTU21D%20Breakout.pdf">http://dlnmh9ip6v2uc.cloudfront.net/datasheets/BreakoutBoards/HTU21D%20Breakout.pdf</a></div><div><i> => HTU21D 온/습도 센서 datasheet & 회로도</i></div><div>[4] <a href="https://www.st.com/resource/en/reference_manual/dm00327659-stm32mp157-advanced-arm-based-32-bit-mpus-stmicroelectronics.pdf">https://www.st.com/resource/en/reference_manual/dm00327659-stm32mp157-advanced-arm-based-32-bit-mpus-stmicroelectronics.pdf</a></div><div>[5] <a href="https://programmer.group/iio-subsystem-of-linux-device-driver-iio-framework-and-iio-data-structure.html">https://programmer.group/iio-subsystem-of-linux-device-driver-iio-framework-and-iio-data-structure.html</a></div><div>[6] Industrial I/O Subsystem: The HOme of Linux Sensors, daniel.baluta@intel.com</div><div>[7] IIO, a new kernel subsystem, maxime.ripard@bootlin.com</div><div>[8] GNU/Linux Rapid Embedded Programming, Rodolfo Giometti</div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div><div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com3tag:blogger.com,1999:blog-6346200245600677355.post-7773238417291719572020-06-16T14:10:00.001+09:002020-07-16T10:08:31.698+09:00Linux Device Driver for Embedded Processors 에피소드 3 - STM32MP157C Discovery Kit 소개(3)지난 시간에 이어 <b>STM32MP157C Discovery Kit</b> 분석, 세번째 시간이다. 😊<div><br /></div><div><font color="#9e9e9e">(온/습도 센서가 도착하는데 시간이 좀 필요하니) </font>이번 시간에는 Qt5 application을 DK2 board에서 돌려 보는 방법을 먼저 소개해 보도록 하겠다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="224" data-original-width="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvcTrzuGaKQUlFtV1GkVSuF4f1cZcUD5KKkLqNg6VXP18PYEykMQtExke3-GtXPJJwp2qHASTc4iyt2TNmJosUF3XtZ3CR4qm9c7UJxHuwd9J6uOCYf8UCC3-Qk5M7070ETNh7Ga_JqZKa/" /><img border="0" data-original-height="4128" data-original-width="3096" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfsFpXyd3EdpHm1hi-E-ylHSfDvpJq7zeb7j1xlgjXNfxQurTMQXXvlHRbMwOwHqc42HAwvRF0xJ-id1u1jzyMxL-hci8nePbJrR8pcvZZxe_-ZOxQn86dLVbMKfExenWKpQMs-u-mymVy/w150-h200/20200616_094449.jpg" width="150" /></div></div><div><div><b><font size="4"><br /></font></b></div><div><b><font size="4"><br /></font></b></div><div><b><font size="4">목차</font></b></div><div><i>1. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">STM32MP157C Discovery Kit 소개</a></i></div><div><i>2. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">Firmware(부팅 image) 설치하기</a></i></div><div><i>3. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">부팅 image 생성하기 - Yocto project, Buildroot</a></i></div><div><i><b>4. Qt application 개발환경 설정 및 테스트해 보기</b></i></div><div><i>5. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">Device Tree 분석 및 Device Driver 시험하기 - i2c 예제 소개</a></i></div><div><i>6. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">온습도 센서 결과 확인용 Qt application 만들기</a></i></div><div><div><i>7. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">Cortex-M4 환경에서의 firmware 개발하기</a></i></div><div><i>8. References</i></div></div><div><font color="#b51200" size="2">(*) 목차는 처음 예정했던 내용과 차이가 날 수도 있다.</font></div><div><br /></div><div><br /></div></div><div><br /></div><div><i><font color="#9e9e9e">Qt는 다양한 산업현장(특히 embedded Linux)에서 많이 사용되고 있다. 최근에는 C++ 말고도 QML, Python(PyQt, PySide) 등을 지원하면서 영역을 확장해 나가고 있고, Android, iOS 등에서도 Qt app이 돌아가는 상황이 되었다. 하지만, 이러한 급속한 발전 추세에도 불구하고, 국내의 Qt 관련 서적이나 강좌는 지지부진한 상태이다(있기는 있는데 많이 없다). 왜 일까 ?</font></i></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">4. Qt5 application 개발환경 설정 및 테스트해 보기</font></b></div><div><b><font color="#0b8043" size="4">a) Buildroot에서 Qt5 enable하기 </font></b></div><div>Qt5 app을 DK2 board에서 돌려 보기 위해서는 stm32mp157c_dk2_defconfig 파일을 수정한 후, buildroot menuconfig를 통해 Qt5를 enable시켜 주어야 한다.</div><div><br /></div><div>$ cd buildroot</div><div>$ <b>vi configs/stm32mp157c_dk2_defconfig</b></div><div>...</div><div><div>BR2_LINUX_KERNEL_INSTALL_TARGET=y</div><div><b><font color="#9c27b0">BR2_PACKAGE_DEJAVU=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_QT5=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_QT5BASE_EXAMPLES=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_QT5BASE_GUI=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_QT5BASE_WIDGETS=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_QT5BASE_FONTCONFIG=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_EVTEST=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_LIBDRM=y</font></b></div><div><b><font color="#9c27b0">BR2_PACKAGE_LIBDRM_INSTALL_TESTS=y</font></b></div><div>BR2_TARGET_ROOTFS_EXT2=y</div></div><div>...</div><div>~</div><div><br /></div><div>$ <b>make menuconfig</b></div><div> => <font color="#f57c00">(변경 1)</font> Toolchain -> Toolchain type : </div><div> ( ) Buildroot toolchain</div><div> (X) External toolchain</div><div> => 이유: Qt5 needs a toolchain w/ gcc >= 5.0, wchar, NPTL, C++, dynamic library ***</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhGiA-rX-duiDSn8EjsNh9h6BjZjpDlUFhOK1X2go11sE9gx6GeknBO5eK-aATFAl-MISKadEC8UhZjVKIRYk4yiMBDW4VKfYrNPOYoRiDx-tX-xcW_djOiSekxJsmValMxt_dtmHVDuVn/s912/qt5_buildroot_menu1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="912" height="274" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhGiA-rX-duiDSn8EjsNh9h6BjZjpDlUFhOK1X2go11sE9gx6GeknBO5eK-aATFAl-MISKadEC8UhZjVKIRYk4yiMBDW4VKfYrNPOYoRiDx-tX-xcW_djOiSekxJsmValMxt_dtmHVDuVn/w400-h274/qt5_buildroot_menu1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.1] Toolchain type 변경</span></div><div><br /></div><div> => <font color="#f57c00">(변경 2)</font> Target packages -> Graphic libraries and applications (graphic/text) -> [*] Qt5 </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRoCGMq-oz3FXOrvdfic-ZKxnYcbW0rKmOJMavDQaXeFPx0DHU4DkDjuiWhE4CPJ6tWl1TGSYDJc3sUianxU8vOnbb0GzDPqNixyHP1TWNpTdJYjeATzbsghUwx_bKdcEWQTVsozUiV64z/s906/qt5_buildroot_menu2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="906" height="275" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRoCGMq-oz3FXOrvdfic-ZKxnYcbW0rKmOJMavDQaXeFPx0DHU4DkDjuiWhE4CPJ6tWl1TGSYDJc3sUianxU8vOnbb0GzDPqNixyHP1TWNpTdJYjeATzbsghUwx_bKdcEWQTVsozUiV64z/w400-h275/qt5_buildroot_menu2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.2] Qt5 enable</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiupefgMYvuQ2djGOJ48apXz5pyyUwk4rc-i2mrXSbr7zDnve85yPGO3QbrzF6ympSzsUhrM8snqz05lncx85GxvxTwbpKj2qyKWpZAPp-2n42QfxYCPFlALJJzPG6ldLHeybyGDc0DHmYg/s909/qt5_buildroot_menu3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="909" data-original-width="904" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiupefgMYvuQ2djGOJ48apXz5pyyUwk4rc-i2mrXSbr7zDnve85yPGO3QbrzF6ympSzsUhrM8snqz05lncx85GxvxTwbpKj2qyKWpZAPp-2n42QfxYCPFlALJJzPG6ldLHeybyGDc0DHmYg/s320/qt5_buildroot_menu3.png" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.3] Qt5 세부 설정</span></div><div><br /></div><div>$ <b>make</b></div><div>$ <b>cd output/images</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRTYIrLrmajCb8SLgGOlZimQS3Z5pTsyxPH1wgM1ctxyW127jb7QHJ6vNhl8rvWjsiBIH172odxlyw_xFjDK0MQ3k2ZybJXxrlg1OwUXhQ4EFCIrTYcJzq6NVtORdTVqEbGOKqCj8CQGwD/s812/qt5_buildroot_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="205" data-original-width="812" height="101" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRTYIrLrmajCb8SLgGOlZimQS3Z5pTsyxPH1wgM1ctxyW127jb7QHJ6vNhl8rvWjsiBIH172odxlyw_xFjDK0MQ3k2ZybJXxrlg1OwUXhQ4EFCIrTYcJzq6NVtORdTVqEbGOKqCj8CQGwD/w400-h101/qt5_buildroot_output.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.4] Qt5 enable 상태에서 build한 결과물</span></div><div><br /></div><div>$ mkdir tmp</div><div>$ <b>sudo mount -o loop ./rootfs.ext2 ./tmp</b></div><div>$ cd usr/lib</div><div>$ <b>ls -l libQt5*</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1yaJRFwirGnyhh6gIeOJlbFvvvWwtiRFpbNWgeO3ijIbKLhLMMOmpZx_tZjsqOR4hBafGwuNJMch0UL3qspeRxTiAuM193UlwWxUtQBxyb0Y3C7AbkVPW-9Foosq51frlhw7hjv_xtrQz/s915/qt5_buildroot_lib.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="650" data-original-width="915" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1yaJRFwirGnyhh6gIeOJlbFvvvWwtiRFpbNWgeO3ijIbKLhLMMOmpZx_tZjsqOR4hBafGwuNJMch0UL3qspeRxTiAuM193UlwWxUtQBxyb0Y3C7AbkVPW-9Foosq51frlhw7hjv_xtrQz/s320/qt5_buildroot_lib.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both;"><span style="text-align: left;">[그림 4.5] libQt5* library files</span></div><div class="separator" style="clear: both;"><span style="text-align: left;"><br /></span></div></div><div>OK, Qt library가 추가된 것으로 보아, 정상적으로 build가 되었음을 알 수 있다.</div><div><br /></div><div>Qt5에는 다양한 예제 코드가 많이 포함되어 있다. 따라서 새로 build한 buidroot image를 이용하여 이를 돌려 보도록 하자.</div><div><br /></div><div>$ cd output/images</div><div>$ <b>sudo dd if=./sdcard.img of=/dev/sdb</b></div><div><br /></div><div><b><Target board 재부팅></b></div><div><i> => Qt5에는 다양한 예제가 포함되어 있는데, 이 중 몇가지를 실행해 보면 다음과 같다.</i></div><div><br /></div><div># /usr/lib/qt/examples/gui/rasterwindow/</div><div># <b>./rasterwindow <font color="#f4a900">-platform linuxfb</font></b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoZ01MBmirB9il-EAs7lepYf9FA40H3Cw2P5kYWHN08F4g-5DDxkm02dqfblP2Q-KTxMGu9n0s5UYwRKR8q9KfCt1CP06maO7bu4HM9Y5XploJExNH59outejhLE7uNxN6Q0Y70aw3qDbT/s4128/20200616_094343.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4128" data-original-width="3096" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoZ01MBmirB9il-EAs7lepYf9FA40H3Cw2P5kYWHN08F4g-5DDxkm02dqfblP2Q-KTxMGu9n0s5UYwRKR8q9KfCt1CP06maO7bu4HM9Y5XploJExNH59outejhLE7uNxN6Q0Y70aw3qDbT/s320/20200616_094343.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.6] rasterwindow Qt app 실행 화면</div><div><br /></div><div><div># /usr/lib/qt/examples/gui/analogclock/</div><div># <b>./analogclock <font color="#f4a900">-platform linuxfb</font></b></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK1NI_pTCXzOBL7iw7CkQjBOXMmEQhIaBHX48jKoGiIuiixG6tniY0IkD0Ws0xwF814cc81LfX0_nIjkADD25A4m7jR9WEEdWz3YWmaUUKyS_z2UANqoRvswjkY7-w38fDYMxPwXmKfceO/s4128/20200616_094449.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4128" data-original-width="3096" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK1NI_pTCXzOBL7iw7CkQjBOXMmEQhIaBHX48jKoGiIuiixG6tniY0IkD0Ws0xwF814cc81LfX0_nIjkADD25A4m7jR9WEEdWz3YWmaUUKyS_z2UANqoRvswjkY7-w38fDYMxPwXmKfceO/s320/20200616_094449.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.7] analogclock Qt app 실행 화면</div><div><br /></div><div><b><font color="#0b8043" size="4">b) DK2 보드에서 ssh 및 sftp 서버 띄우기</font></b></div><div>Program이 추가될 때마다 전체 build 및 microSD card에 image writing을 하는 것은 너무 비효율적이라고 볼 수 있다. 따라서 이절에서는 ssh daemon(dropbear)과 sftp daemon(Green End SFTP server)을 띄우고 이를 활용하는 방법을 소개하고자 한다.</div><div><br /></div><div>$ <b>make menuconfig</b></div><div> => Target packages --> Networking applications --></div><div> [*] dropbear</div><div> [*] gesftpserver</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ2i3zdUSvRzrqy5wLY4z9Lt18cjmnXpV7uZnN7-MifqW-5tpdHIyplbwDdDUZXgkzrN1jG6XgO8BbMdSzB_hrq1AluEB5A2bAi_xqUVRchIfI3x3jfuSibFPIdgzjBX1x0E7GBVPNCWcO/s865/buildroot_dropbear.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="619" data-original-width="865" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJ2i3zdUSvRzrqy5wLY4z9Lt18cjmnXpV7uZnN7-MifqW-5tpdHIyplbwDdDUZXgkzrN1jG6XgO8BbMdSzB_hrq1AluEB5A2bAi_xqUVRchIfI3x3jfuSibFPIdgzjBX1x0E7GBVPNCWcO/w400-h286/buildroot_dropbear.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.8] buildroot에서 dropbear, gesftpserver enable시키기</div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;"><span style="color: #b51200; font-size: small; text-align: left;">[Tip] dropbear, gesftpserver 외에도 rsync가 필요할 듯하여 선택해 주었다.</span></span></div><div><span style="text-align: center;"><br /></span></div><div style="text-align: left;">그 다음, target board가 부팅할 때마다 eth0 interface에 static ip가 할당될 수 있도록 /etc/network/interfaces 파일을 overlay 디렉토리에 포함시켜 주도록 하자.</div><div style="text-align: left;"><span style="color: #b51200; font-size: small; text-align: center;">[Tip] </span><span style="color: #b51200; font-size: small;">board/stmicroelectronics/stm32mp157c-dk2/overlay 디렉토리 아래의 파일은 전체 build 후, rootfs디렉토리로 자동 복사된다.</span></div><div style="text-align: left;"><span style="color: #b51200; font-size: small;"><br /></span></div><div style="text-align: left;">$ <b>cd board/stmicroelectronics/stm32mp157c-dk2/overlay/</b></div><div style="text-align: left;">$ <b>mkdir -p ./etc/network</b></div><div style="text-align: left;"><span style="text-align: center;">$ <b>vi interfaces</b></span></div><div><span style="text-align: center;"><i><font color="#4285f4"><div style="text-align: left;">auto lo</div><div style="text-align: left;">iface lo inet loopback</div><div style="text-align: left;"><br /></div><div style="text-align: left;">auto eth0</div><div style="text-align: left;">iface eth0 inet static</div><div style="text-align: left;"><span style="white-space: pre;"> </span>address 192.168.1.100</div><div style="text-align: left;"><span style="white-space: pre;"> </span>netmask 255.255.255.0</div><div style="text-align: left;">~</div></font></i></span></div><div><span style="text-align: center;"><br /></span></div><div><span style="text-align: center;">$ <b>make</b></span></div><div><br /></div><div><div>$ cd output/images</div><div>$ <b>sudo dd if=./sdcard.img of=/dev/sdb</b></div></div><div><i> => 새로 build한 image를 microSD에 write하도록 하자.</i></div><div><br /></div><div><br /></div><div><b><Desktop PC></b></div><div>Target board 재 부팅 후, ssh와 sftp login을 각각 시도해 보면 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifHpLJNB1sAS0h5IH29lTsYz54DPSMVJyZv_6tcjJUetGRIpYQNOnzXSaAFsQaMobzJXmKjhL3cIAt0OqlgPu9idfVEtok0xA2NRC68Ph0bKIg5cS-tiTkVp3JvV9jnRff5NfuF1hqWd9Y/s727/dk2_ssh_login.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="170" data-original-width="727" height="94" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifHpLJNB1sAS0h5IH29lTsYz54DPSMVJyZv_6tcjJUetGRIpYQNOnzXSaAFsQaMobzJXmKjhL3cIAt0OqlgPu9idfVEtok0xA2NRC68Ph0bKIg5cS-tiTkVp3JvV9jnRff5NfuF1hqWd9Y/w400-h94/dk2_ssh_login.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.9] ssh login</div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAJs6eyxMU7pz-tlAJ4tpI_kH_xW53gmrvXN2r-EY3DEMAo2IbKQXJuR7y7iqd-SwhIn5DEsQ_NkpO4483HXzrN2HUKcKj-zRt9WOt4v8-MGZtQ3GgseEtT3VwksA4wMe9uxl1sBiGzWpB/s612/dk2_sftp.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="111" data-original-width="612" height="73" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAJs6eyxMU7pz-tlAJ4tpI_kH_xW53gmrvXN2r-EY3DEMAo2IbKQXJuR7y7iqd-SwhIn5DEsQ_NkpO4483HXzrN2HUKcKj-zRt9WOt4v8-MGZtQ3GgseEtT3VwksA4wMe9uxl1sBiGzWpB/w400-h73/dk2_sftp.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.10] sftp login</div><div><br /></div><div><b><Target board></b></div><div>이 상태에서 Target board의 network 설정 상태와 ps 출력 결과를 확인해 보면 다음과 같다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir7jS9zZKWkBCvBcNLfmTWQ6RJnPfB6of8vX-CxeJwRk7dWk77UKlaXbZ_4h302rz35oEkqbzXEiJDPaN5sUypXTGZ_YI2c7rOTqHKYZ78MzVcOVn_QtltD_7jgV1QiCBSP4CbGdp9equI/s638/dk2_ifconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="200" data-original-width="638" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEir7jS9zZKWkBCvBcNLfmTWQ6RJnPfB6of8vX-CxeJwRk7dWk77UKlaXbZ_4h302rz35oEkqbzXEiJDPaN5sUypXTGZ_YI2c7rOTqHKYZ78MzVcOVn_QtltD_7jgV1QiCBSP4CbGdp9equI/s320/dk2_ifconfig.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.11] DK2 board ifconfig 실행 모습</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2WSzdRu5pcimoM-XN4UGMw9XpRGlK6KZ-nrn7b5hk3d0QJjCRmWajBzaQAoRMoWyH0r5rYp8L5LFRePQy67TEXhgTQOQJ3XFqfH2fcsR_NB02Wwx7kWBNJB7PwVW9-_-FpUGfj7S3gAow/s728/dk2_minicom_ssh.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="721" data-original-width="728" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2WSzdRu5pcimoM-XN4UGMw9XpRGlK6KZ-nrn7b5hk3d0QJjCRmWajBzaQAoRMoWyH0r5rYp8L5LFRePQy67TEXhgTQOQJ3XFqfH2fcsR_NB02Wwx7kWBNJB7PwVW9-_-FpUGfj7S3gAow/s320/dk2_minicom_ssh.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.12] DK2 board 상에서 ps 실행 결과</div><div><br /></div><div><b><font color="#0b8043" size="4">c) DK2 보드에서 Qt5 app 실행하기</font></b></div><div>일전(3년 전)에도 이와 비슷한 내용을 blog에 실은 적이 있다. 그 때는 buildroot가 아니라 yocto project를 기준으로 설명을 전개했었다. 비슷한 내용이니 다음 내용을 진행하기에 앞서 먼저 확인해 보는 것도 좋을 듯 싶다. </div><div><br /></div><div style="text-align: center;"><a href="http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html">http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html</a></div><div><br /></div><div>우선, Qt5 설치(<font color="#9e9e9e">지면 관계상, 여기서는 이 부분에 대한 설명은 생략</font>) 후, 아래와 같이 설정하도록 하자. 앞서 언급한 blog post 내용과 중복되는 내용이므로 간단히 요점만 정리해 보기로 하자.</div><div><br /></div><div><b>1) Tools -> Options 메뉴 선택 -> Kits tab 선택</b></div><div> <font color="#0b8043"> - </font><b><font color="#3367d6">Name</font></b>: Buildroot ARM 입력(<font color="#9e9e9e">다른 적당한 이름으로 해도 됨</font>)</div><div> - <b><font color="#3367d6">Device type</font></b>: Generic Linux Device 선택</div><div> - <b><font color="#3367d6">Sysroot</font></b>: buildroot sysroot path 입력(예: /home/chyi/workspace/Boards/STM32MP1/workspace/buildroot/<font color="#f57c00">buildroot/output/host/arm-buildroot-linux-gnueabihf/sysroot</font>)</div><div> </div><div><b>2) Compiler tab 선택 </b></div><div> - Add 버튼 선택하여 GCC compiler 추가</div><div> - <b><font color="#3367d6">Name</font></b>: Buildroot GCC(<font color="#9e9e9e">다른 적당한 이름으로 해도 됨</font>)</div><div> - <b><font color="#3367d6">Compiler path</font></b>: /home/chyi/workspace/Boards/STM32MP1/workspace/buildroot/buildroot/output/host/bin/arm-none-linux-gnueabihf-gcc</div><div> </div><div> - Add 버튼 선택하여 C++ compiler 추가</div><div> - <b><font color="#3367d6">Name</font></b>: Buildroot G++(<font color="#9e9e9e">다른 적당한 이름으로 해도 됨</font>)</div><div> - <b><font color="#3367d6">Compiler path</font></b>: /home/chyi/workspace/Boards/STM32MP1/workspace/buildroot/buildroot/output/host/bin/arm-none-linux-gnueabihf-g++</div><div><br /></div><div><b>3) Debugger tab 선택 </b></div><div> - Add 버튼 선택하여 gdb 추가</div><div> - <b><font color="#3367d6">Name</font></b>: Buildroot GDB(<font color="#9e9e9e">다른 적당한 이름으로 해도 됨</font>)</div><div> - <b><font color="#3367d6">Path</font></b>: /home/chyi/workspace/Boards/STM32MP1/workspace/buildroot/buildroot/output/host/bin/arm-none-linux-gnueabihf-gdb</div><div><br /></div><div><b>4) Qt Versions tab 선택</b></div><div> - <b><font color="#3367d6">qmake path 입력</font></b>: /home/chyi/workspace/Boards/STM32MP1/workspace/buildroot/buildroot/output/host/bin</div><div> - <b><font color="#3367d6">Version name</font></b>: Qt %{Qt:Version} (host)를 Qt %{Qt:Version} (Buildroot)로 수정</div><div><br /></div><div><b>5) Kits tab으로 다시 복귀</b></div><div> - C, C++ compiler는 Buildroot GCC, Buildroot G++ compiler로 선택(변경)</div><div> - Qt mkspec: devices/linux-buildroot-g++ 입력</div><div> - Apply -> OK 버튼 선택</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiku68RO6naE1N8ZskBWv1SaCxA9W4e2MPgBmJXv9G7Mai5Qb-lYz-DIUx9uEH4mXZ_Gil3TSZBj0n81NyXzYU_JFiPKpmKWDyxoFUNpD2JrpK-9Gax9t5Y4wDg2xP19Kb3OGDdeguRjp7v/s1199/qtcreator_c.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="828" data-original-width="1199" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiku68RO6naE1N8ZskBWv1SaCxA9W4e2MPgBmJXv9G7Mai5Qb-lYz-DIUx9uEH4mXZ_Gil3TSZBj0n81NyXzYU_JFiPKpmKWDyxoFUNpD2JrpK-9Gax9t5Y4wDg2xP19Kb3OGDdeguRjp7v/w400-h276/qtcreator_c.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.13] Tool => Options => Kits => Compilers 설정</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUbFl3vbblEe0Ouj4tLMbk4gnJU6htsjthxYDZm0ZCVLVBpB1OhYHESvaA9HiFK07BXy4RXKaqqBRqw18ynRkmn7ovuSYeadmLFAeD31zKxx442XfNBfQt4qARZTbFuM5YpNg0gK1LEF0B/s1199/qtcreator_qt_versions.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="828" data-original-width="1199" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUbFl3vbblEe0Ouj4tLMbk4gnJU6htsjthxYDZm0ZCVLVBpB1OhYHESvaA9HiFK07BXy4RXKaqqBRqw18ynRkmn7ovuSYeadmLFAeD31zKxx442XfNBfQt4qARZTbFuM5YpNg0gK1LEF0B/w400-h276/qtcreator_qt_versions.png" width="400" /></a></div><div><div class="separator" style="clear: both; text-align: center;">[그림 4.14] Tool => Options => Kits => Qt Versions 설정</div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkrBEYaUdR9r4hOerzwx_uuCG-V3eOocuPqOoQs8-FZjy-dgPAeHZFQ41fREays7DpfTGH86PNmN6XcW5OJNckRJoAqtm-MOznjATjkRr3xLVitieU-zwVE79x5EhhyphenhyphenW5AQ1dgchBI2k4m/s1199/qtcreator_kits.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="828" data-original-width="1199" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkrBEYaUdR9r4hOerzwx_uuCG-V3eOocuPqOoQs8-FZjy-dgPAeHZFQ41fREays7DpfTGH86PNmN6XcW5OJNckRJoAqtm-MOznjATjkRr3xLVitieU-zwVE79x5EhhyphenhyphenW5AQ1dgchBI2k4m/w400-h276/qtcreator_kits.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.15] Tool => Options => Kits 설정</div><div><br /></div><div><b>6) Devices tab 선택 => Add 버튼 선택 후, Generic Linux Device 선택</b></div><div><i> => 여기서는 ssh & sftp로 target board에 접속하여 Qt app(binary)를 복사(upload)하기 위해 필요한 설정을 해 준다.</i></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRu5i36V3ESZZPOn3vONjKU3kjS7tHOKvSc0V1agL-_Iwvey_S8M2n86ZMro4cd7lGOUC8CWckh_mWJHPwGToiNmQmK1_HjruMZ7e_UHbmoYjw64nCTKIdl9sQLgZqqQKSPoJfLCX1_GE-/s1199/qtcreator_devices.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="828" data-original-width="1199" height="276" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRu5i36V3ESZZPOn3vONjKU3kjS7tHOKvSc0V1agL-_Iwvey_S8M2n86ZMro4cd7lGOUC8CWckh_mWJHPwGToiNmQmK1_HjruMZ7e_UHbmoYjw64nCTKIdl9sQLgZqqQKSPoJfLCX1_GE-/w400-h276/qtcreator_devices.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.16] Tool => Options => Devices 설정</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">이미 <font color="#0b8043">"b) DK2 보드에 ssh 및 sftp 서버 띄우기"</font> 절에서 관련 설정을 진행한 바 있다. 따라서 제대로 설정을 해 주었다면 아래와 같이 정상 동작 메시지가 출력되어야 한다.</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5akqSFG3ZgdzY0IOEsC30_hvXqaKcCJbSw94pL8nR2R8IskvlMi-yc9YJ8Y1A7nEOn4m12brgOSb0CaqZulJKcYTa0znnikG9GxVW084pKckXQGewQom0813j73P3kBM-3WHstpTHTQkt/s610/qtcreator_ssh_ok.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="610" data-original-width="607" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5akqSFG3ZgdzY0IOEsC30_hvXqaKcCJbSw94pL8nR2R8IskvlMi-yc9YJ8Y1A7nEOn4m12brgOSb0CaqZulJKcYTa0znnikG9GxVW084pKckXQGewQom0813j73P3kBM-3WHstpTHTQkt/s320/qtcreator_ssh_ok.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.17] Qt creator <=> target board 연결 성공(sftp, rsync 사용)</div><div><br /></div><div>앞서 살펴본 바와 같이 target board에서 Qt app을 실행하려면, <b>-platform linuxfb</b> option을 붙여 주어야 한다. 따라서 마지막으로 아래와 같이 Qt creator 설정을 변경해 주도록 하자.</div><div><br /></div><div style="text-align: center;">Projects => Buildroot ARM => Run => Command line arguments: <b>-platform linuxfb</b> 입력</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH1LwlxMhGKFtSpoWtwz68Q1J2Av3tJnfHib6ULnMXhuBnY6_a5vFSAita1sYCegta5_VyNGDCaig9Cw96I_pdaAE1dthQZlyJix-VKhwrGT6x2RftIagLsEmr26USYJurjHdcO6gGSyLN/s1428/qtcreator_projects_run.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="884" data-original-width="1428" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgH1LwlxMhGKFtSpoWtwz68Q1J2Av3tJnfHib6ULnMXhuBnY6_a5vFSAita1sYCegta5_VyNGDCaig9Cw96I_pdaAE1dthQZlyJix-VKhwrGT6x2RftIagLsEmr26USYJurjHdcO6gGSyLN/w400-h248/qtcreator_projects_run.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 4.18] <span style="text-align: left;">Projects => Buildroot ARM => Run => Command line arguments 설정</span></div><div><br /></div><div>Qt Creator에 대한 모든 설정이 진행되었다. 따라서 이 상태에서 예제 program을 하나 만들어 실행해 보도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9zPEMz2zld-Q_z-x5ZP6pxDsU0zvHtZhizD9rOuvs796zzrNpIsg9CFd9CKQA_w8pa_mvVReV_BM07trDcGcMaywo8ObMD4sssqoEt_K1wAwJwF9AV6ASXGJj0udhTFa3MdaBN85O2HIi/s1428/qtcreater_hello3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="884" data-original-width="1428" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9zPEMz2zld-Q_z-x5ZP6pxDsU0zvHtZhizD9rOuvs796zzrNpIsg9CFd9CKQA_w8pa_mvVReV_BM07trDcGcMaywo8ObMD4sssqoEt_K1wAwJwF9AV6ASXGJj0udhTFa3MdaBN85O2HIi/w400-h248/qtcreater_hello3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.19] Hello3 app</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">[Tip] Build 결과물을 target board 올리기 위해 아래와 같이 Hello3.pro 파일의 target.path를 적당히 잡아 주어야 한다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPV_U88d9WHDQnKhGzGhVb5K20KGnU8NXkhrd6KxxZS_SfZ2oArFqI5P_s1nov45_x2KLoyOwrseD1OpVgVL62gstStc4Cmo9aGeBEKyk2IJJhZkPLBMyDamKzkQgUiCb3Qj4xJI5so7AC/s532/qtcreator_pro.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="164" data-original-width="532" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPV_U88d9WHDQnKhGzGhVb5K20KGnU8NXkhrd6KxxZS_SfZ2oArFqI5P_s1nov45_x2KLoyOwrseD1OpVgVL62gstStc4Cmo9aGeBEKyk2IJJhZkPLBMyDamKzkQgUiCb3Qj4xJI5so7AC/w400-h124/qtcreator_pro.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVItqZg0w5WWgdDpOe2A-a9x60rtysV3Host-X8IjD47ej4QVsWu2-GsjuMf3zKyK9gmlpL13VN-bw-a7i7mI61Letp0opbOVX5_xKVq5w0UEv7KhTZfexF4IeNq1NHJ-bUt3iA6bjBMo/s37/qtcreator_run_button.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="35" data-original-width="37" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjtVItqZg0w5WWgdDpOe2A-a9x60rtysV3Host-X8IjD47ej4QVsWu2-GsjuMf3zKyK9gmlpL13VN-bw-a7i7mI61Letp0opbOVX5_xKVq5w0UEv7KhTZfexF4IeNq1NHJ-bUt3iA6bjBMo/" /><font color="#000000"> Compile에 성공한 경우, 좌측 하단의 run 버튼을 눌러 app을 실행해 보면 다음과 같다.</font></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHzgqUUeXZLc_1i4wGrln5phBwv4NZd-Zbv6Sii6EkgiBiV1OwB4FSBm64jz1Ntvb3j40tUM2Y28pr6sSjT_h-o3nlWQ95F2-SQIghkP4-v3z1pexeh9fC1h79bt1UNCdqFgvRdJtMCewl/s700/dk2_hello3_ps.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="700" data-original-width="537" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHzgqUUeXZLc_1i4wGrln5phBwv4NZd-Zbv6Sii6EkgiBiV1OwB4FSBm64jz1Ntvb3j40tUM2Y28pr6sSjT_h-o3nlWQ95F2-SQIghkP4-v3z1pexeh9fC1h79bt1UNCdqFgvRdJtMCewl/s320/dk2_hello3_ps.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.20] Hello3 app ps 명령 모습(/root/workspace/Hello3 -platform linuxfb)</span></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFYrM5kA1wFb34yDX8RfCIE8ZEvRQag_6lWYTN32IZDwVdGl37VQIqJv8GzB4XAu2ClormKgmEg0OJ1-M60fB7jnnVUha2uz7jK_oET8uT3ef5EOAk4CHHTfL_Nscj4EUi4sl105_vIg_f/s4128/20200616_120634.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4128" data-original-width="3096" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFYrM5kA1wFb34yDX8RfCIE8ZEvRQag_6lWYTN32IZDwVdGl37VQIqJv8GzB4XAu2ClormKgmEg0OJ1-M60fB7jnnVUha2uz7jK_oET8uT3ef5EOAk4CHHTfL_Nscj4EUi4sl105_vIg_f/s320/20200616_120634.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 4.21] Hello3 app 실행 모습</span></div><div><br /></div><div>지금까지 설명한 내용은 Qt Creator로 application을 cross-compile 한 후, scp or sftp 등을 활용하여 target board에 올려 실행하는 것과 동일하다고 볼 수 있다.</div><div><br /></div><div><b><Desktop></b></div><div><div>chyi@mars:~build-Hello2-Buildroot_ARM-Debug$ <b>scp ./Hello3 root@192.168.1.100:~/workspace</b></div><div><font size="2">root@192.168.1.100's password: </font></div><div><font size="2">Hello3 100% 26KB 1.0MB/s 00:00</font></div></div><div><br /></div><div><b><Target board></b></div><div># cd workspace</div><div># <b>./Hello3 -platform linuxfb</b></div><div><br /></div><div><br /></div><div><br /></div><div><div class="separator" style="clear: both; text-align: left;"><b><font color="#3367d6" size="6">5. Device Tree 분석 및 Device Driver 시험하기</font></b></div><div class="separator" style="clear: both; text-align: left;">이번 장에서는 DK2 보드의 device tree를 분석하고, i2c 용 온/습도 센서를 DK2 보드에 연결하는 과정을 소개해 보도록 하겠다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><b>stm32mp157.dtsi</b></div><div class="separator" style="clear: both; text-align: center;">stm32mp15xc.dtsi</div><div class="separator" style="clear: both; text-align: center;"><b>stm32mp15-pinctrl.dtsi</b></div><div class="separator" style="clear: both; text-align: center;">stm32mp15xxac-pinctrl.dtsi</div><div class="separator" style="clear: both; text-align: center;"><b>stm32mp15xx-dkx.dtsi</b></div><div class="separator" style="clear: both; text-align: center;">^</div><div class="separator" style="clear: both; text-align: center;">|</div><div class="separator" style="clear: both; text-align: center;"><b>stm32mp157c-dk2.dts</b></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpxzksaxy7MAU9mHF0Mk0IOeadUylRmZwqRoWhXojihIGJcwtj7xbrxr5MegN-ogxkE3r8Pl_qzfnSBsxvdlUG8AFp1M6JG5evP8OOg-3sGApk9pwktR50s6msw7qMPjaFnI5XxU83zs2c/s842/dk2_device_tree.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="755" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpxzksaxy7MAU9mHF0Mk0IOeadUylRmZwqRoWhXojihIGJcwtj7xbrxr5MegN-ogxkE3r8Pl_qzfnSBsxvdlUG8AFp1M6JG5evP8OOg-3sGApk9pwktR50s6msw7qMPjaFnI5XxU83zs2c/s320/dk2_device_tree.png" /></a></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 5.1] output/build/linux-5.7.1/arch/arm/boot/stm32mp157c-dk2.dts</span></div><div><span style="text-align: left;"><br /></span></div></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#f57c00">To be continued ...</font></b></div></div><div><br /></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">8. References</font></b></div><div>[1] <a href="http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html" style="text-align: center;">http://slowbootqt.blogspot.com/2017/01/embedded-qt-programming.html</a></div><div>[2] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-enabling-qt5-for-graphical-applications/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-enabling-qt5-for-graphical-applications/</a></div><div>[3] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-setting-up-a-qt5-application-development-environment/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-setting-up-a-qt5-application-development-environment/</a></div><div>[4] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-developing-a-qt5-graphical-application/">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-developing-a-qt5-graphical-application/</a></div><div><br /></div><div><br /></div><div><br /></div><div><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-8629153789010909122020-06-10T16:48:00.007+09:002020-07-16T10:06:07.032+09:00Linux Device Driver for Embedded Processors 에피소드 2 - STM32MP157C Discovery Kit 소개(2)지난 시간에 이어 STM32MP157C Discovery Kit를 계속 분석(두번째 시간)해 보도록 하겠다. 😎<div><br /><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLSf1yOcIDAab-yhKH_RI8aoucCI1QdxBfLRlmiIyaz5EuNFq6SyKztsrUCLbabteuby2PoAYB5jWbMq1JGa0atlBD1xpVT9EU0Pf3FWUrvUC3jmCGZqNwKQTKrJsJbi59eXShzeuhEDsY/s4128/20200608_102904.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLSf1yOcIDAab-yhKH_RI8aoucCI1QdxBfLRlmiIyaz5EuNFq6SyKztsrUCLbabteuby2PoAYB5jWbMq1JGa0atlBD1xpVT9EU0Pf3FWUrvUC3jmCGZqNwKQTKrJsJbi59eXShzeuhEDsY/s320/20200608_102904.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><br /></div><div><b><font size="4">목차</font></b></div><div><i>1. </i><i><a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">STM32MP157C Discovery Kit 소개</a></i></div><div><i><b>2. Firmware(부팅 image)설치하기</b></i></div><div><i><b>3. 부팅 image 생성하기</b> - <font color="#f57c00">Yocto project, Buildroot</font></i></div><div><div><i>4. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">Qt application 개발 환경 설정 및 테스트해 보기</a></i></div><div><i>5. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">Device Tree 분석 및 Device Driver 시험하기 - i2c 예제 소개</a></i></div><div><i>6. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">온습도 센서 결과 확인용 Qt application 만들기</a></i></div><div><i>7. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">Cortex-M4 환경에서의 firmware 개발하기</a></i></div></div><div><i>8. References</i></div><div><font color="#b51200" size="2">(*) 목차는 처음 예정했던 내용과 차이가 날 수도 있다.</font></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">2. Firmware(부팅 image) 설치하기</font></b></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">STM32MP157C Discovery Kit(이하 </span><span style="text-align: left;">DK2 보드)에는 크게 4개(종류)의 USB port가 있는데, 아래 그림은 그 중 3개를 보여주고 있다. 왼쪽 port는 Power supply(<b>5V/3A USB type C</b>)용이고, 우측의 USB OTG(USB type C) port는 firmware upgrade(to microSD) 용이다. 그리고 아래쪽 port(micro USB B to USB A)는 ST-Linux/V2-1에 연결되어 있는데, debug용(linux 관점에서)으로 보면 된다.</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOcJqJJ4W2dolXwN0ydhjHBAM_eaFtWzxhBjSk3cJ59Lcx6szHCrbcxmDlAJ7lhIMoI1OsKEpxX5S8khxkHj44N1K47qk-i2IgpfZyXwAOCcPq378Nqvaijs2KZJKaQCxSOjJ14Pzrb3hW/s600/600px-STM32MP157C-DK2_with_power_stlink_flasher_ethernet+%25281%2529.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="544" data-original-width="600" height="363" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgOcJqJJ4W2dolXwN0ydhjHBAM_eaFtWzxhBjSk3cJ59Lcx6szHCrbcxmDlAJ7lhIMoI1OsKEpxX5S8khxkHj44N1K47qk-i2IgpfZyXwAOCcPq378Nqvaijs2KZJKaQCxSOjJ14Pzrb3hW/w400-h363/600px-STM32MP157C-DK2_with_power_stlink_flasher_ethernet+%25281%2529.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] STM32MP1 Connection block diagram</div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">참고: 아래 <span style="text-align: left;">ST-Linux/V2-1에 연결된 USB port(아래쪽 포트)는 Linux console port로 사용되지만, Cortex-M4용 flash에 firmware를 write하는 용도로도 사용된다.</span></font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">그럼, 이 상태에서 prebuilt firmware image를 이용해 microSD에 writing을 해 보기로 하자. 여기서는 microSD를 꺼내지 않고(즉, PC에 장착하지 않고), STM32CubeProgrammer & USB OTG port를 통해 직접(마치 nand flash writing을 하듯이) writing을 시도해 볼 것이다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><b><Firmware 설치 방법></b></div><div class="separator" style="clear: both; text-align: center;">MicroSD card <== ROM code(boot switch 조정) <== USB OTG <== <b><font color="#0b8043">STM32CubeProgrammer</font></b> <== firmware image file</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">지금부터 소개하는 내용은 모두 아래 site의 내용을 기준으로 하였다. 따라서 자세한 내용은 아래 site 내용을 참조하기로 하고, 여기에서는 반드시 필요한 내용 위주로 간략히 정리하기로 한다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Let%27s_start/Populate_the_target_and_boot_the_image">https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Let%27s_start/Populate_the_target_and_boot_the_image</a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><Desktop PC - Ubuntu 18.04></b></div><div class="separator" style="clear: both; text-align: left;">$ sudo apt-get install openjdk-8-jre-headless</div><div class="separator" style="clear: both; text-align: left;">$ sudo update-alternatives --config java</div><div class="separator" style="clear: both; text-align: left;"><i> -> Select the java-8-openjdk</i></div><div class="separator" style="clear: both; text-align: left;">$ sudo apt purge openjfx</div><div class="separator" style="clear: both; text-align: left;">$ sudo apt install openjfx=8u161-b12-1ubuntu2 libopenjfx-jni=8u161-b12-1ubuntu2 libopenjfx-java=8u161-b12-1ubuntu2</div><div class="separator" style="clear: both; text-align: left;">$ sudo apt-mark hold openjfx libopenjfx-jni libopenjfx-java</div><div class="separator" style="clear: both; text-align: left;">$ sudo apt-get install libusb-1.0-0</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#7b1fa2">Download STM32CubeProgrammer ...</font></b></div><div class="separator" style="clear: both; text-align: left;">$ unzip en.stm32cubeprog_v2-4-0.zip</div><div class="separator" style="clear: both; text-align: left;">$ <b>./SetupSTM32CubeProgrammer-2.4.0.linux</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyK6g5gTKYrESwbgx5U5M0eYFfYzN5sWT0TfbM_mrkN1TJ9ANJWxh0b2iEx1VEknB1XL6yNHKHbV6RNZonvzk3oEyVn72K13KhG1oD-_U4zzukYpbc3NR6QUD_wfYLN4AP6urMFVmBExpg/s640/stm32cubeprogram1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="480" data-original-width="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyK6g5gTKYrESwbgx5U5M0eYFfYzN5sWT0TfbM_mrkN1TJ9ANJWxh0b2iEx1VEknB1XL6yNHKHbV6RNZonvzk3oEyVn72K13KhG1oD-_U4zzukYpbc3NR6QUD_wfYLN4AP6urMFVmBExpg/s320/stm32cubeprogram1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.2] STM32CubeProgrammer 설치 시작 화면</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ vi ~/.bashrc</div><div class="separator" style="clear: both; text-align: left;">$ export PATH=/home/chyi/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin:$PATH</div><div class="separator" style="clear: both; text-align: left;">$ source ~/.bashrc</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#7b1fa2">Download STM32MP15-Ecosystem-v1.2.0 Starter Package ...</font></b></div><div class="separator" style="clear: both; text-align: left;">$ tar xvf en.FLASH-stm32mp1-openstlinux-20-02-19.tar.xz</div><div class="separator" style="clear: both; text-align: left;"><i> => 이안에 prebuilt booting image 파일이 포함되어 있음.</i></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><Target board 설정></b></div><div class="separator" style="clear: both; text-align: left;"><i>1) (전원을 인가하지 않은 상태에서) Target board 뒷 면의 boot switch를 아래와 같이 조정한다.</i></div><div class="separator" style="clear: both; text-align: left;"><i> => <font color="#9c27b0">firmware writing이 성공한 후, 재부팅을 하려면 다시 원복해 주어야 한다.</font></i></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQC48U96keCSgHYnPb8QtjRW_jzMHLW-aTqHMIGlQ9GQ3OW6JxzGrm9jKcOgf-JMyASbENPVXe9Hod1vJ9PXQLC2qU2ck_GZhQ4EFLqJVIyA3e4B978kZ3wc5UvT2AEQnyvghkNXlkUdwU/s493/STM32MP157C-DK2_jumper_flash.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="227" data-original-width="493" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQC48U96keCSgHYnPb8QtjRW_jzMHLW-aTqHMIGlQ9GQ3OW6JxzGrm9jKcOgf-JMyASbENPVXe9Hod1vJ9PXQLC2qU2ck_GZhQ4EFLqJVIyA3e4B978kZ3wc5UvT2AEQnyvghkNXlkUdwU/s320/STM32MP157C-DK2_jumper_flash.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.3] 보드 후면 부트 스위치 변경 모습</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">2) USB A to C cable을 USB OTG port에 연결한다.</div><div class="separator" style="clear: both; text-align: left;">3) 5V/3A power cable을 연결한다.</div><div class="separator" style="clear: both; text-align: left;"><i> <font color="#b51200">=> 5V/2A adapter 밖에 없으니, 이걸 일단 사용한다.</font></i></div><div class="separator" style="clear: both; text-align: left;">4) reset button을 눌러준다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><Desktop PC></b></div><div class="separator" style="clear: both; text-align: left;">1) 이 상태에서 앞서 설치한 STM32CubeProgrammer를 실행하자.</div><div class="separator" style="clear: both; text-align: left;">2) 화면 상단 우측의 USB 선택 후, Connect 버튼을 누른다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc1VokH6sS_YDouDEqsbxOElDv3JWZwX41DGZbMJCIHsSTCIPpShE5Qvtb5LHhamEB4CHYGLu_ENaTFvlul-kIlPr2fEtrPoNT3ev3cK5qENBFumbjgLzZDtZR756KjIoQ0Nb4CluJ52Fp/s1200/CubeProgrammer1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="798" data-original-width="1200" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc1VokH6sS_YDouDEqsbxOElDv3JWZwX41DGZbMJCIHsSTCIPpShE5Qvtb5LHhamEB4CHYGLu_ENaTFvlul-kIlPr2fEtrPoNT3ev3cK5qENBFumbjgLzZDtZR756KjIoQ0Nb4CluJ52Fp/w400-h266/CubeProgrammer1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.4] STM32CubeProgrammer 실행 모습(1)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">3) 화면 좌측의 Open file을 선택하여 image 파일을 선택한다.</div><div class="separator" style="clear: both; text-align: center;">stm32mp1-openstlinux-20-02-19/images/stm32mp1/flashlayout_st-image-weston/<b>FlashLayout_sdcard_stm32mp157c-dk2-trusted.tsv</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEwDEtZ5SxGuN5sjt8wmSIEBfHMICNoDopLU0FKQvxHfkpxQzKk6xpnmYFOcJOYwUgnSAphmKQky4NZcJTjOVDH8mEEpThe5dy0Cz7pAl_kBwlxDcH5fG1dToGiUNGN9NebCdC2_hlMDTP/s1200/CubeProgrammer2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="798" data-original-width="1200" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEwDEtZ5SxGuN5sjt8wmSIEBfHMICNoDopLU0FKQvxHfkpxQzKk6xpnmYFOcJOYwUgnSAphmKQky4NZcJTjOVDH8mEEpThe5dy0Cz7pAl_kBwlxDcH5fG1dToGiUNGN9NebCdC2_hlMDTP/w400-h266/CubeProgrammer2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.5] STM32CubeProgrammer 실행 모습(2)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">4) 화면 우측 중앙의 Download 버튼을 눌러 programming(writing)을 시작한다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgriM6Sen3OjXrUUFsnRFUl2eg0T4zEaqXBGjU6MFIYiqdPnIuOHSeBevPeG7qB5SNekwcrzesb1G2wiMh-tXAiNsvUaIlh5HWQXe5tWXGnHtCpwQt8TUePYAhOp9jdxkMUbGhuRehpBX9L/s1200/CubeProgrammer3.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="798" data-original-width="1200" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgriM6Sen3OjXrUUFsnRFUl2eg0T4zEaqXBGjU6MFIYiqdPnIuOHSeBevPeG7qB5SNekwcrzesb1G2wiMh-tXAiNsvUaIlh5HWQXe5tWXGnHtCpwQt8TUePYAhOp9jdxkMUbGhuRehpBX9L/w400-h266/CubeProgrammer3.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.6] STM32CubeProgrammer 실행 모습(3)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">5) Download가 진행되었고, 이후 설치가 되어야 하는데 ... 어랍쇼~ 에러가 나면서 program이 중지가 된다. Target board를 쳐다 보니, 빨간색 LED가 계속 깜빡거리고, serial console(minicom)에는 "<b>ERROR USB Type-C connection in unattached mode</b>"라는 메시지가 보인다. 뭔가 잘못되었다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvkQ6eV18xsujqB5jShZKvIsgkA_bwTDerHsVC-7aSFb5gy2kYTOkoz1aRS3xA_ngyOl_f5xXCIRKFxqQ6e9w-NsEb90k0mRvu1nhRfFfhTZ76psDryHAPzweftY7YlkpR-q0XMg4Yo7U/s1200/CubeProgammer4.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="798" data-original-width="1200" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUvkQ6eV18xsujqB5jShZKvIsgkA_bwTDerHsVC-7aSFb5gy2kYTOkoz1aRS3xA_ngyOl_f5xXCIRKFxqQ6e9w-NsEb90k0mRvu1nhRfFfhTZ76psDryHAPzweftY7YlkpR-q0XMg4Yo7U/w400-h266/CubeProgammer4.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.7] STM32CubeProgrammer 실행 모습(4) - 에러 발생</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200">아무래도 전류가 딸리는 모양이다. 5V/2A power adapter가 문제인 거 같다. </font>어쩔 수 없다. 5V/3A adapter를 하나 구매하는 수 밖에... 😂</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: #f7cb4d;"><font color="#9e9e9e">[나중에 다시 작성한 것임]</font> <b>5V/3A power adapter가 도착했다. 위의 작업을 계속 이어서 진행해 보니, 역시나 제대로 동작한다.</b></span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAQLrmkz0eHRm-AY_xZnWOsnm0UdzPMM25ZBTO1W3QK5nrjUStEeMu9Eiox3UmmbB0lmfD_Qp6J1ukeH2Wf61Z0jxefZTdVJtENhEfmZE1yAuSKdP-1mUU69RS0VIR1eFW1swsNZNporaH/s1312/stm32_cube_programmer_ok2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="889" data-original-width="1312" height="271" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAQLrmkz0eHRm-AY_xZnWOsnm0UdzPMM25ZBTO1W3QK5nrjUStEeMu9Eiox3UmmbB0lmfD_Qp6J1ukeH2Wf61Z0jxefZTdVJtENhEfmZE1yAuSKdP-1mUU69RS0VIR1eFW1swsNZNporaH/w400-h271/stm32_cube_programmer_ok2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.8] STM32CubeProgrammer 실행 모습(5) - OK 화면</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">[Tip] 끝까지 진행하는데 생각보다 시간이 꽤나 걸린다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HCOYKkq7roC8zb87QmrkcEqZdDhIqywL5GFVQH2XEfw1NpNuDpjLvi2-2h5z0COM9nzRVLBF7tHx43zd3MruZIkvpNQAR_NyID7MQh1C0mF3y7HBjBB7i5PkREsADL-x58CIXMDAuk_6/s4096/20200619_100719.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4096" data-original-width="3072" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_HCOYKkq7roC8zb87QmrkcEqZdDhIqywL5GFVQH2XEfw1NpNuDpjLvi2-2h5z0COM9nzRVLBF7tHx43zd3MruZIkvpNQAR_NyID7MQh1C0mF3y7HBjBB7i5PkREsADL-x58CIXMDAuk_6/s320/20200619_100719.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.9] STM32CubeProgrammer 실행 모습(6) - LCD에 출력 모습</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMG2yWUAs41Y-GE2UOoi5EnXab9zmSuonouUvb7ObSFR5FK46-Vn7gmEeq8cTbFFp1MgnGZSYASpH1GZx9z_Y-x0jRawhURbZA5cQx2srvYQ9s7OQbCfM4n_te4bVWxCW3HRhN2yZD5H7y/s4128/20200619_101826.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4128" data-original-width="3096" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMG2yWUAs41Y-GE2UOoi5EnXab9zmSuonouUvb7ObSFR5FK46-Vn7gmEeq8cTbFFp1MgnGZSYASpH1GZx9z_Y-x0jRawhURbZA5cQx2srvYQ9s7OQbCfM4n_te4bVWxCW3HRhN2yZD5H7y/s320/20200619_101826.jpg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.10] 재부팅 모습</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b style="background-color: #c6dafc;"><여기서 잠깐 ! STM32MP boot chains에 관하여></b></div><div class="separator" style="clear: both; text-align: left;">아래 그림에서 보는 것과 같이 STM32MP의 booting flow(chain)는 꽤나 복잡하게 구성되어 있다. 단순히 u-boot, linux kernel만 이해한다고 끝날게 아닌 것 같다. <b><font color="#f57c00">좀 더 면밀히 분석할 필요가 있어 보인다.</font></b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFi7SxcHH33Si1PVmzaWUn-zN6ownuAbQbAxRmwqDrPj782DzmaN1kI3HWGIxRg7455kcwCWbNX8dDkATqkS__y2_K4bK19ptCc2XiqTLKmyZdkxz_GAruFPVH0TmQLz08M0efBw7JTR3I/s705/stm32mp1_bootchain.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="556" data-original-width="705" height="504" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFi7SxcHH33Si1PVmzaWUn-zN6ownuAbQbAxRmwqDrPj782DzmaN1kI3HWGIxRg7455kcwCWbNX8dDkATqkS__y2_K4bK19ptCc2XiqTLKmyZdkxz_GAruFPVH0TmQLz08M0efBw7JTR3I/w640-h504/stm32mp1_bootchain.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.11] Trusted boot chain</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">참고: TF-A, OP-TEE 등은 trusted boot(or secure boot)를 위해 개발된 open source들인데, 추후 좀 더 알아보아야 할 듯 하다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#9e9e9e">5V/3A power adapter를 구매하는데 시간이 좀 필요하므로, </font>그 전에 bootloader, kernel code 등을 먼저 build해 보아야 겠다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#3367d6" size="6">3. 부팅 image 생성하기</font></b></div><div class="separator" style="clear: both; text-align: left;">2장을 보면서 느꼈겠지만, STM32MPU booting에 필요한 요소(TF-A, OP-TEE, u-boot, kernel, coprocessor용 firmware 등)가 생각보다 많고 꽤나 복잡해 보인다. 따라서 이번 장에서는 Yocto project와 Buildroot를 통해 이런 요소들이 전체적으로 어떻게 build되고 생성되는지를 따져 보도록 하자.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#0b8043" size="4">a) Yocto project를 통한 이미지 생성</font></b></div><div class="separator" style="clear: both; text-align: left;">먼저 이절에서는 아래 site 내용을 참조하여 Yocto/OpenEmbedded를 기반으로 image를 생성하는 방법을 정리해 보도록 하겠다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://wiki.st.com/stm32mpu/wiki/STM32MP1_Distribution_Package">https://wiki.st.com/stm32mpu/wiki/STM32MP1_Distribution_Package</a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbXTOyTAAQ3bIeJn4uaV15vjSGQUx2yXNcSds0DWGjtMQdL1Gt2uxe-yPq13hcNlAaYyzPnZk9kpqX1_yXjTd4sw4u-4rQxAsyLEsc4H2irvNgFbK_QmSyWdr9pg8_FF66_olXud6w-Klm/s600/600px-STM32_MPU_Embedded_Software_Distribution_Package.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbXTOyTAAQ3bIeJn4uaV15vjSGQUx2yXNcSds0DWGjtMQdL1Gt2uxe-yPq13hcNlAaYyzPnZk9kpqX1_yXjTd4sw4u-4rQxAsyLEsc4H2irvNgFbK_QmSyWdr9pg8_FF66_olXud6w-Klm/s320/600px-STM32_MPU_Embedded_Software_Distribution_Package.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] Distribution 패키지 구성 요소</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ mkdir openstlinux-20-02-19</div><div class="separator" style="clear: both; text-align: left;">$ cd openstlinux-20-02-19</div><div class="separator" style="clear: both; text-align: left;">$ <b>repo init -u https://github.com/STMicroelectronics/oe-manifest.git -b refs/tags/openstlinux-20-02-19</b></div><div class="separator" style="clear: both; text-align: left;">$ <b>repo sync</b></div><div class="separator" style="clear: both; text-align: left;"><b><br /></b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjelvplJJ7pqB72qLxdTMZBmqUz641kUTbWqeyKbf1mCjKhNsSy9zy6lCODQLw4w1WM8Zk6qahdoIn__zsuoHznU6XP7iZWT6GjgVNVEaS0-yiNwYYjcj2RlzbqGFWUg23WM7tn6y6bTbqr/s869/stm32mp1_yocto_layers.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="865" data-original-width="869" height="399" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjelvplJJ7pqB72qLxdTMZBmqUz641kUTbWqeyKbf1mCjKhNsSy9zy6lCODQLw4w1WM8Zk6qahdoIn__zsuoHznU6XP7iZWT6GjgVNVEaS0-yiNwYYjcj2RlzbqGFWUg23WM7tn6y6bTbqr/w400-h399/stm32mp1_yocto_layers.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] meta-st 관련 주요 파일들</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ <b>DISTRO=openstlinux-weston MACHINE=stm32mp1 source layers/meta-st/scripts/envsetup.sh</b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: left;"><font size="1">[HOST DISTRIB check]</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">Linux Distrib: Ubuntu</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">Linux Release: 18.04</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">[source layers/openembedded-core/oe-init-build-env][from nothing]</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">[EULA configuration]</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">[Configure *.conf files]</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">[INFO] No 'site.conf.sample' file available at /home/chyi/workspace/Boards/STM32MP1/workspace/distribution/openstlinux-20-02-19/layers/meta-st/scripts. Create default one...</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">===========================================================================</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">Configuration files have been created for the following configuration:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> DISTRO : openstlinux-weston</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> DISTRO_CODENAME : thud</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> MACHINE : stm32mp1</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> BB_NUMBER_THREADS : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> PARALLEL_MAKE : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> BUILDDIR : build-openstlinuxweston-stm32mp1</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> DOWNLOAD_DIR : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> SSTATE_DIR : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> SOURCE_MIRROR_URL : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> SSTATE_MIRRORS : <no-custom-config-set></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> WITH_EULA_ACCEPTED: YES</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">===========================================================================</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">Available images for OpenSTLinux layers are:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> - Official OpenSTLinux images:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> st-image-weston - OpenSTLinux weston image with basic Wayland support (if enable in distro)</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> - Other OpenSTLinux images:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> - Supported images:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> st-image-core - OpenSTLinux core image</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> - Proposed images as example only:</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> st-example-image-qt - ST example of image based on Qt framework (require 'openstlinux-eglfs' distro)</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> st-example-image-x11 - ST example of image based on X11 (require 'openstlinux-x11' distro)</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> st-example-image-xfce - ST example of image based on XFCE framework (require 'openstlinux-x11' distro)</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"> and more images are available on meta-st-openstlinux/recipes-samples/images.</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">You can now run 'bitbake <image>'</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ <b>bitbake st-image-weston</b></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RSPBX8j0_umvtzA_K-N3BQcLcUf30pkXtWj9iNLa6IOjdDa6i4p7MiQcoW_YlE2h8v3v4wTTK4wxK_EyRWwPby-slPZ8MePurZFBGDPp1bA8YZaetCMsiyo3civ7N-KIErQG8RKqfkXF/s982/stm32mp1_yocto1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="945" data-original-width="982" height="385" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RSPBX8j0_umvtzA_K-N3BQcLcUf30pkXtWj9iNLa6IOjdDa6i4p7MiQcoW_YlE2h8v3v4wTTK4wxK_EyRWwPby-slPZ8MePurZFBGDPp1bA8YZaetCMsiyo3civ7N-KIErQG8RKqfkXF/w400-h385/stm32mp1_yocto1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] Yocto/OpenEmbedded build 모습</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ cd tmp-glibc/deploy/images/stm32mp1</div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: left;">$ ls -la</div><div class="separator" style="clear: both; text-align: left;"><font size="1">합계 1870164</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">drwxr-xr-x 4 chyi chyi 16384 6월 9 21:01 .</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">drwxr-xr-x 3 chyi chyi 4096 6월 9 18:22 ..</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 44 6월 9 19:21 Image -> Image--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 17589768 6월 9 19:21 Image--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 44 6월 9 19:21 Image-stm32mp1.bin -> Image--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">drwxr-xr-x 2 chyi chyi 4096 6월 9 21:01 flashlayout_st-image-weston</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">drwxr-xr-x 2 chyi chyi 4096 6월 9 18:22 scripts</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 67108864 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.bootfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 6732772 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.bootfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 139 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 355706 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 11010048 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.bootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 10158080 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.bootfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 355 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 70 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1.ext4 -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.bootfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 74 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1.manifest -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 72 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1.tar.xz -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.bootfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 72 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1.testdata.json -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 80 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1_nand_4_256.ubi -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.bootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 82 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1_nand_4_256.ubifs -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.bootfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 85 6월 9 20:49 st-image-bootfs-openstlinux-weston-stm32mp1_nand_4_256.ubinize.cfg.ubi -> st-image-bootfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 11080 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 355775 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 100308992 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.userfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 62478284 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.userfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 357 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 72351744 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.userfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 69582848 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.userfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 70 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1.ext4 -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.userfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 74 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1.manifest -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 72 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1.tar.xz -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.userfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 72 6월 9 20:08 st-image-userfs-openstlinux-weston-stm32mp1.testdata.json -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 80 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1_nand_4_256.ubi -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.userfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 82 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1_nand_4_256.ubifs -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.userfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 85 6월 9 20:09 st-image-userfs-openstlinux-weston-stm32mp1_nand_4_256.ubinize.cfg.ubi -> st-image-userfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 274 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 356324 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 16777216 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.vendorfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 2251344 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.vendorfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 367 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 7864320 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.vendorfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 7110656 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.vendorfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 74 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1.ext4 -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.vendorfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 76 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1.manifest -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 76 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1.tar.xz -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.vendorfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 74 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1.testdata.json -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 84 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1_nand_4_256.ubi -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.vendorfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 86 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1_nand_4_256.ubifs -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.vendorfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 87 6월 9 19:48 st-image-vendorfs-openstlinux-weston-stm32mp1_nand_4_256.ubinize.cfg.ubi -> st-image-vendorfs-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 303914 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922-license_content.html</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 21707 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922.license</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 530441216 6월 9 21:00 st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 79102 6월 9 20:59 st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 103492068 6월 9 21:00 st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 359952 6월 9 20:59 st-image-weston-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 216006656 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.rootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 208748544 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.rootfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 357 6월 9 21:00 st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 305659904 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256_multivolume.rootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 1545 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256_multivolume.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 79 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1-license_content.html -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922-license_content.html</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 70 6월 9 21:00 st-image-weston-openstlinux-weston-stm32mp1.ext4 -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.ext4</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 66 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1.license -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922.license</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 74 6월 9 20:59 st-image-weston-openstlinux-weston-stm32mp1.manifest -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.manifest</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 72 6월 9 21:00 st-image-weston-openstlinux-weston-stm32mp1.tar.xz -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922.rootfs.tar.xz</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 72 6월 9 20:59 st-image-weston-openstlinux-weston-stm32mp1.testdata.json -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922.testdata.json</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 80 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1_nand_4_256.ubi -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.rootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 82 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1_nand_4_256.ubifs -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.rootfs.ubifs</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 85 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1_nand_4_256.ubinize.cfg.ubi -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 92 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1_nand_4_256_multivolume.ubi -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256_multivolume.rootfs.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 1 chyi chyi 97 6월 9 21:01 st-image-weston-openstlinux-weston-stm32mp1_nand_4_256_multivolume.ubinize.cfg.ubi -> st-image-weston-openstlinux-weston-stm32mp1-20200609082922_nand_4_256_multivolume.ubinize.cfg.ubi</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 71751 6월 9 19:21 stm32mp157a-dk1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157a-dk1-stm32mp1.dtb -> stm32mp157a-dk1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157a-dk1.dtb -> stm32mp157a-dk1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 73578 6월 9 19:21 stm32mp157c-dk2--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 73626 6월 9 19:21 stm32mp157c-dk2-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-dk2-a7-examples-stm32mp1.dtb -> stm32mp157c-dk2-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-dk2-a7-examples.dtb -> stm32mp157c-dk2-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 74162 6월 9 19:21 stm32mp157c-dk2-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-dk2-m4-examples-stm32mp1.dtb -> stm32mp157c-dk2-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-dk2-m4-examples.dtb -> stm32mp157c-dk2-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-dk2-stm32mp1.dtb -> stm32mp157c-dk2--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-dk2.dtb -> stm32mp157c-dk2--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 68471 6월 9 19:21 stm32mp157c-ed1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-ed1-stm32mp1.dtb -> stm32mp157c-ed1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-ed1.dtb -> stm32mp157c-ed1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 78033 6월 9 19:21 stm32mp157c-ev1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 78340 6월 9 19:21 stm32mp157c-ev1-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-ev1-a7-examples-stm32mp1.dtb -> stm32mp157c-ev1-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-ev1-a7-examples.dtb -> stm32mp157c-ev1-a7-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 78673 6월 9 19:21 stm32mp157c-ev1-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-ev1-m4-examples-stm32mp1.dtb -> stm32mp157c-ev1-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 66 6월 9 19:21 stm32mp157c-ev1-m4-examples.dtb -> stm32mp157c-ev1-m4-examples--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-ev1-stm32mp1.dtb -> stm32mp157c-ev1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 54 6월 9 19:21 stm32mp157c-ev1.dtb -> stm32mp157c-ev1--4.19-r0.2-stm32mp1-20200609082922.dtb</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 300 6월 9 20:00 tee-header_v2-stm32mp157a-dk1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 300 6월 9 20:00 tee-header_v2-stm32mp157c-dk2-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 300 6월 9 20:00 tee-header_v2-stm32mp157c-ed1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 300 6월 9 20:00 tee-header_v2-stm32mp157c-ev1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 147712 6월 9 20:00 tee-pageable_v2-stm32mp157a-dk1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 147712 6월 9 20:00 tee-pageable_v2-stm32mp157c-dk2-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 147712 6월 9 20:00 tee-pageable_v2-stm32mp157c-ed1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 151808 6월 9 20:00 tee-pageable_v2-stm32mp157c-ev1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 84512 6월 9 20:00 tee-pager_v2-stm32mp157a-dk1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 84512 6월 9 20:00 tee-pager_v2-stm32mp157c-dk2-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 84512 6월 9 20:00 tee-pager_v2-stm32mp157c-ed1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 84544 6월 9 20:00 tee-pager_v2-stm32mp157c-ev1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 4048748 6월 9 20:00 tee-stm32mp157a-dk1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 4048748 6월 9 20:00 tee-stm32mp157c-dk2-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 4048748 6월 9 20:00 tee-stm32mp157c-ed1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 4052844 6월 9 20:00 tee-stm32mp157c-ev1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 833568 6월 9 20:49 tf-a-bl2-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 943132 6월 9 20:49 tf-a-bl2-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 900152 6월 9 20:49 tf-a-bl32-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 224997 6월 9 20:49 tf-a-stm32mp157a-dk1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 245384 6월 9 20:49 tf-a-stm32mp157a-dk1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 224997 6월 9 20:49 tf-a-stm32mp157c-dk2-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 245384 6월 9 20:49 tf-a-stm32mp157c-dk2-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 224997 6월 9 20:49 tf-a-stm32mp157c-ed1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 245384 6월 9 20:49 tf-a-stm32mp157c-ed1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 224997 6월 9 20:49 tf-a-stm32mp157c-ev1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 245384 6월 9 20:49 tf-a-stm32mp157c-ev1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 2312644 6월 9 20:54 u-boot-spl.elf-stm32mp157a-dk1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 2312644 6월 9 20:54 u-boot-spl.elf-stm32mp157c-dk2-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 2312644 6월 9 20:54 u-boot-spl.elf-stm32mp157c-ed1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 2312644 6월 9 20:54 u-boot-spl.elf-stm32mp157c-ev1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 101049 6월 9 20:54 u-boot-spl.stm32-stm32mp157a-dk1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 101113 6월 9 20:54 u-boot-spl.stm32-stm32mp157c-dk2-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 102415 6월 9 20:54 u-boot-spl.stm32-stm32mp157c-ed1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 103521 6월 9 20:54 u-boot-spl.stm32-stm32mp157c-ev1-basic</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 9028612 6월 9 20:54 u-boot-stm32mp157a-dk1-basic.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 812862 6월 9 20:54 u-boot-stm32mp157a-dk1-basic.img</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755788 6월 9 20:54 u-boot-stm32mp157a-dk1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 808778 6월 9 20:54 u-boot-stm32mp157a-dk1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755684 6월 9 20:54 u-boot-stm32mp157a-dk1-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 808674 6월 9 20:54 u-boot-stm32mp157a-dk1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 9028612 6월 9 20:54 u-boot-stm32mp157c-dk2-basic.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 814689 6월 9 20:54 u-boot-stm32mp157c-dk2-basic.img</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755788 6월 9 20:54 u-boot-stm32mp157c-dk2-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 810605 6월 9 20:54 u-boot-stm32mp157c-dk2-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755684 6월 9 20:54 u-boot-stm32mp157c-dk2-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 810501 6월 9 20:54 u-boot-stm32mp157c-dk2-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 9028612 6월 9 20:54 u-boot-stm32mp157c-ed1-basic.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 809668 6월 9 20:54 u-boot-stm32mp157c-ed1-basic.img</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755788 6월 9 20:54 u-boot-stm32mp157c-ed1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 805584 6월 9 20:54 u-boot-stm32mp157c-ed1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755684 6월 9 20:54 u-boot-stm32mp157c-ed1-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 805480 6월 9 20:54 u-boot-stm32mp157c-ed1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 9028612 6월 9 20:54 u-boot-stm32mp157c-ev1-basic.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 819589 6월 9 20:54 u-boot-stm32mp157c-ev1-basic.img</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755788 6월 9 20:54 u-boot-stm32mp157c-ev1-optee.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 815505 6월 9 20:54 u-boot-stm32mp157c-ev1-optee.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 8755684 6월 9 20:54 u-boot-stm32mp157c-ev1-trusted.elf</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 1 chyi chyi 815401 6월 9 20:54 u-boot-stm32mp157c-ev1-trusted.stm32</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 45 6월 9 19:21 uImage -> uImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 6722112 6월 9 19:21 uImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 45 6월 9 19:21 uImage-stm32mp1.bin -> uImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 46 6월 9 19:21 vmlinux -> vmlinux--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 210023156 6월 9 19:21 vmlinux--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 46 6월 9 19:21 vmlinux-stm32mp1.bin -> vmlinux--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 45 6월 9 19:21 zImage -> zImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">-rw-r--r-- 2 chyi chyi 6722048 6월 9 19:21 zImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div class="separator" style="clear: both; text-align: left;"><font size="1">lrwxrwxrwx 2 chyi chyi 45 6월 9 19:21 zImage-stm32mp1.bin -> zImage--4.19-r0.2-stm32mp1-20200609082922.bin</font></div><div><br /></div><div>오 이런 ~ 너무나도 많은 결과 파일이 생긴다. <font color="#f4a900">이번 posting에서는 Yocto 관련 내용은 요 정도만 언급하고, 나머지는 부분은 모두 Buildroot 환경에서 확인할 생각이다.</font></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><font color="#0b8043" size="4">b) Buildroot를 통한 이미지 생성</font></b></div><div class="separator" style="clear: both; text-align: left;">다행히도 최신 buildroot source에는 DK2 board가 이미 porting되어 있다. 따라서 아래와 같은 간단한 방법으로 build가 가능하다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ <span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><b>git clone git://git.buildroot.net/buildroot</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;">$ cd buildroot</span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;">$ </span><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><b>make stm32mp157c_dk2_defconfig</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLidjZzxptpM66IbsJOun4wlYuPufG9c11__1kR72Js6gy7EC7ewUvYs_FYYjZMzMeo-ZpTSK2P0jYIA5mgFch2ypl7_mzlooJ5CMRBEVrJNNKzuBi-MzLgx_83msBcCrDA52y96_dZECq/s908/dk2_defconfig.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="603" data-original-width="908" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLidjZzxptpM66IbsJOun4wlYuPufG9c11__1kR72Js6gy7EC7ewUvYs_FYYjZMzMeo-ZpTSK2P0jYIA5mgFch2ypl7_mzlooJ5CMRBEVrJNNKzuBi-MzLgx_83msBcCrDA52y96_dZECq/s320/dk2_defconfig.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.4] stm32mp157c_dk2_defconfig 파일</div></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;">$ <b>make menuconfig</b></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi28f9f2et8wG1oD8MiFXH8w4XcSPyVnCPdQnGGWV12xSe4Lp9XsJB8Nn6QmU5vgoz4MBV1bqr6LVO4eFHPMYUMEWjFoCZVBqOCB6N44EJpwMtAVB1oIsPYAEdFk69htHX2OIxG0mXkIETA/s968/dk2_buildroot_bootloader.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="636" data-original-width="968" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi28f9f2et8wG1oD8MiFXH8w4XcSPyVnCPdQnGGWV12xSe4Lp9XsJB8Nn6QmU5vgoz4MBV1bqr6LVO4eFHPMYUMEWjFoCZVBqOCB6N44EJpwMtAVB1oIsPYAEdFk69htHX2OIxG0mXkIETA/w400-h263/dk2_buildroot_bootloader.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.5] Bootloaders 메뉴 - u-boot SPL(FSBL), u-boot(SSBL)</div></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;">$ <b>make</b></span></div><div class="separator" style="clear: both; text-align: left;"> <i> => buildroot는 상대적으로 결과물이 매우 단출하다.</i></div><div class="separator" style="clear: both; text-align: left;"><i> => 특이한 점은 u-boot이 SPL(u-boot-spl.stm32)과 u-boot.img로 2개가 만들어 진다는 점이다.</i></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF3-xj9A7NM42aCLXuq6KGNw_l0KccVMEuwChBGpbUjU3f-p_afYXFHWTA17xzAaO_ZOJFFnO1XnyqBUFnJzskX7PL890L-Q2PtSNDnhbnO-qtaom8xEG0c2ZOF2qpNR0QeiRDSJupGd8i/s812/dk2_buildroot_images.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="206" data-original-width="812" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhF3-xj9A7NM42aCLXuq6KGNw_l0KccVMEuwChBGpbUjU3f-p_afYXFHWTA17xzAaO_ZOJFFnO1XnyqBUFnJzskX7PL890L-Q2PtSNDnhbnO-qtaom8xEG0c2ZOF2qpNR0QeiRDSJupGd8i/w640-h162/dk2_buildroot_images.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.6] buildroot build 결과 파일</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Buildroot는 file system image를 build하고 나면, support/scripts/<b>genimage.sh </b>파일을 통해 최종 sdcard.img 파일을 생성하게 된다(이때, <b>genimage.cfg</b> 파일이 사용됨).</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><configs/stm32mp157c_dk2_defconfig></b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: left;"> BR2_ROOTFS_POST_IMAGE_SCRIPT="support/scripts/genimage.sh"</div><div class="separator" style="clear: both; text-align: left;"> BR2_ROOTFS_POST_SCRIPT_ARGS="-c board/stmicroelectronics/common/stm32mp157/genimage.cfg"</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdjRTs1Wrs6UG2pfp8v6EBN3cggOkvLriUQFBBmZq9JA4_z4kB4OD0E_Kr_TJaXfwExfzjuulgd9c0PU6zrFUCmAuZzxNCgk93U5Z6tTTCcUJr1v1RNEKzu22PZp96iNYYvu8v9d3gCog7/s432/dk2_buildroot_genimage_cfg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="348" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdjRTs1Wrs6UG2pfp8v6EBN3cggOkvLriUQFBBmZq9JA4_z4kB4OD0E_Kr_TJaXfwExfzjuulgd9c0PU6zrFUCmAuZzxNCgk93U5Z6tTTCcUJr1v1RNEKzu22PZp96iNYYvu8v9d3gCog7/s320/dk2_buildroot_genimage_cfg.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.7] board/stmicroelectronics/common/stm32mp157/genimage.cfg 파일</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">sdcard.img 생성 및 부팅과 관련해서는 몇가지 집고 넘어가야할 내용이 있는데, 이를 간단히 정리해 보면 다음과 같다.</div><div class="separator" style="clear: both; text-align: justify;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><span style="text-align: left;">1) sdcard.img는 </span><a href="https://en.wikipedia.org/wiki/GUID_Partition_Table" style="text-align: left;">GPT partition table</a><span style="text-align: left;"> 스펙에 맞는 파티션 정보를 갖도록 만들어진다.</span></font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><span style="text-align: left;"><br /></span></font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIQAA-GRCoCHorxkB5mUabjo-kz-QpEqtGtjGt16jm9riNyasYgRH0jM0gXVxuWL4tlTPrK2f0fgOQ-ZX8fgrP26oHpBbf3OXWf5sWK0aZ5iZhfhj_bCqDyvggVVXJeo8E5eWmVwmkeSpg/s413/300px-GUID_Partition_Table_Scheme.svg.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="413" data-original-width="300" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIQAA-GRCoCHorxkB5mUabjo-kz-QpEqtGtjGt16jm9riNyasYgRH0jM0gXVxuWL4tlTPrK2f0fgOQ-ZX8fgrP26oHpBbf3OXWf5sWK0aZ5iZhfhj_bCqDyvggVVXJeo8E5eWmVwmkeSpg/s320/300px-GUID_Partition_Table_Scheme.svg.png" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><br /></div></div></font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2">2) 위의 그림 3.7에서 linux kernel 및 dtb 파일은 별도의 파티션이 아니라 rootfs 파티션(정확히는 /boot 디렉토리)에 포함되어 있다.</font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2">3) rootfs 파티션에는 bootable="yes" 부분이 있는데, 이는 u-boot으로 하여금 bootable로 표시된 파티션을 찾은 후, 다시 (해당 파일 시스템에서) extlinux.conf(예: /boot/extlinux/extlinux.conf) 파일을 찾아내어 이를 토대로 부팅하도록 도와 준다. 즉, u-boot이 kernel 파티션이 없는 상황에서 어디에 kernel이 위치하고, kernel image 명이 무엇인지를 확인하기 위해 extlinux.conf 파일이 활용된다는 뜻이다.</font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2">4) extlinux.conf 파일 내용 중, root=/dev/mmcblk0p4 rootwait 스트링은 u-boot이 kernel에 argument로 넘기는 내용이다. kernel은 이 내용을 보고 rootfs가 어느 파티션에 위치하는지를 알게 된다.</font></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: justify;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw9ZFbY5rsXg0K6Ga_JuvlIvNcKIXYPmfgKiGmRMDVpb7NQ5H8GH_mq2D9J75L4PejLBSk0Oam966qBgTyP7QCbZQLRQDtJoIwUrjfo-JrfG1ZGZPIQ3Lmi66S0AeVee_scosP7VJKv6NN/s368/dk2_buildroot_extlinux_conf.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="105" data-original-width="368" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgw9ZFbY5rsXg0K6Ga_JuvlIvNcKIXYPmfgKiGmRMDVpb7NQ5H8GH_mq2D9J75L4PejLBSk0Oam966qBgTyP7QCbZQLRQDtJoIwUrjfo-JrfG1ZGZPIQ3Lmi66S0AeVee_scosP7VJKv6NN/s320/dk2_buildroot_extlinux_conf.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.8] </span><span style="text-align: justify;">board/stmicroelectronics/stm32mp157c-dk2/overlay/boot/extlinux/extlinux.conf 파일</span></div></div><div class="separator" style="clear: both; text-align: justify;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">앞서 얻은 결과를 토대로, 전체적인 부팅 순서를 정리해 보면 대략 아래와 같다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: center;"><b>Boot ROM code -> u-boot SPL(first stage bootloader) -> u-boot(second stage bootloader) -> linux kernel ...</b></div></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">참고: 편의 상 Coprocessor(Cortex-M4)에 설치된 firmware를 구동시키는 부분은 내용에서 제외하였다. 정확치는 않지만 u-boot or linux kernel에서 이를 수행하는 듯 보인다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2">1) STM32MP157 ROM code는 GPT partition 중 fsbl로 시작하는 파티션을 찾은 후, 그 내용을 내부 system memory에 loading 후 실행한다(=> first stage bootloader).</font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2">2) First stage bootloader(u-boot SPL)는 sdcard의 3번째 파티션의 내용(second stage bootloader)을 loading하도록 hard coding되어 있다. 따라서 external RAM을 초기화한 후, second stage bootloader(u-boot)를 RAM에 loading후, 이를 실행시킨다.</font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2">3) Second stage bootloader는 sdcard 파티션 중 bootable로 표시된 녀석을 찾은 후, 다시 /boot/extlinux/extlinux.conf 파일을 찾아 이 내용을 참조하여 kernel과 dtb file을 RAM에 loading 시킨다. 이후 kernel을 실행하면서, argument로 "root=/dev/mmcblk0p4 rootwait"를 전달한다.</font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2">4) Kernel은 부팅 후반부에 root=/dev/mmcblk0p4 내용을 참조하여 root file system을 mount하게 되는데, rootfs mount가 진행되고 나면, kernel은 user space process(예: init)를 실행시키게 된다.</font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><font color="#0b8043" size="2">5) 제일 처음 실행되는 /sbin/init process는 busybox에 포함된 녀석(buildroot 기준)이며, 몇가지 service를 시작시킨 후, login prompt를 띄우게 된다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">USB OTG를 통한 firmware writing이 현재로써는 불가(전류 문제)하니, microSD를 desktop PC에 붙여 image writing을 시도해 보도록 하자. 이와 관련해서는 아래 위치에 있는 readme.txt 파일을 참고할 필요가 있다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><b>board/stmicroelectronics/stm32mp157c-dk2/readme.txt</b></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><Desktop PC></b></div><div class="separator" style="clear: both; text-align: left;"><div class="separator" style="clear: both; text-align: left;">$ <b>sudo dd if=./output/images/sdcard.img of=/dev/sdb</b></div><div class="separator" style="clear: both; text-align: left;"><font size="2">247694+0 레코드 들어옴</font></div><div class="separator" style="clear: both; text-align: left;"><font size="2">247694+0 레코드 나감</font></div><div class="separator" style="clear: both; text-align: left;"><font size="2">126819328 bytes (127 MB, 121 MiB) copied, 26.464 s, 4.8 MB/s</font></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">microSD를 다시 board에 장착 후, 부팅을 시도해 보니, u-boot SPL(FSBL) => u-boot(SSBL)까지 구동되고 멈춰 버린다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbrQOAy5KYnKX-AFdsFGJ5S3HFhOU2hZEw62B4rm1M5cyBuH49gKxK0qrHffUYW6iURe9djfYvfaCiMp9VW7g5ZTtbxOBB4t8AToytu1eFMAW3Z00m-xam7DvypGpjAUJdNkrLjf349oLp/s726/dk2_buildroot_boot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="726" height="353" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbrQOAy5KYnKX-AFdsFGJ5S3HFhOU2hZEw62B4rm1M5cyBuH49gKxK0qrHffUYW6iURe9djfYvfaCiMp9VW7g5ZTtbxOBB4t8AToytu1eFMAW3Z00m-xam7DvypGpjAUJdNkrLjf349oLp/w400-h353/dk2_buildroot_boot.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.9] sdcard.img 설치 후, 부팅 모습(u-boot SL => u-boot)</span></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200">오, 이런... 5V/3A 없으면 부팅도 안되는 군 ... s**t, f**k 👿</font></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200"><br /></font></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: #f7cb4d;">(주문한지 2틀만에) <b>5V/3A USB-C type power adapter</b>가 도착했다(정말 우리는 배달의 민족^^). 전원을 넣어 보니, 역시 정상적으로 부팅이 된다. 🙆</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqbidj1_F6HqzrreC_HwsByOA0_o87E7BtpueVB3cc4NoqcFbREgpVFdQQwAAJ79ABMXQL7SsD5HxoKVG3ZT3SXGY0X6D4Xy7Mh3QZ4sUg2FvPC-VaqDRPjN8zQJWmxVycMTYT3Q-ZSelu/s833/dk2_5v3a_minicom.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="746" data-original-width="833" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqbidj1_F6HqzrreC_HwsByOA0_o87E7BtpueVB3cc4NoqcFbREgpVFdQQwAAJ79ABMXQL7SsD5HxoKVG3ZT3SXGY0X6D4Xy7Mh3QZ4sUg2FvPC-VaqDRPjN8zQJWmxVycMTYT3Q-ZSelu/s320/dk2_5v3a_minicom.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.10] sdcard.img 설치 후, 정상 부팅 모습(u-boot SL => u-boot => kernel)</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvz9w-HJcSDZeeRSZTDzJjpjOYFc7u16u3zCX04l32KdRL9xYlN00zOv9_p0g_ilIhTPT1zFtSh_o354Vs17LdyWf92NYnXZQlFo6yY9ZtS6oSqAVW3KYQf8y8HiyuI_xYPrADDSaRkle_/s4128/20200612_150355.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvz9w-HJcSDZeeRSZTDzJjpjOYFc7u16u3zCX04l32KdRL9xYlN00zOv9_p0g_ilIhTPT1zFtSh_o354Vs17LdyWf92NYnXZQlFo6yY9ZtS6oSqAVW3KYQf8y8HiyuI_xYPrADDSaRkle_/s320/20200612_150355.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 3.11] 정상 부팅 모습 - LCD에 부팅 message 출력</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><div><b><font color="#3367d6" size="6">4. Qt application 개발환경 설정 및 테스트해 보기</font></b></div><div>이 장에서는 DK2 보드에서 Qt5 application을 돌려 보기 위해 필요한 환경 설정 부분과 몇가지 Qt app을 실행하는 내용을 소개해 보고자 한다.</div><div><br /></div><div><b><font color="#f57c00">To be continued...</font></b></div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div style="background-color: white; color: #333333; font-family: arial, tahoma, helvetica, freesans, sans-serif; font-size: 14.85px;"><b style="font-family: "noto sans cjk kr";"><font color="#3367d6" size="6">8. References</font></b></div><div style="background-color: white;">[1] https://www.st.com/en/embedded-software/stm32cubemp1.html</div><div style="background-color: white;">[2] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/" style="background-color: transparent;">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/</a></div><div style="background-color: white;"><br /></div><div style="background-color: white;"><br /></div><div style="background-color: white; text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div style="background-color: white;"><br /></div></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com3tag:blogger.com,1999:blog-6346200245600677355.post-42975491697077653642020-06-08T17:18:00.010+09:002020-07-16T13:52:13.063+09:00Linux Device Driver for Embedded Processors 에피스드 2 - STM32MP157C Discovery Kit 소개지난 주에 주문한 STM32MP157C Discovery Kit(<font color="#9e9e9e">$99 - 배송비 포함하면 12~13만원 정도</font>)가 일주일만에 도착했다. 😎 <div><br /></div><div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEXm-z0mrgqPLr1xHEHIHgmVgHQun9BHqSrU9hN4P3G5iYXogtYfCldJ-EakwWwp2kxrmqYhFnu34drAYVXxLHyJKam65Lto7lL5xv01CfQ3LWppnUusKj9EMql_ILXv3D-rO234KDlT89/s844/stm32mp1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="437" data-original-width="844" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEXm-z0mrgqPLr1xHEHIHgmVgHQun9BHqSrU9hN4P3G5iYXogtYfCldJ-EakwWwp2kxrmqYhFnu34drAYVXxLHyJKam65Lto7lL5xv01CfQ3LWppnUusKj9EMql_ILXv3D-rO234KDlT89/s320/stm32mp1.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><font color="#b51200" size="2">참고: STM(ST Micro)은 익히 알고 있는 바와 같이 ARM Cortex-M microcontroller 업계의 선두 주자이다.</font></span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: left;">항상 느끼는 것이지만 새로운 보드를 접하는 것은 언제나 설레는 일이다. 😋 앞으로 이 보드를 이용해 몇차례에 걸쳐 다양한 주제를 다뤄 보도록 하겠다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font size="4">목차</font></b></div><div style="text-align: left;"><i><b>1. STM32MP157C Discovery Kit 소개</b></i></div><div style="text-align: left;"><i>2. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">Firmware(부팅 image) 설치하기</a></i></div><div style="text-align: left;"><i>3. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">부팅 image 생성하기 - Yocto project, Buildroot</a></i></div><div style="text-align: left;"><i>4. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">Qt application 개발 환경 설정 및 테스트해 보기</a></i></div><div style="text-align: left;"><i>5. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">Device Tree 분석 및 Device Driver 시험하기 - i2c 예제 소개</a></i></div><div style="text-align: left;"><i>6. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">온습도 센서 결과 확인용 Qt application 만들기</a></i></div><div style="text-align: left;"><i>7. <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">Cortex-M4 환경에서의 firmware 개발하기</a></i></div><div style="text-align: left;"><i>8. References</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><font color="#9e9e9e"><br /></font></div><div style="text-align: left;"><i><font color="#9e9e9e">내용이 길어질 수 있으니 이번 posting에서는 우선 STM32MP157C Discovery Kit 소개 부분만을 먼저 정리해 보기로 하겠다.</font></i></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#3367d6" size="6">1. STM32MP157C Discovery Kit 소개</font></b></div><div style="text-align: left;">STM32MP157C Discovery Kit(<font color="#f57c00">이하 DK2 보드라고 칭하겠음</font>)는 STM(ST Micro)의 주력 기술인 Cortex-M4 micom(ST firmware를 탑재)과 32bit Cortex-A7 microprocessor(Linux or Android 탑재)를 하나로 합쳐 놓은 아주 재밌는 보드이다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;">사실 이러한 형태의 보드는 일전에 아래 posting(<a href="https://www.udoo.org/">UDOO Neo</a> 보드)을 통해 한차례 소개한 바 있다. 따라서 두 보드 간의 차이를 분석해 보는 것도 재밌을 듯하다.</div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2017/02/how-to-build-android-sources-for-udoo.html">https://slowbootkernelhacks.blogspot.com/2017/02/how-to-build-android-sources-for-udoo.html</a></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#0b8043" size="4">a) DK2 보드 개요</font></b></div><div style="text-align: left;">우선 DK2 보드 외관은 아래와 같다. 크기는 (남자) 손바닥 보다는 작고, Raspberry Pi 보다는 좀 큰 느낌이다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_dd8MGiNOJMHl0qg7ZSdqwMeKZXMe0S9_wkx3lhZTaTbXq1ZeTKNqV7a8gL-qeHlegnF5hVFCSMr7DOj_MFpXUXRKcluOTXUEgrp-YCJ1-O6qFr_lfFBPF42RW8x6Dy7pVOm2z81dA5O3/s983/stm32mp1_top_bottom.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="983" height="140" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_dd8MGiNOJMHl0qg7ZSdqwMeKZXMe0S9_wkx3lhZTaTbXq1ZeTKNqV7a8gL-qeHlegnF5hVFCSMr7DOj_MFpXUXRKcluOTXUEgrp-YCJ1-O6qFr_lfFBPF42RW8x6Dy7pVOm2z81dA5O3/w400-h140/stm32mp1_top_bottom.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.1] <span style="text-align: left;">STM32MP157C-DK2 top & bottom view - LCD를 제거한 모습</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSfzev91d7Ld23gfofL1VCMW5msqQN-5yqT8x36H1c_nAa-xlQlaHd9XvPy9c7ERozvrw5nmp0cZ34xUC2_m0TAKvOieg0R1nRNU0BEAnhRtnbWMRnuNfrbhs_j0HIbZ-yxxnJYlCR3-Ew/s225/stm32mp157_dk2.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSfzev91d7Ld23gfofL1VCMW5msqQN-5yqT8x36H1c_nAa-xlQlaHd9XvPy9c7ERozvrw5nmp0cZ34xUC2_m0TAKvOieg0R1nRNU0BEAnhRtnbWMRnuNfrbhs_j0HIbZ-yxxnJYlCR3-Ew/d/stm32mp157_dk2.jpeg" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.2] LCD가 장착된 모습</div><div style="text-align: left;"><br /></div><div style="text-align: left;">다음으로 DK2 보드의 주요 특징(H/W 특징)과 CPU core의 block diagram을 연이어 정리해 보면 다음과 같다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><table border="1" bordercolor="#888" cellspacing="0" style="border-collapse: collapse; border-color: rgb(136, 136, 136); border-width: 1px;"><tbody><tr><td style="min-width: 60px;"><b>CPU</b>: Cortex-A7 Micro processor + Cortex-M4 Micro controller<br /><b>OS</b>: Linux(or Android) + ST code 기반의 firmware(or FreeRTOS 등 탑재 가능)<br /><b>주요 주변 장치</b>: 4인치 TFT LCD(MIPI DSI), HDMI, 1Gbps Ethernet, 802.11 b/g/n Wi-Fi, BLE 4.1<br />40 pin Raspberry Pi connector, Arduino Uno connector...<br /><b>PMIC:</b> STPMIC1A<br /><b>Power input</b>: 5V/3A<br />...</td></tr></tbody></table></div><div style="text-align: left;"><br /></div><div style="text-align: left;">====================================================================</div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4hogRnYqy9k08RqPgS8R6tvBKunLUFPunqtp0aLkiXF_XWjkxxyxoXU7MynmSte65gKJ1SQEbMaxjk5Gvi-rRDJ5Dq-webaNr2gvG7Nktx7j_NLLd_tIqs2JUAJlb05RGVGeoVzFBSDhH/s870/stm32mp1_feature.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="870" data-original-width="662" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4hogRnYqy9k08RqPgS8R6tvBKunLUFPunqtp0aLkiXF_XWjkxxyxoXU7MynmSte65gKJ1SQEbMaxjk5Gvi-rRDJ5Dq-webaNr2gvG7Nktx7j_NLLd_tIqs2JUAJlb05RGVGeoVzFBSDhH/w486-h640/stm32mp1_feature.png" width="486" /></a></div><div style="text-align: left;">====================================================================</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpvQaAZm4yhwilUJhHJIv-SiMOWEG1_xyFDiOSEe9wDgK_cMwRsRrQGCyRlNAfvXeC_WGVRlQT1uFlUHVVpgQeLI-bqcjNtX6qEZeaLmekw8vak7nT179LMLgH2vta8ijGjGkG3YIaCQ6b/s685/stm32mp157_block_diagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="685" data-original-width="475" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpvQaAZm4yhwilUJhHJIv-SiMOWEG1_xyFDiOSEe9wDgK_cMwRsRrQGCyRlNAfvXeC_WGVRlQT1uFlUHVVpgQeLI-bqcjNtX6qEZeaLmekw8vak7nT179LMLgH2vta8ijGjGkG3YIaCQ6b/w278-h400/stm32mp157_block_diagram.png" width="278" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.3] STM32MP157 Block diagram</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#0b8043" size="4">b) DK2 보드 상세 소개</font></b></div><div style="text-align: left;"><div style="text-align: left;">DK2 보드 전체의 block diagram을 그려보면 다음과 같다. 실제 DK2 보드에 대한 회로도(schematic)를 살펴보기 전에 block diagram을 훑어 보면 회로도를 이해하기가 좀 더 수월해 질 수 있다.</div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div style="text-align: left;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3X_mdflmpv_-FGDwuxMQCpvCuHwE6K5mhJ3vzwm1JjTX3o1C-S8cPSc6ZRGm6Y3tDGNyHkWZcBmia0lI5iMFiJSPpyN8j89JZ6H7-4LqvzTgdWP1Vn-vKpOXAvM_60tMtZccT6H6wpkpf/s848/stm32mp157x_block_diagram2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="842" data-original-width="848" height="637" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3X_mdflmpv_-FGDwuxMQCpvCuHwE6K5mhJ3vzwm1JjTX3o1C-S8cPSc6ZRGm6Y3tDGNyHkWZcBmia0lI5iMFiJSPpyN8j89JZ6H7-4LqvzTgdWP1Vn-vKpOXAvM_60tMtZccT6H6wpkpf/w640-h637/stm32mp157x_block_diagram2.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.4] STM32MP157 Block diagram(2)</div><div style="text-align: left;"><font color="#b51200" size="2">참고: 위의 그림을 보면 PMIC(STPMIC1), Touch panel, USB Type-C, Audio DAC, HDMI 등이 i2c를 사용하는 것을 알 수 있다.</font></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><div style="text-align: left;"><div style="text-align: left;"><u><짝퉁(?) 개발자의 보드 분석 절차></u></div><div style="text-align: left;"><font color="#f57c00"> 1) brochure or 보드의 개요를 설명하는 문서를 훑어 봄.</font></div><div style="text-align: left;"><font color="#f57c00"> 2) user manual을 꼼꼼히 읽어 봄.</font></div><div style="text-align: left;"><span style="color: #f57c00;"> -> 전체적인 보드 구성(block diagram)을 파악해 보고, 상호 어떻게 연결되어 있는지를 살펴 봄.</span></div><div style="text-align: left;"><font color="#f57c00"> -> 상호 연결이라 하면, CPU(or MPU)와 주변 장치의 pin 연결 관계를 말함.</font></div><div style="text-align: left;"><font color="#f57c00"> 3) 회로도를 훑어 봄.</font></div><div style="text-align: left;"><font color="#f57c00"> -> PMIC, USB power 부분</font></div><div style="text-align: left;"><font color="#f57c00"> -> RAM 연결 부분</font></div><div style="text-align: left;"><font color="#f57c00"> -> 나머지 주변 장치 연결 부분(LCD - MIPI DSI, HDMI, Audio, SD/MMC, Ethernet, Wi-Fi/BT, LED/Buttons, GPIO expansion 등)</font></div><div style="text-align: left;"><font color="#f57c00"> 4) 여기까지 한 후, 부팅이 가능한 상태라면 부팅해 보고, 그렇지 않다면 ... 보드를 살리는 작업 시작함. </font></div><div style="text-align: left;"><font color="#f57c00"> 5) 보드 => 회로도/block diagram => device tree => device driver 개발로 이어짐.</font></div></div><div style="text-align: left;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEqFca_qsyl85epkbnK1_IBPlOHH2WW_P1jxiVUC3EeRg0PEYljuyuwRmhygjixsEipao2dpkgz2h8V5GypQt3SRnJ9aTngoVrrxkxtpWPJYUmaDlqI0KkWCXu6fhvh9jwEDgOkMhszZy7/s873/dk2_schematic1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="745" data-original-width="873" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEqFca_qsyl85epkbnK1_IBPlOHH2WW_P1jxiVUC3EeRg0PEYljuyuwRmhygjixsEipao2dpkgz2h8V5GypQt3SRnJ9aTngoVrrxkxtpWPJYUmaDlqI0KkWCXu6fhvh9jwEDgOkMhszZy7/w400-h341/dk2_schematic1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.5] STM32MP157 Schematic(1)</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvusakUSFQ06lbRUVsCkp-8qXpt3DDUsTb_rY4bgjU_QpdJ_Ve2JySymWSajM6cbHPk7isjWF7KBM3H6dhuiS_bOUq0Dsb8IWP0Ig6vJtcBev7V7ssHvAnK95q0ZJhN6ng-d6DjDa6kYTZ/s1042/dk2_schematic2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="737" data-original-width="1042" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvusakUSFQ06lbRUVsCkp-8qXpt3DDUsTb_rY4bgjU_QpdJ_Ve2JySymWSajM6cbHPk7isjWF7KBM3H6dhuiS_bOUq0Dsb8IWP0Ig6vJtcBev7V7ssHvAnK95q0ZJhN6ng-d6DjDa6kYTZ/w400-h283/dk2_schematic2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.6] STM32MP157 Schematic(2)</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;">다음으로 아래 3개의 그림(그림 1.7 ~ 1.9)은 DK2 board를 구성하는 내용(요소)을 상세히 보여준다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQlahIakmbBs82mkR4-7W0C2nkUCTt1kQSEtgi9YJh58W7-HNeepzorBCiGFL8syh56ZlDBxhKYzfs3jmK0nXlYvgLpDg10OenYVZlb-QePIVQNnrRYBVLg0-P3AVF4DtCG-_vcY46h4l/s910/dk2_top_side.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="620" data-original-width="910" height="272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZQlahIakmbBs82mkR4-7W0C2nkUCTt1kQSEtgi9YJh58W7-HNeepzorBCiGFL8syh56ZlDBxhKYzfs3jmK0nXlYvgLpDg10OenYVZlb-QePIVQNnrRYBVLg0-P3AVF4DtCG-_vcY46h4l/w400-h272/dk2_top_side.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.7] <span style="text-align: left;">STM32MP157C-DK2 top view</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP55cBuYmbFbwR5M7ym5tNNhMxKKRrdLT2oobMdoDcq7pm5LLU3ATymjp7qYWa3vD-LKCUF6WVuaqIUVpQqbEyZo3GFXbuUPX7tJHvLMYa9aTy0RBRVQgpAkJQa2lh39IDcMMCnJ9vT4nk/s918/dk2_bottom_view.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="603" data-original-width="918" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjP55cBuYmbFbwR5M7ym5tNNhMxKKRrdLT2oobMdoDcq7pm5LLU3ATymjp7qYWa3vD-LKCUF6WVuaqIUVpQqbEyZo3GFXbuUPX7tJHvLMYa9aTy0RBRVQgpAkJQa2lh39IDcMMCnJ9vT4nk/w400-h263/dk2_bottom_view.png" width="400" /></a></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: center;">[그림 1.8] <span style="text-align: left;">STM32MP157C-DK2 bottom view</span></div><div style="text-align: left;"><br /></div></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiklMea73YzMl1A3C2baaKBe-Do0Xzl2hVvg_17l9O3JQdW68qBl-K_NfkLf6MklzOTZh7LZ1AXDaMT_AS-hWn6oPVxCJUgSI4lFpy3EfGHfK1VlyxJEQCluwK4yciC6_B8Pc8H8-vklDWG/s810/dk2_lcd.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="517" data-original-width="810" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiklMea73YzMl1A3C2baaKBe-Do0Xzl2hVvg_17l9O3JQdW68qBl-K_NfkLf6MklzOTZh7LZ1AXDaMT_AS-hWn6oPVxCJUgSI4lFpy3EfGHfK1VlyxJEQCluwK4yciC6_B8Pc8H8-vklDWG/s320/dk2_lcd.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.9] <span style="text-align: left;">STM32MP157C-DK2 MIPI DSI LCD 연결</span></div><div style="text-align: left;"><br /></div><div style="text-align: justify;">최신 (규모가 좀 커다란) embedded board를 구성하는 요소 중 중요한 부분을 차지하는 것 중의 하나는 단연 PMIC(Power Management IC)가 아닐까 싶다. 아래 그림 1.10 ~ 1.12는 DK2 보드에 장착되어 있는 STPMIC1 chip에 관한 내용을 소개하고 있다. STPMIC1은 CPU(STM32MP1)는 물론이고 주변 장치(RAM, USB, Wi-Fi, BT, Micro SD 등)의 power를 control하는 역할을 담당한다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMNFA7q7tiUNhefTrie8H-hY1pWRO7OqyaMxWAr4NX0qdZn8PxpTI7wCgSas_EIrzTty5yYgISTuauVcDK02EWEK-sm0LGwg8eNQcSIc_8k0ii5T7p2cIyRYyrK48n84UPX8Im_pOpQfsy/s220/stpmic1_chip.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="130" data-original-width="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMNFA7q7tiUNhefTrie8H-hY1pWRO7OqyaMxWAr4NX0qdZn8PxpTI7wCgSas_EIrzTty5yYgISTuauVcDK02EWEK-sm0LGwg8eNQcSIc_8k0ii5T7p2cIyRYyrK48n84UPX8Im_pOpQfsy/" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.10] <span style="text-align: left;">STPMIC1 PMIC chip</span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg48aXawf83DndrboPL1nx0_4DcmjROgLienQISYoLOUtG-AJhoppLrYKy0t4vj9KCLVdXjuTmfm1LMMA69CnfoQxW2ADFi0nZWpDqvTo9S8OJaf4-yDoO6JoLyfzj-y1czsmmP9G1olW3N/s1098/stpmic1_block_diagram.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="555" data-original-width="1098" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg48aXawf83DndrboPL1nx0_4DcmjROgLienQISYoLOUtG-AJhoppLrYKy0t4vj9KCLVdXjuTmfm1LMMA69CnfoQxW2ADFi0nZWpDqvTo9S8OJaf4-yDoO6JoLyfzj-y1czsmmP9G1olW3N/w400-h203/stpmic1_block_diagram.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.11] <span style="text-align: left;">STPMIC1 PMIC chip block diagram</span></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41-4QFwLOq55glonzh-rGoHZ5m2XMQ-A585PKoGxsTA06MpmjYzwB-RrQZp4mK8sMxbrMjIV27DSzq_v-OpyKumaIAaUBBYVKib8nv2tNYuP4sSP0LoIHkvgV58BHhpph9JHjmqo1sDEf/s1180/stpmic1_role.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="544" data-original-width="1180" height="296" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh41-4QFwLOq55glonzh-rGoHZ5m2XMQ-A585PKoGxsTA06MpmjYzwB-RrQZp4mK8sMxbrMjIV27DSzq_v-OpyKumaIAaUBBYVKib8nv2tNYuP4sSP0LoIHkvgV58BHhpph9JHjmqo1sDEf/w640-h296/stpmic1_role.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><span style="text-align: center;">[그림 1.12] </span><span style="text-align: left;">STPMIC1 PMIC chip의 역할</span></span></div><div style="text-align: left;"><br /></div><div style="text-align: justify;">다음으로 확인해 볼 사항은 DK2 보드의 gpio pinout과 더불어 전체((STM32MP1 SoC Ball) pinout(각 pin의 용도)에 관한 것이다. 지면 관계상 모든 pin의 용도를 기술할 수는 없지만, device driver 구현 시(특히 pinmux 설정 관련) pinout 내용을 제대로 알고 있는 것이 도움이 된다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyXkUziDoQz_j01iNBjd-yw9qLoqe-7CHsv538hwMNrln_0rqoOAEGnyeD6GkkNqtALEQCsWSxaep8dFA4hZIYzRvSdlxYF9tAI-KYc2ZGn4gqOcrHFngClj3BswbaU2jodpvUrcmngY3K/s878/dk2_gpio_pinout.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="493" data-original-width="878" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyXkUziDoQz_j01iNBjd-yw9qLoqe-7CHsv538hwMNrln_0rqoOAEGnyeD6GkkNqtALEQCsWSxaep8dFA4hZIYzRvSdlxYF9tAI-KYc2ZGn4gqOcrHFngClj3BswbaU2jodpvUrcmngY3K/s320/dk2_gpio_pinout.png" width="320" /></a></div><div style="text-align: center;"><b>...</b></div><div style="text-align: center;">[그림 1.13] DK2 보드 GPIO connector pinout</div><div style="text-align: center;"><br /></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4pIjptyTAOtbe-_KkRl1OFUvP4Ty1u2eUpbl1N7CwOPvtzPMMyk9Cv_qd1QmJNI6Zzgk4AgwWZIBQeAZXhKMCRQpB5clP-PryseuYzc55MeWK07_O6IXq9w7snYkbzpeHA09-Q9uuChyphenhyphenb/s874/dk2_io_assignment.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="691" data-original-width="874" height="316" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4pIjptyTAOtbe-_KkRl1OFUvP4Ty1u2eUpbl1N7CwOPvtzPMMyk9Cv_qd1QmJNI6Zzgk4AgwWZIBQeAZXhKMCRQpB5clP-PryseuYzc55MeWK07_O6IXq9w7snYkbzpeHA09-Q9uuChyphenhyphenb/w400-h316/dk2_io_assignment.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><b>...</b></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;">[그림 1.14] DK2 보드 pinmap(I/O assignment)</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#0b8043" size="4">c) DK2 보드 부팅하기</font></b></div><div style="text-align: justify;">DK2 보드에는 (가격적인 이유로) SPI Flash나 eMMC 등이 포함되어 있지 않다. 따라사 SD card(micro SD)를 통한 부팅(아래 그림 우측)만이 가능하며, flash memory에 writing하는 상황을 대비하여 USB booting 모드(아래 그림 좌측)를 제공하고 있다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijfAuh_yGnKWT_P9EykZWn3IN6iVe13v-bpitN3948Dzyy0pvqzcerp9DhIgioctJW3R3ZDhuZ_RTLvoTQNWFZOA0Ks6CJltpHgOv5Kb7k4y6GMsuTcbQRE11_aBFLllbj93PXKtsyw8mR/s679/dk2_bootmode_switch.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="303" data-original-width="679" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijfAuh_yGnKWT_P9EykZWn3IN6iVe13v-bpitN3948Dzyy0pvqzcerp9DhIgioctJW3R3ZDhuZ_RTLvoTQNWFZOA0Ks6CJltpHgOv5Kb7k4y6GMsuTcbQRE11_aBFLllbj93PXKtsyw8mR/w400-h179/dk2_bootmode_switch.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.15] <span style="text-align: left;">STM32MP157C-DK2 부팅 모드 switch</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;">이상으로 DK2 보드에 관한 내용을 대략적으로 살펴 보았으니, 이제 전원을 넣어 부팅을 시도해 보도록 하겠다. 불행하게도 (가격적인 이유로) DK2 보드 제품 패키지에는 power input(5V/3A) adapter(USB C type)가 포함되어 있지 않다(단, USB C to C cable은 포함되어 있음). 다행히 5V/2A 이기는 하지만 USB B to C adapter가 하나 있어, 이를 사용하여 부팅을 시도해 보기로 한다.</div><div style="text-align: left;"><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;"><font color="#b51200" size="2">참고: DK2 package에는 부팅용 image가 포함되어 있는 microSD가 장착되어 있다.</font></span></div><div class="separator" style="clear: both; text-align: center;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><b><font color="#7b1fa2">minicom 115200, 8N1, /dev/ttyACM0</font></b></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">부팅 시, u-boot에서 아래와 같이 warning message를 출력하기는 하지만, 이후 문제 없이 부팅이 이루어 진다.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEHuI-kNnVkaLUG52vg5oBX589erTg9DDaY4iCoQfKTZA0TjSaGFmI3PW6-AdkpvSqpMuUpMxuZmL45lhd5El-8NYKeaAoloxg6S_sKiNrX9IYjK26XaoxXcok38VEtKF5VZDeCtenhEio/s401/dk2_uboot_warning.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="90" data-original-width="401" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEHuI-kNnVkaLUG52vg5oBX589erTg9DDaY4iCoQfKTZA0TjSaGFmI3PW6-AdkpvSqpMuUpMxuZmL45lhd5El-8NYKeaAoloxg6S_sKiNrX9IYjK26XaoxXcok38VEtKF5VZDeCtenhEio/s320/dk2_uboot_warning.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.16] u-boot warning message 출력</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2m1wad1c4JDonCt4FSbubyveOCjJm_246aUDeM3o1aLz21zgakVRsrrC6yHenEURjFvVQDB7OkmZZ5c4PplxX8WDbcNfaSfQqWsYmWmxfJxQOztXrwKnN5IF9wB2HtMv76qQub35_9Kul/s784/dk2_boot1.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="750" data-original-width="784" height="383" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2m1wad1c4JDonCt4FSbubyveOCjJm_246aUDeM3o1aLz21zgakVRsrrC6yHenEURjFvVQDB7OkmZZ5c4PplxX8WDbcNfaSfQqWsYmWmxfJxQOztXrwKnN5IF9wB2HtMv76qQub35_9Kul/w400-h383/dk2_boot1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXE3jWABRYfE0hqGqVPfh7SRQxoejjvPqnaIh8v81od9tXHbCMQTQ6TV2Mn-hROxR-EHJzruvyajRn5gquQ15o5WMA_OCJqlBzXUq6MTrsVts7Up6bx2RKPfsLWAki3KMrFMl_DbVo6htk/s977/dk2_boot2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="782" data-original-width="977" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXE3jWABRYfE0hqGqVPfh7SRQxoejjvPqnaIh8v81od9tXHbCMQTQ6TV2Mn-hROxR-EHJzruvyajRn5gquQ15o5WMA_OCJqlBzXUq6MTrsVts7Up6bx2RKPfsLWAki3KMrFMl_DbVo6htk/w400-h320/dk2_boot2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.17] DK2 보드 부팅 모습</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div style="text-align: left;">와우, LCD에 예쁜 UI가 출력되었다. (당연히)touch도 먹힌다.</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwe3rtWI3Y4u-qJ1ZZhE2nKF-esvKtrksDOokoGEfl-Kkos7O_5nIhNC-z72tEMnRJjOuZTCcqGOAjjrtBXl7fW8pYXQw8mNqbUkqRfciLTbwYTgH5ScbE1m6NB9R70_fO5ZL9QuA3bswj/s4128/20200608_102904.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3096" data-original-width="4128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwe3rtWI3Y4u-qJ1ZZhE2nKF-esvKtrksDOokoGEfl-Kkos7O_5nIhNC-z72tEMnRJjOuZTCcqGOAjjrtBXl7fW8pYXQw8mNqbUkqRfciLTbwYTgH5ScbE1m6NB9R70_fO5ZL9QuA3bswj/s320/20200608_102904.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 1.18] 보드 설치 모습</div><div style="text-align: left;"><target board></div><div style="text-align: left;"># /usr/bin/python3 /usr/local/demo/demo_launcher.py</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div style="text-align: left;"><font color="#b51200" size="2">참고: 위의 UI는 Qt로 만든 것이 아니라 python3로 구현(GTK 기반)한 것이다.</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#3367d6" size="6">2. Firmware(부팅 image) 설치하기</font></b></div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRnFjrSjb3U0C_do9SHKs0Hi5sb30eYwGPw-Tpz6kNywhyphenhyphenv-EXqGKPcedq0dvF8NE2UVBStbWjyxETtIQafyG0G9IbO8Q9y3SYyjDlIEQvPmDp6M4v1c0b7_SPPaaJh7nZfKWW44fthQ-q/s697/dk2_stmp32mp1_sw.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="498" data-original-width="697" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRnFjrSjb3U0C_do9SHKs0Hi5sb30eYwGPw-Tpz6kNywhyphenhyphenv-EXqGKPcedq0dvF8NE2UVBStbWjyxETtIQafyG0G9IbO8Q9y3SYyjDlIEQvPmDp6M4v1c0b7_SPPaaJh7nZfKWW44fthQ-q/w400-h286/dk2_stmp32mp1_sw.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] STM32MP1 S/W Architecture</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;">[1] <a href="https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Let%27s_start/Unpack_the_STM32MP157C-DK2_board">https://wiki.st.com/stm32mpu/wiki/Getting_started/STM32MP1_boards/STM32MP157C-DK2/Let%27s_start/Unpack_the_STM32MP157C-DK2_board</a></div></div><div style="text-align: left;"><i> => prebuilt image 사용 방법 소개</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;">[2] <a href="https://wiki.st.com/stm32mpu/wiki/STM32MP1_Developer_Package">https://wiki.st.com/stm32mpu/wiki/STM32MP1_Developer_Package</a></div><div style="text-align: left;"><i> => kernel/bootloader source 사용 방법 소개</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;">[3] <a href="https://wiki.st.com/stm32mpu/wiki/STM32MP1_Distribution_Package">https://wiki.st.com/stm32mpu/wiki/STM32MP1_Distribution_Package</a></div><div style="text-align: left;"> <i> => OpenEmbedded(Yocto Project) 기반</i></div><div style="text-align: left;"><br /></div><div style="text-align: left;">[4] <a href="https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/" style="text-align: center;">https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-basic-system/</a></div><div style="text-align: left;"> => buildroot 이용하는 방법(by Bootlin)</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#f57c00">To be continued...</font></b></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><b><font color="#3367d6" size="6">8. References</font></b></div><div style="text-align: left;">[1] <a href="https://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html">https://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html</a></div><div style="text-align: left;"> <i> => DK2 board introduction pages</i></div><div style="text-align: left;">[2] <a href="https://www.st.com/resource/en/data_brief/stm32mp157c-dk2.pdf" style="text-align: center;">https://www.st.com/resource/en/data_brief/stm32mp157c-dk2.pdf</a></div><div style="text-align: left;"> <i> => Data brief document</i></div><div style="text-align: left;">[3] <a href="https://www.st.com/resource/en/user_manual/dm00591354-discovery-kits-with-stm32mp157-mpus-stmicroelectronics.pdf">https://www.st.com/resource/en/user_manual/dm00591354-discovery-kits-with-stm32mp157-mpus-stmicroelectronics.pdf</a></div><div style="text-align: left;"> <i> => User manual</i></div><div style="text-align: left;">[4] <a href="https://www.st.com/content/ccc/resource/technical/layouts_and_diagrams/schematic_pack/group0/36/8e/ea/7a/ca/ca/4b/e4/mb1272-dk2-c01_schematic/files/MB1272-DK2-C01_Schematic.pdf/jcr:content/translations/en.MB1272-DK2-C01_Schematic.pdf" style="text-align: center;">https://www.st.com/content/ccc/resource/technical/layouts_and_diagrams/schematic_pack/group0/36/8e/ea/7a/ca/ca/4b/e4/mb1272-dk2-c01_schematic/files/MB1272-DK2-C01_Schematic.pdf/jcr:content/translations/en.MB1272-DK2-C01_Schematic.pdf</a></div><div style="text-align: left;"><i> => DK2 board schematic</i></div><div style="text-align: left;">[5] <a href="https://www.st.com/resource/en/datasheet/stpmic1.pdf" style="text-align: center;">https://www.st.com/resource/en/datasheet/stpmic1.pdf</a></div><div style="text-align: left;"><i> => PMIC introduction pages</i></div><div style="text-align: left;">[6] <a href="https://www.st.com/resource/en/data_brief/stpmic1.pdf">https://www.st.com/resource/en/data_brief/stpmic1.pdf</a></div><div style="text-align: left;"><i> => PMIC data brief(data sheet)</i></div><div style="text-align: left;">[7] <a href="https://www.st.com/content/ccc/resource/sales_and_marketing/presentation/product_presentation/group0/f1/ae/a7/b2/de/1f/4d/da/STPMIC1_product_overview/files/Power_Management_STPMIC1_product_overview.pdf/jcr:content/translations/en.Power_Management_STPMIC1_product_overview.pdf">https://www.st.com/content/ccc/resource/sales_and_marketing/presentation/product_presentation/group0/f1/ae/a7/b2/de/1f/4d/da/STPMIC1_product_overview/files/Power_Management_STPMIC1_product_overview.pdf/jcr:content/translations/en.Power_Management_STPMIC1_product_overview.pdf</a></div><div style="text-align: left;"><i> => PMIC overview document</i></div><div style="text-align: left;">[8] <a href="https://wiki.st.com/stm32mpu/wiki/STM32MP15_resources#Reference_manuals">https://wiki.st.com/stm32mpu/wiki/STM32MP15_resources#Reference_manuals</a></div><div style="text-align: left;"> <i> => 다양한 manual 문서 </i></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div><br style="text-align: left;" /></div></div><div><br /></div></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-3884389155551681112020-05-29T14:17:00.003+09:002020-07-16T13:52:23.877+09:00Linux Driver Development for Embedded Processors - 에피소드 1(보이지 않는 Board의 위협^^)이번 posting 부터는 지난 1월에 공지했던 <b><font color="#0b8043">"Linux Driver Development for Embedded Processors(for short, LDD4EP)"</font></b> 라는 주제에 대한 글을 연재해 보고자 한다. <font color="#9e9e9e">(매우 유감스럽게도) 당초 예상 보다 좀 늦어졌다^^.</font><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHXQ7311hmGeIq0s-OKG89lqF_JULnq91UY-QTc33Dwhh6A5fLLSkM3wrsoYCUUFOxlYzUvWep0YD1AQljowiJmZq0M7CMSwCRJ5RKjUkYd9d1cIpfGuMqwW1-lkG_8c5BjdhBXdoRVinl/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="250" data-original-width="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHXQ7311hmGeIq0s-OKG89lqF_JULnq91UY-QTc33Dwhh6A5fLLSkM3wrsoYCUUFOxlYzUvWep0YD1AQljowiJmZq0M7CMSwCRJ5RKjUkYd9d1cIpfGuMqwW1-lkG_8c5BjdhBXdoRVinl/d/ldd4ep2.jpeg" /></a> <img border="0" data-original-height="206" data-original-width="245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjabS22tMrqgvGmkc1RiNMaimZnVfV_am1PRQV7B0PgWVFCwuWOh6KqsVWqFqD4W31yeKsRDuPybliH88z5Ipx-A_J_pRusTOz8RXSbfmYZeJtHJAhbPANouallYnckDd6MzoEzfPpxZzTU/" style="text-align: left;" /></div><div style="text-align: center;">LDD4EP2 book & Atmel SAMA5D3 Xplained 보드</div></div><div><div style="text-align: center;"><i><b><br /></b></i></div><div style="text-align: center;"><span style="color: #f57c00;">(에피소드 1 - 부제) "Atmel SAMA5D3 Xplained 보드의 기본 환경 설정과 LDD4EP2 book의 예제 build해 보기"</span></div><div style="text-align: center;"><span style="text-align: left;"><br /></span></div><div style="text-align: justify;"><br /></div><div style="text-align: center;"><b style="font-style: italic;">LDD4EP 3부작 시리즈<font color="#9e9e9e">(Director: Slowboot) </font>👍🏼</b></div><div style="text-align: center;"><i><b><font color="#7b1fa2">에피소드 1(보이지 않는 Board의 위협) => 에피소드 2(Device Tree의 습격) => 에피소드 3(Device Driver의 복수)</font></b></i></div><div><i><b><font color="#7b1fa2"><br /></font></b></i></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEichOn1UzrWGhEyqDwgSxM8i7bUkbjijHv-D3pKJsDIhVuKd7QwSqH0uEtWCHL7cfbtuZJ82pON8-z9biC0e6AviehNMThGv28VLHFUWeJHhkFg_XX1B6WMiy19uLFJZmdJDF0MFxR5TIdY/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="163" data-original-width="310" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEichOn1UzrWGhEyqDwgSxM8i7bUkbjijHv-D3pKJsDIhVuKd7QwSqH0uEtWCHL7cfbtuZJ82pON8-z9biC0e6AviehNMThGv28VLHFUWeJHhkFg_XX1B6WMiy19uLFJZmdJDF0MFxR5TIdY/w200-h105/jedi_sword2.jpeg" width="200" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><div><br /></div><div><b><font color="#3367d6" size="4"><u>Episode I. 보이지 않는 Board의 위협</u></font></b></div><div><b><font size="4">목차</font></b></div><div><b>1. 머릿말</b></div><div><b>2. Atmel SAMA5D3 Xplained Reloaded</b></div><div><i> - Prebuilt yocto image 설치(to NAND flash)</i></div><div><i> - FIT 소개</i></div><div><i> - UBI/UBIFS 소개</i></div><div><b>3. OpenWrt build 및 image 설치</b></div><div><i> - Build 방법 소개</i></div><div><i> - NAND flash image 설치 방법 소개</i></div><div><b>4. LDD4EP2 book 예제 build해 보기</b></div><div> <i> - 하나 하나 분석해 보는 것은 두번째 에피소드에서 ...</i></div><div><b>5. References</b></div><div>============</div><div><br /></div><div><b><font color="#3367d6" size="6">1. 머릿말</font></b></div><div><div>Embedded 제품 개발 회사에서는 대략 아래와 같은 일들을 진행한단다(?). 물론 실제 목표하는 제품이 뭐냐(예: car blackbox, car navigation, l2/l3 switch, smart phone, settop box ...)에 따라서 좀 더 심오한 일들이 진행되기도 하지만 말이다.</div><div><br /></div><div>a) 보드 설계(H/W) 및 보드 bring-up(S/W) 관련 일</div><div><i> - 보드 & Embedded processor에 대한 이해 필요</i></div><div><i> - board bring-up: bootloader(u-boot), kernel, rootfs(특히, UBI/UBIFS, SquashFS) 초기 작업 필요</i></div><div>b) <b><font color="#f57c00">build system에 대한 이해 및 관련 작업</font></b></div><div><i> - yocto project, openwrt, android, buildroot, armbian ...</i></div><div>c) <b><font color="#f57c00">신규 device driver 개발 및 기존 코드 수정</font></b></div><div><i> - device, device tree, device drivers(특히 platform device driver)에 대한 이해 필요</i></div><div><i> - Pin muxing, GPIO, i2c, spi, uart, usb 등</i></div><div>d) rootfs를 구성하는 각종 system s/w 이해 & porting</div><div><i> - </i><i>특정 s/w 추가 or 수정, 직접 개발 등.</i></div><div><i> - android 등의 경우는 framework에 대한 이해 필요</i></div><div>e) UI</div><div> <i> - WebUI, Qt, Android app...</i></div></div><div><br /></div><div>소위 BSP 혹은 kernel/device driver 개발자가 해야 하는 일이, 단순히 특정 device driver 만을 개발하는 것은 아니며, 위에 언급한 것과 같이 board bring-up에 관련된 일부터 시작해서 build system(yocto, openwrt 등) handling, rootfs(squashfs, ubi/ubifs) 제어 및 각종 system s/w(dnsmasq, iptables, sshd, lighttpd, ....) 안정화까지의 영역을 총 망라하는 것이라고 봐야 할 것이다.</div><div><br /></div><div><font color="#0b8043">편의 상, 이번 posting과 이어지는 posting에서는 주로 b와 (특히) c 항목에 해당하는 내용을 중점적으로 다뤄 볼 생각이다.</font></div><div><br /></div><div>== == ==</div><div><div>이번 posting의 main text인 LDD4EP2 book에서는 아래 3가지 보드를 기준으로 device tree 및 device driver 예제를 소개하고 있다.</div><div><br /></div><div><i><b><font color="#7b1fa2">- NXP i.MX 7Dual Application Processor MCIMX7SABRE 보드</font></b></i></div><div><i><b><font color="#7b1fa2">- Microchip SAMA5D2 Xplained Ultra 보드</font></b></i></div><div><i><b><font color="#7b1fa2">- Raspberry Pi 3 Model B</font></b></i></div><div><br /></div><div style="text-align: justify;">따라서 이 중 하나의 보드에서 device tree & device driver 예제를 실습해 보는 것이 신상(?)에 이로울 듯 하여, 하나를 구매할까도 생각해 보았으나, 사정상 (3년 전에 사용하던) Atmel SAMA5D3 Xplained board를 다시 사용하기로 결심하였다. 정말 다행인 것은 Linux4SAM community에서는 예전 보드에 대해서도 최신 BSP(Board Support Package) 지원을 매우 잘 해주고 있어, 요즘 유행(?)에 맞는 device tree & device driver study에 전혀 문제가 없을 듯 보인다. </div></div><div><br /></div><div><br /></div><div><b><font color="#3367d6" size="6">2. Atmel SAMA5D3 Xplained Reloaded</font></b></div><div><b><font size="4">2.1 At91Bootstrap loader, u-boot bootloader, kernel 등 build해 보기</font></b></div><div>이와 관련해서는 아래 page에 자세히 소개되어 있으니, 여기서는 별도로 정리하지 않기로 하겠다.</div><div style="text-align: center;"><br /></div><div style="text-align: center;"><a href="https://www.linux4sam.org/bin/view/Linux4SAM/Sama5d3XplainedMainPage">https://www.linux4sam.org/bin/view/Linux4SAM/Sama5d3XplainedMainPage</a></div><div><br /></div><div>다만, u-boot bootloader의 코드 흐름(시작 -> linux loading 까지) 정도 만이라도 간단히 살펴보고 넘어가기로 하겠다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgROrpSFj-ld5Nj3dAn7GuLfsXLys4d3aQEXaO3cCP3Z6tIii7PGvfRajYNpK1NXM9TeojXSXpuJ4hgEGlp8VW_ggtKw7qL5JrYLt83FWdnFYOG_FybD-kO3DtYk07s3H_eU1qq_hB6Eenj/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="581" data-original-width="280" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgROrpSFj-ld5Nj3dAn7GuLfsXLys4d3aQEXaO3cCP3Z6tIii7PGvfRajYNpK1NXM9TeojXSXpuJ4hgEGlp8VW_ggtKw7qL5JrYLt83FWdnFYOG_FybD-kO3DtYk07s3H_eU1qq_hB6Eenj/s320/at91_bootflow.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.1] SAMA5D3 Booting Flow</div><div><span><br /></span></div><div><span id="docs-internal-guid-c707dce1-7fff-9f3e-bdb6-a6eef2190a3c"><span style="font-family: "malgun gothic"; font-size: large; font-weight: 700; white-space: pre-wrap;"><u-boot 주요 코드 검색></span><br /><div align="left" dir="ltr" style="margin-left: -5.4pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="615"></col></colgroup><tbody><tr style="height: 0pt;"><td style="border-color: rgb(0, 0, 0); border-style: solid; border-width: 0.5pt; overflow-wrap: break-word; overflow: hidden; padding: 0pt 5.4pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "malgun gothic"; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 430px; overflow: hidden; width: 398px;"><img alt="uboot_codeflow0.png" height="430" src="https://lh3.googleusercontent.com/OPAmQTPYi3j59YrQWzz3ajZx_MumTaSxfq84auauJfq-iKGSeq5vVG5Eqj41MHEAF2F-r7rLf-OW_xw0Rxbx-2mqLovFTqQMrVYCDQybikCUwbxYFGceTRV-gP89b2hvofXRNq8" style="margin-left: 0px; margin-top: 0px;" width="398" /></span></span></p></td></tr></tbody></table></div><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><br /></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><span style="font-family: "malgun gothic"; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><font size="4"><br /></font></span></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: left;"><span style="font-family: "malgun gothic"; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: large;"><u-boot 코드 흐름 1></span></span></p><div align="left" dir="ltr" style="margin-left: -5.4pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="616"></col></colgroup><tbody><tr style="height: 0pt;"><td style="border-color: rgb(0, 0, 0); border-style: solid; border-width: 0.5pt; overflow-wrap: break-word; overflow: hidden; padding: 0pt 5.4pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "malgun gothic"; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 418px; overflow: hidden; width: 602px;"><img alt="uboot_codeflow1.png" height="418" src="https://lh4.googleusercontent.com/FblqTKsQq1Ihnl643XJDAsK20U3EieOOvgwlEB3gRuMhiLix2tsAfobofq7NU6qzLbUVJks0TWhReJmulBw8rl3ypf-dJUZJwJiM-Y1_4_wa6b0bk-xC_3GVQm2WK0vFbv_ZSHY" style="margin-left: 0px; margin-top: 0px;" width="602" /></span></span></p></td></tr></tbody></table></div><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><br /></p><span style="font-family: "malgun gothic"; font-size: large; font-weight: 700; text-align: center; white-space: pre-wrap;"><u-boot 코드 흐름 2></span><br /><div align="left" dir="ltr" style="margin-left: -5.4pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="615"></col></colgroup><tbody><tr style="height: 0pt;"><td style="border-color: rgb(0, 0, 0); border-style: solid; border-width: 0.5pt; overflow-wrap: break-word; overflow: hidden; padding: 0pt 5.4pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "malgun gothic"; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 403px; overflow: hidden; width: 491px;"><img alt="uboot_codeflow2.png" height="403" src="https://lh6.googleusercontent.com/hFQWNCsDUB5VgcCg48ftpKAKhIkwsa6aIeGQqnY0QprW0_QLEa-6fiiFflevXSW90499TH7KTmeAd_zbpb2NZG5U9JAkcNyri4Tc640wcQLlHWRWdKV--ZfcvGfVLwiFsOAQJMw" style="margin-left: 0px; margin-top: 0px;" width="491" /></span></span></p></td></tr></tbody></table></div><div align="left" dir="ltr" style="margin-left: -5.4pt;"><br /></div></span></div><div>u-boot 관련하여 보다 구체적인 내용을 알고 싶다면 아래 README 파일을 꼼꼼히 읽어보기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://gitlab.denx.de/u-boot/u-boot/raw/master/README">https://gitlab.denx.de/u-boot/u-boot/raw/master/README</a></div><div><br /></div><div><font color="#b51200" size="2">[참고] u-boot은 보드 bring-up 과정에서 매우 중요한 역할을 차지하는 만큼, 추후 기회가 된다면 별도의 주제로 정리해 볼 생각이다.</font></div><div><br /></div><div><div><b><font size="4">2.2 Device Tree 분석</font></b></div><div><div dir="ltr" style="margin-left: -5.4pt; text-align: left;"> SAMA5D3 Xplained board의 device tree(및 device tree 기초)와 관련해서는 이전 posting을 참조하기 바란다.</div><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><br /></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2016/11/atmel-sama5d3-xplained-board-i2c-device.html">https://slowbootkernelhacks.blogspot.com/2016/11/atmel-sama5d3-xplained-board-i2c-device.html</a></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><br /></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html">https://slowbootkernelhacks.blogspot.com/2014/03/beaglebone-linux-kernel310x-programming.html</a></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><span style="text-align: left;"><br /></span></p><p dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt; text-align: justify;"><span style="text-align: left;">실제로 device tree 설정과 관련해서는 다음번 posting에서 좀 더 구체적으로 다시 살펴 볼 것이다.</span></p></div><div style="text-align: center;"><br /></div></div><div><br /></div><div><b><font size="4">2.3 NAND flash에 prebuilt image 설치하기</font></b></div><div>다음으로 할 일은 yocto project를 통해 사전에 생성해 둔 prebuilt image 파일을 가지고 nand 부팅을 시도해 보는 것이다. 이는 flash memory 파티션 구조(map), FIT, UBI/UBIFS 등을 파악하는 것과도 연관이 있다.</div><div style="text-align: center;"><br /></div><div style="text-align: center;"><a href="https://files.linux4sam.org/pub/demo/linux4sam_6.2/linux4sam-poky-sama5d3_xplained-headless-6.2.zip" style="border: none; color: #999966; font-family: arial, verdana, sans-serif; font-size: 14px; text-decoration-line: none;" target="_blank">linux4sam-poky-sama5d3_xplained-headless-6.2.zip</a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0AaMOk5sNxV7rcGzk2BcwBLL_5NUC2hVRnpMa4CGf8_70rwsr6UW9MdsDy5md3hkNfM2L9AzwwsTvu8y-Qzli_u-tmkgfy9ui64pVNVr_nkVFfq4AgQOmaBuikfWlHhAoVU8PfRu2dv7I/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="148" data-original-width="950" height="63" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0AaMOk5sNxV7rcGzk2BcwBLL_5NUC2hVRnpMa4CGf8_70rwsr6UW9MdsDy5md3hkNfM2L9AzwwsTvu8y-Qzli_u-tmkgfy9ui64pVNVr_nkVFfq4AgQOmaBuikfWlHhAoVU8PfRu2dv7I/w400-h63/sama5d3_nand_image.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.2] Demo용 nand flash image 파일</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">$ <b>unzip linux4sam-poky-sama5d3_xplained-headless-6.2.zip</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg__CGDR6mXBO0tsv-m6G4T7aTBVWdTNPFcGIDPf-7nujsuhR9o8gXWT9WI5bWvxP8np7uRyUs2qXEqWJxZs7bM7FbKniZJ4PeMLK5EJqlZ5iGgH3QWQBKhWvn4MNlLOD7PuPzrzt10DR5y/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="881" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg__CGDR6mXBO0tsv-m6G4T7aTBVWdTNPFcGIDPf-7nujsuhR9o8gXWT9WI5bWvxP8np7uRyUs2qXEqWJxZs7bM7FbKniZJ4PeMLK5EJqlZ5iGgH3QWQBKhWvn4MNlLOD7PuPzrzt10DR5y/w640-h224/linux4sam_poky_headless.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.3] NAND flash 용 image 파일</div><div><br /></div><div><br /></div><div>NAND flash에 image를 writing(program)하기 위해서는 아래 그림 상단의 <b>JP9: NAND chip select jumper</b>를 제거(open)한 상태에서 그림 하단의 <b>reset 버튼(BP2: Reset button)</b>을 눌러 주어, <u>RomBoot(SROM에 설치되어 있는 primary bootloader) 상태로 진입</u>해 주어야 한다. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiuvL9a_fME0QRedaz432C8DUsuysAOYNruCami4sgyaZrfltp07u59TGTXOkHqqKb9uYVhWLpwRLf05cY9BWUPwBdnqam9ytQcybsV0v6QwFspA7u27SuxcgS-7mFaBPrtjGFYY-cPped/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="523" data-original-width="956" height="350" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiuvL9a_fME0QRedaz432C8DUsuysAOYNruCami4sgyaZrfltp07u59TGTXOkHqqKb9uYVhWLpwRLf05cY9BWUPwBdnqam9ytQcybsV0v6QwFspA7u27SuxcgS-7mFaBPrtjGFYY-cPped/w640-h350/sama5d3_xplained.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.4] SAMA5D3 Xplained 보드</div><div><br /></div><div>Console(minicom: 115200, 8N1)에 "RomBoot" 메세지가 출력되면, 정상적으로 RomBoot 상태로 진입한 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjByq6KK6f2Y1cR84kr-t4bXinjqLWVlVN0hYpxLJ56XOZbwbVBhzl0wQ4KI8BeeldLNGe_PoARL3GyoSzLJbAUdgZIbhw-8J12NUocQofdQ_pEh_wZaiBrm3y05sssCvpRwrFYc1PyX4Mn/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="132" data-original-width="726" height="73" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjByq6KK6f2Y1cR84kr-t4bXinjqLWVlVN0hYpxLJ56XOZbwbVBhzl0wQ4KI8BeeldLNGe_PoARL3GyoSzLJbAUdgZIbhw-8J12NUocQofdQ_pEh_wZaiBrm3y05sssCvpRwrFYc1PyX4Mn/w400-h73/romboot.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.5] RomBoot mode 진입 모습 - minicom console에서 확인</div><div><br /></div><div>RomBoot 상태에서 NAND flash에 image writing을 하기 위해서는 다시 JP9: NAND chip select jumper를 꽂아(close) 주어야 한다.</div><div><br /></div><div><b><font color="#9c27b0"><Firmware Writing 동작 원리></font></b></div><div>[RomBoot] <============== USB <============== NAND flash용 image</div><div> ||</div><div> V</div><div>NAND writing</div><div><br /></div><div><font color="#b51200" size="2">참고: 요즘 나오는 보드는 대개 이런식의 firmware writing 방법을 지원하고 있다.</font></div><div><br /></div><div><div>$ <b>sudo ./demo_linux_nandflash.sh</b> </div><div><i><font color="#f57c00">=> sam-ba -x demo_linux_nandflash_usb.qml 2>&1 | tee logfile.log</font></i></div><div><br /></div><div><font color="#0b8043">참고: Atmel에서는 sam-ba라는 firmware writing tool을 제공하고 있는데, 위의 shell script는 이를 이용하여 자동으로 NAND flash에 firmware image writing 을 수행해 주게 된다.</font></div><div><font size="2">...</font></div><div><font size="2">...</font></div><div><font size="2">...</font></div><div><font size="2">Wrote 18432 bytes at address 0x09c5b800 (99.83%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c60000 (99.85%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c65800 (99.86%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c6b000 (99.88%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c70800 (99.89%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c76000 (99.90%)</font></div><div><font size="2">Wrote 18432 bytes at address 0x09c7b800 (99.92%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c80000 (99.93%)</font></div><div><font size="2">Wrote 22528 bytes at address 0x09c85800 (99.94%)</font></div><div><font size="2">Wrote 4096 bytes at address 0x09c8b000 (99.95%)</font></div><div><font size="2">Skipped 40 empty page(s) at address 0x09c8c000</font></div><div><font size="2">-I- === Done. ===</font></div><div><font size="2">Connection closed.</font></div></div><div><br /></div><div>정상적으로 writing이 진행된 후, u-boot config를 확인해 보면 다음과 같다.</div><div><br /></div><div><b><target board u-boot 설정 내용></b></div><div><div>=> print</div><div>baudrate=115200</div><div>bootargs=console=ttyS0,115200 mtdparts=<font color="#f57c00">atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),6656k(itb)ro,-(rootfs) rootfstype=ubifs ubi.mtd=5 root=ubi0:rootfs rw</font></div><div>bootcmd=<font color="#0b8043">nand read 0x24000000 0x00180000 0x406730; bootm 0x24000000#kernel_dtb</font></div><div>bootdelay=1</div><div>fdtcontroladdr=2fb30b68</div><div>stderr=serial@ffffee00</div><div>stdin=serial@ffffee00</div><div>stdout=serial@ffffee00</div><div><br /></div><div>Environment size: 381/131067 bytes</div></div><div><br /></div><div>위의 demo script를 돌리고 나면, 아래와 같은 NAND flash 파티션 map이 그려지게 된다. 이 중 눈여겨 볼만한 부분은 dtb와 kernel image가 FIT(Flattened Image Tree) image 형태로 묶여 있다는 점과 rootfs로 UBIFS 파일 시스템이 사용되었다는 점일 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7WEviD4VmJlRB3AVaCe0cD_wqIxVAu3JVEJu3CCm7LUkQxsqZmInpaZn6ZbsGvL3th6OqzFP829wRGT553wrm2eyCYhPCFJJEQjrzwuwSZukuuCnSBTN63DKx1ekODIPjxINXkPBlY6eN/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="481" data-original-width="309" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7WEviD4VmJlRB3AVaCe0cD_wqIxVAu3JVEJu3CCm7LUkQxsqZmInpaZn6ZbsGvL3th6OqzFP829wRGT553wrm2eyCYhPCFJJEQjrzwuwSZukuuCnSBTN63DKx1ekODIPjxINXkPBlY6eN/s320/at91_nand_flash_map.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.6] NAND flash partition map</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><font color="#b51200" size="2">참고: 요즘은 rootfs로 여러가지 장점이 있는 UBIFS를 사용하는 추세다. 즉, JFFS2나 YAFFS2 등은 잘 사용하지 않는다.</font></div><div><br /></div><div><b><font color="#4285f4"><여기서 잠깐 !></font></b></div><div>SAMA5D2 Xplained board의 flash memory는 요즘 많이 사용하는 SPI flash(serial flash)와 eMMC로 구성되어 있음을 알 수 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYxZBPsstJPuwJ6vg5cnAdrFeRPQbfwqVmJOSbbReK-73_hCjrypeHQ-zYLn07PI-BY8YQL8zr9wEc575MHeTn6k6uI-KPhvAXM4Ejzsx2yZqNgmIPMZFD2QgVBm22SkgCsxtkBSvi_C4k/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="620" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYxZBPsstJPuwJ6vg5cnAdrFeRPQbfwqVmJOSbbReK-73_hCjrypeHQ-zYLn07PI-BY8YQL8zr9wEc575MHeTn6k6uI-KPhvAXM4Ejzsx2yZqNgmIPMZFD2QgVBm22SkgCsxtkBSvi_C4k/s320/sama5d2_flash.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.7] SAMA5D2 Xplained board의 flash map</div><div>==========</div><div><br /></div><div><font size="4"><b>2.4 FIT(Flattened Image Trees) 소개</b></font></div><div>[그림 2.3]에서 보면, 확장자가 itb인 이상한(?) 파일이 하나 보인다.</div><div style="text-align: center;"><b><font color="#0b8043">sama5d3_xplained.itb</font></b></div><div><br /></div><div>도대체 이 파일의 의미 & 용도가 무엇일까 ? </div><div><br /></div><div>Board bring-up을 하다 보면, dtb(device tree blob)를 별도로 관리하기 보다는 kernel image 뒤에 붙여서 하나의 이미지로 만들고 싶다거나 dtb를 용도에 맞게 여러 개 만들어 두고, 부팅 시에 원하는 것으로 선택(<font color="#b51200">실제로 # 으로 선택함</font>)해 사용하고 싶은 경우가 있다. 아니면, android boot.img style로 (recovery 목적으로) initial ramdisk image를 kernel image에 붙여야 하는 상황도 생각해 볼 수 있다. </div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeJOKYh9pX5Sa_hnVbKeGuSzRg9fyBvyr5XEZf0-n4VF_BxezzptC4lN2SoQCQyqRGj1vs0wARIXfVz6nTTsWBYaYWjvg_kSnxLBGct7DrG7SnFaylAW1-l6bdbJfZDC2dQvSJfrWAbhop/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="624" data-original-width="526" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgeJOKYh9pX5Sa_hnVbKeGuSzRg9fyBvyr5XEZf0-n4VF_BxezzptC4lN2SoQCQyqRGj1vs0wARIXfVz6nTTsWBYaYWjvg_kSnxLBGct7DrG7SnFaylAW1-l6bdbJfZDC2dQvSJfrWAbhop/s320/multi_component_image.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.8] kernel, ramdisk, dtb를 하나의 이미지로 만들기</div><div><br /></div><div>FDT는 Flattened Device Tree(device driver와 맞물려 있음)를 뜻하며, FIT(Flattened Image Tree)는 kernel, dtb, ramdisk fs(initrd)등을 여러개 묶을 수 있는 device tree 기반의 이미지 생성 방식으로 보면 될 것 같다. 아래에 FIT source(its file) 예제 하나를 소개해 보았다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL6BMxTVU3QZ2VxB8LRgoPfiyiv4-DmhpeXT7MSLyiaZ2oPmIO4ZtE3Iv6eR0v1YAlUilZ8Zaw8wRxs_S65oZmaZQNVyR4UGvzGkG2exl05GzHstbPmn-hX6LxvP5b9mp3Bf0HXbxdKvPA/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="563" data-original-width="659" height="341" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiL6BMxTVU3QZ2VxB8LRgoPfiyiv4-DmhpeXT7MSLyiaZ2oPmIO4ZtE3Iv6eR0v1YAlUilZ8Zaw8wRxs_S65oZmaZQNVyR4UGvzGkG2exl05GzHstbPmn-hX6LxvP5b9mp3Bf0HXbxdKvPA/w400-h341/fit1.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSz2otohIsODUlcyce8a-iU_z2LI0iG9TZkgq6v7vjV7s26qBNfVAVsON-iiwf3REdxDL-utDCF0yqE_pjc4_QocMEHk-Seci9EDXHPsvci-tjti9CYnBLnxP3TuFJmyykJ6aPad9WuW5K/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="571" data-original-width="639" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSz2otohIsODUlcyce8a-iU_z2LI0iG9TZkgq6v7vjV7s26qBNfVAVsON-iiwf3REdxDL-utDCF0yqE_pjc4_QocMEHk-Seci9EDXHPsvci-tjti9CYnBLnxP3TuFJmyykJ6aPad9WuW5K/w400-h358/fit2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;">[그림 2.9] single kernel, single DTB FIT source(kernel_fdt.its 파일)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: justify;"><span style="text-align: left;">itb(FIT blob) 파일 생성은 uImage를 생성할 때 사용했던 mkimage로 하게 된다.</span></div><div class="separator" style="clear: both; text-align: left;">$ <b>mkimage -f kernel_fdt.its kernel_fdt.itb</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">그렇다면 부팅은 어떻게 할까 ? (편의상, 앞선 예제하고는 무관하게) SAMA5D3 Xplained board를 가지고 직접 확인해 보도록 하자.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg6Zi3OabfP-LoEYA9qMdpWVF05NQQt1xaJ_XCoH3NKuzriULtC0TP6JqTfkEYwxsM5PsusGElYc2sPeLX8q2JmL1CcYSDKeLxx_Ej8JSaejnTSe2EYtqLpxQGDZt0AN0jXQoVYd_Vx46b/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="221" data-original-width="861" height="164" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg6Zi3OabfP-LoEYA9qMdpWVF05NQQt1xaJ_XCoH3NKuzriULtC0TP6JqTfkEYwxsM5PsusGElYc2sPeLX8q2JmL1CcYSDKeLxx_Ej8JSaejnTSe2EYtqLpxQGDZt0AN0jXQoVYd_Vx46b/w640-h164/at91_fit_uboot_config.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.10] FIT 관련 u-boot config</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">다른 부분은 크게 차이가 없고, 단 하나 <b style="text-align: left;"><font color="#0b8043">bootm 0x24000000#kernel_dtb</font></b><span style="text-align: left;"> 표현식 부분이 그간 못 보던 내용이다.</span></div><div class="separator" style="clear: both; text-align: left;"><span style="text-align: left;"><br /></span></div><div class="separator" style="clear: both; text-align: left;"><span style="text-align: left;">다음은 kernel booting 모습이다. 이 부분도 기존에 보던 것과는 사뭇 다르다. 내용을 보면 알겠지만, FIT image 중에서 kernel을 찾아 loading 하고, 이어서 dtb를 찾아 loading을 하고 있다.</span></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC5aCsuhKR2FrTZpUGqSU7Rl0Ledu9tJ2cpebD3FMOTXaFH7xUW2dIR8UwdiVEbM16UodK1XKK9oNAI7X_6-A9r3OGARHyQfLIfZbrx0ZlEfPkg7DAvNzpn-92EmoxIx4sQ2AmWsh-OBpp/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="810" data-original-width="1004" height="517" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgC5aCsuhKR2FrTZpUGqSU7Rl0Ledu9tJ2cpebD3FMOTXaFH7xUW2dIR8UwdiVEbM16UodK1XKK9oNAI7X_6-A9r3OGARHyQfLIfZbrx0ZlEfPkg7DAvNzpn-92EmoxIx4sQ2AmWsh-OBpp/w640-h517/at91_fit_boot.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;">[그림 2.11] FIT를 이용한 booting</div></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">참고: 위에서 소개한 its 예제와 위의 그림 2.11의 내용은 서로 아무런 관련이 없다.</font></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">FIT 관련 내용은 앞서 언급한 것 보다 훨씬 더 많은 내용을 담고 있는데, 보다 자세한 사항은 아래 site 내용을 참고하기 바란다.</div><div><br /></div><div style="text-align: center;"><a href="https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf">https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf</a></div><div style="text-align: center;"><a href="https://www.linux4sam.org/bin/view/Linux4SAM/UsingFITwithOverlays">https://www.linux4sam.org/bin/view/Linux4SAM/UsingFITwithOverlays</a></div><div style="text-align: center;"><br /></div><div><br /></div><div><b><font size="4">2.5 UBI/UBIFS 소개</font></b></div><div style="text-align: justify;">UBIFS는 현재 가장 활발하게 사용하는 file system 중 하나이다. UBIFS는 MTD device의 추상화 layer인 UBI(Unsorted Block Images)를 기반으로 하고 있다. UBI는 아래 그림에서 보는 것 처럼 PEB(Physical Erase Blocks)와 LEB(Logical Erase Blocks)를 서로 mapping해 주는 역할을 담당한다.</div><div style="text-align: justify;"><font color="#b51200" size="2">참고: UBI와 UBIFS는 서로 다른 사람이 개발한 것이다.</font></div><div><br /></div><div><div class="separator" style="clear: both;"><b><몇가지 용어 정리></b></div><div><i><b>UBI(Unsorted Block Image)</b></i></div><div><i> => bad block handling 및 wear leveling을 담당하는 volume manager</i></div><div><i><b>UBIFS(UBI File System)</b></i></div><div><i> => UBI 개념을 활용한 file system</i></div><div><i><b>MTD(Memory Technology Devices)</b></i></div><div><i><b> </b>=> sector 단위가 아니라 page 단위(or erase block이라고도 함)로 read/write하기 위해 나온 개념.</i></div><div><i> => JFFS2, YAFFS2, UBIFS 등은 모두 MTD layer 위에 존재함.</i></div><div><i><b>Wear Leveling</b></i></div><div><i> => flash memory를 구성하는 cell을 골고루 돌아 가며 읽기/쓰기를 할 수 있도록 하는 기능. </i></div><div><i> => flash memory의 수명을 연장시키키기 위한 기술.</i></div><div><i> => wear leveling이 가능하도록 하기 위해 몇번 erase되었는지를 표시하는 count 값을 flash memory 앞 부분에 저장해 둠.</i></div><div><br /></div><div><font color="#b51200" size="2">참고: 모든 출발점은 NAND flash의 수명을 연장시키기 위한 방법(wear leveling)과 bad block을 어찌 처리할 것인가에 있다.</font></div><div><br /></div></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOPstg70gvLymzdLYSsBnsGk2lvJNk5hhQ0aaZ7NlCguQI080R5YEo41BKO7bsPDkH_ooygxkLoST7l-EZQ9g9PSXfshDCq-6h72n4ZQX2U6kINGUKGm6Uv9bZxilDfQeZl8DkTOnBupNE/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="270" data-original-width="896" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOPstg70gvLymzdLYSsBnsGk2lvJNk5hhQ0aaZ7NlCguQI080R5YEo41BKO7bsPDkH_ooygxkLoST7l-EZQ9g9PSXfshDCq-6h72n4ZQX2U6kINGUKGm6Uv9bZxilDfQeZl8DkTOnBupNE/w400-h120/flash008.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.12] UBI <=> MTD 간의 관계도 - LEB and PEB mapping</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyeMUxdsow8cgVTQRKnmRA41Ku39ns48xiOnhAwetdo4gjUH-CDt-b0Jqx2zjFtK746_Zxk-s_vckBm2JVGTgpc8qG1R1MnsK3yWk9ZxsukvA7iuPMQDIe8ntMydINyej9WE8EU8bZTxaq/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="449" data-original-width="432" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyeMUxdsow8cgVTQRKnmRA41Ku39ns48xiOnhAwetdo4gjUH-CDt-b0Jqx2zjFtK746_Zxk-s_vckBm2JVGTgpc8qG1R1MnsK3yWk9ZxsukvA7iuPMQDIe8ntMydINyej9WE8EU8bZTxaq/s320/flash009.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.13] PEB vs LEB의 차이점</div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimfbvfEY7LCmwbk8Mu6uPeHUezI3FUnVXVH4TgzGM5_rY3xFlTmGdBmV6USS5uIzD7TZGYRZGSroUdzVLvacFFJvEu_cwMiSP0HBg2M_JuMmNJpxGMQ7utfPoMtDZf_BwjFwVjNbKt5kBY/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="334" data-original-width="850" height="253" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimfbvfEY7LCmwbk8Mu6uPeHUezI3FUnVXVH4TgzGM5_rY3xFlTmGdBmV6USS5uIzD7TZGYRZGSroUdzVLvacFFJvEu_cwMiSP0HBg2M_JuMmNJpxGMQ7utfPoMtDZf_BwjFwVjNbKt5kBY/w640-h253/flash011.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.14] Flash device => MTD => UBI => UBIFS 관계도(계층도)</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">UBI file system을 만들기 위해서는 NAND flash 관련 parameter의 정확한 값을 사전에 알 수 있어야만 한다(이 값들은 datasheet를 통해 알 수 있는데, 사실 이 부분을 파악하는 것이 좀 어렵게 느껴질 수 있다 - <i><font color="#9e9e9e">일전에 굉장히 고생했던 기억이 있다 :(</font></i>).</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">- PEB (physical erase blocks) size</div><div class="separator" style="clear: both; text-align: left;">- LEB (logical erase blocks) size</div><div class="separator" style="clear: both; text-align: left;"><i><font size="2"> => PEB size - <span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;">(int((Subpage_size + Page_size) / Page_size)) * Page_size</span></font></i></div><div class="separator" style="clear: both; text-align: left;"><span style="background-color: white; color: #1a1a1a; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><i><font size="2"> => 대략적으로 LEB size는 PEB size 보다 1 page 적다고 보면 됨.</font></i></span></div><div class="separator" style="clear: both; text-align: left;">- page size(minimum input/out size)</div><div class="separator" style="clear: both; text-align: left;">- sub pages size</div><div class="separator" style="clear: both; text-align: left;">- maximum erase block counts</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">UBIFS 파일을 생성 및 운용하는 방법 또한 좀 복잡한데, 가장 간단한 방법을 소개하면 다음과 같다.</div><div class="separator" style="clear: both; text-align: left;"><i>1) mkfs.ubifs 명령을 사용하여 ubifs raw image 파일을 만들고,</i></div><div class="separator" style="clear: both; text-align: left;"><i>2) ubinize 명령을 사용하여 volume을 지정하는 과정을 통해 최종 file system image를 만들어 낸다. 이때 ubinize.cfg 라는 파일(설정해 주어야 함)이 별도로 필요하다.</i></div><div class="separator" style="clear: both; text-align: left;"><i>3) 마지막으로, ubifs image 파일을 nand flash에 write한 후, u-boot 설정을 변경하여 ubifs image로 부팅(rootfs mount)이 가능하도록 만든다.</i></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><mkfs.ubifs 명령 사용법></b></div><div class="separator" style="clear: both; text-align: left;"><pre style="background-color: white; border: 1px solid rgb(209, 209, 209); box-sizing: inherit; color: #1a1a1a; font-family: inconsolata, monospace; line-height: 1.3125; margin-bottom: 1.75em; margin-top: 0px; max-width: 100%; overflow-wrap: break-word; overflow: auto; padding: 1.75em; white-space: pre-wrap;"><font size="2"># mkfs.ubifs -r </path/to/your/rootfs/tree> -m <min io size>
-e <LEB size> -c <Eraseblocks count>
-o </path/to/output/ubifs.img></font></pre></div><div class="separator" style="clear: both; text-align: left;"><b><ubinize.cfg 파일 구성 방법></b></div><div class="separator" style="clear: both; text-align: left;"><pre style="background-color: white; border: 1px solid rgb(209, 209, 209); box-sizing: inherit; color: #1a1a1a; font-family: inconsolata, monospace; line-height: 1.3125; margin-bottom: 1.75em; margin-top: 0px; max-width: 100%; overflow-wrap: break-word; overflow: auto; padding: 1.75em; white-space: pre-wrap;"><font size="2">[rootfs_volume]
mode=ubi
image=rootfs.ubifs
vol_id=1
vol_type=static
vol_name=rootfs
vol_alignment=1
[rwdata_volume]
mode=ubi
image=data.ubifs
vol_id=2
vol_type=dynamic
vol_name=data
vol_alignment=1
vol_flags=autoresize</font></pre></div><div class="separator" style="clear: both; text-align: left;"><b><ubinize 명령 사용 방법></b></div><div class="separator" style="clear: both; text-align: left;"><pre style="background-color: white; border: 1px solid rgb(209, 209, 209); box-sizing: inherit; color: #1a1a1a; font-family: inconsolata, monospace; line-height: 1.3125; margin-bottom: 1.75em; margin-top: 0px; max-width: 100%; overflow-wrap: break-word; overflow: auto; padding: 1.75em; white-space: pre-wrap;"><font size="2"># ubinize -vv -o <output image> -m <min io size>
-p <PEB size>KiB <configuration file></font></pre></div><div class="separator" style="clear: both; text-align: left;"><b><u-boot config 설정 방법></b></div><div class="separator" style="clear: both; text-align: left;"><pre style="background-color: white; border: 1px solid rgb(209, 209, 209); box-sizing: inherit; color: #1a1a1a; font-family: inconsolata, monospace; line-height: 1.3125; margin-bottom: 1.75em; margin-top: 0px; max-width: 100%; overflow-wrap: break-word; overflow: auto; padding: 1.75em; white-space: pre-wrap;"><font size="2">ubi.mtd=<mtd partition number>
root=<ubi device>:<volume>
rootfstype=ubifs</font></pre></div><div class="separator" style="clear: both; text-align: left;">그럼 예를 하나 들어 보도록 하겠다.</div><div style="text-align: left;">$ <b>mkfs.ubifs -m 2048 -e 129024 -c 1996 -o <font color="#b51200">ubifs.img</font> -r ./rootfs</b></div><div style="text-align: left;">$ vi ubinize.cfg</div><div style="text-align: left;">[ubifs]</div><div style="text-align: left;">mode=ubi</div><div style="text-align: left;">image=<font color="#d52c1f">ubifs.img</font></div><div style="text-align: left;">vol_id=0</div><div style="text-align: left;">vol_size=200MiB</div><div style="text-align: left;">vol_type=dynamic</div><div style="text-align: left;">vol_name=rootfs</div><div style="text-align: left;">~</div><div style="text-align: left;">$ <b>ubinize -m 2048 -p 128KiB -s 512 -o <font color="#0b8043">ubi.img</font> ubinize.cfg</b></div><div style="text-align: left;"><font color="#b51200" size="2">[참고] ubi.img 파일을 XXX.ubi 형태로 변경해도 된다.</font></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><u-boot config></div><div style="text-align: left;"><b>ubi.mtd=4 root=ubi0:rootfs rw rootfstype=ubifs</b></div><div style="text-align: left;"><font color="#b51200" size="2">[참고] 당연히, 위의 설정과 함께 앞서 생성한 </font><font color="#0b8043" size="2">ubi.img</font><font color="#b51200" size="2"> 파일을 nand flash 파티션(여기서는 mtd=4이므로 5번째 파티션)에 write해 주어야 부팅이 가능하다.</font></div><div style="text-align: left;"><br /></div><div>글로써 많은 내용을 설명하려니, 좀 어렵다^^. 암튼 UBI/UBIFS는 현재 가장 hot한 file system임에 틀림 없으나, 정확한 사용을 하기 위해서는 분명히 몇가지 넘어야 할 장벽이 좀 있는 것 같다. 보다 자세한 사항은 아래 site 내용을 참조해 주기 바란다.</div><div><br /></div><div><div style="text-align: center;"><a href="https://bootlin.com/blog/creating-flashing-ubi-ubifs-images/">https://bootlin.com/blog/creating-flashing-ubi-ubifs-images/</a></div><div style="text-align: center;"><br /></div></div><div><br /></div><div>마지막으로 아래 그림은 (독자 여러분의 이해를 돕기 위해) SAMA5D3 board를 위한 UBIFS 설정 관련 파라미터를 Buildroot menuconfig 통해 보여주기 위해 캡쳐한 것이다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9JeOQ-fz6gGZWO94QawO7Uc-53O2irnj7ABnecMjf-JHTUPgF8_vUdhfDm5-lZQ0MAq73ZVOaqL3R7aPx6iPbQ5mo0lEZ1Lgfcim5mEcMmToxnWyy3hVVOBEq9CXOkAUdt_ZsARz65yK0/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="562" data-original-width="909" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9JeOQ-fz6gGZWO94QawO7Uc-53O2irnj7ABnecMjf-JHTUPgF8_vUdhfDm5-lZQ0MAq73ZVOaqL3R7aPx6iPbQ5mo0lEZ1Lgfcim5mEcMmToxnWyy3hVVOBEq9CXOkAUdt_ZsARz65yK0/w400-h248/buildroot_ubifs.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 2.15] buildroot menuconfig - SAMA5D3 UBIFS 설정 값</div><div><br /></div><div><br /></div><div><font color="#3367d6" size="6"><b>3. OpenWrt build 및 Image 설치</b></font></div><div>Yocto project와 Buildroot를 이용한 방법은 그 동안 여러 차례 설명하였으니, 오늘은 OpenWrt 환경을 소개해 보고자 한다.</div><div><br /></div><div><b><font size="4">3.1 OpenWrt build 하기</font></b></div><div>$ <b>git clone https://github.com/linux4sam/openwrt-at91.git</b></div><div><div><font size="2">'openwrt-at91'에 복제합니다...</font></div><div><font size="2">remote: Enumerating objects: 13, done.</font></div><div><font size="2">remote: Counting objects: 100% (13/13), done.</font></div><div><font size="2">remote: Compressing objects: 100% (13/13), done.</font></div><div><font size="2">remote: Total 470521 (delta 0), reused 0 (delta 0), pack-reused 470508</font></div><div><font size="2">오브젝트를 받는 중: 100% (470521/470521), 165.95 MiB | 2.24 MiB/s, 완료.</font></div><div><font size="2">델타를 알아내는 중: 100% (319691/319691), 완료.</font></div></div><div><br /></div><div>$ cd openwrt-at91/</div><div><div>$ <b>./scripts/feeds update -a</b></div><div>$ <b>./scripts/feeds install -a</b></div></div><div><br /></div><div>$ <b>cp configs/sama5d3_xplained_defconfig .config</b></div><div>$ <b>make defconfig</b></div><div><br /></div><div><div>$ <b>make menuconfig</b></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgozKEP4K9_4dItFksyzoUwdJIEmeB-7t8waXeCQOnFT4KuCThMQdAxzPKKh_TiK4ZxEOnalh11ycrrw7TYoU2JLezugcD_yGDBJUxfU_ISFAnuJNJ8QgjHuBDgIllMAzlTv_X5gFgJZugK/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="618" data-original-width="943" height="263" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgozKEP4K9_4dItFksyzoUwdJIEmeB-7t8waXeCQOnFT4KuCThMQdAxzPKKh_TiK4ZxEOnalh11ycrrw7TYoU2JLezugcD_yGDBJUxfU_ISFAnuJNJ8QgjHuBDgIllMAzlTv_X5gFgJZugK/w400-h263/openwrt_at91_menuconfig.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.1] OpenWrt menuconfig</div><div><br /></div><div><br /></div><div>$ <b>make V=s -j1</b></div><div>or</div><div>$ <b>make -j4</b></div></div><div><br /></div><div>$ cd bin/targets/at91/sama5d3-glibc; ls -la</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirAx2EDrKE8EOzmdPoBrL0O75OKQQpmb981vogT8hMX142LD_S7eeYSpVJlt-vLCaVRxF4jkH7yMp3fHY2uUwgBvmcrKkDxqmjMvFlEn6Ltinr33W1AobgG72EdJHo6U4VeSc-5yGx76j5/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="434" data-original-width="1202" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirAx2EDrKE8EOzmdPoBrL0O75OKQQpmb981vogT8hMX142LD_S7eeYSpVJlt-vLCaVRxF4jkH7yMp3fHY2uUwgBvmcrKkDxqmjMvFlEn6Ltinr33W1AobgG72EdJHo6U4VeSc-5yGx76j5/w400-h145/openwrt_at91_output.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.2] OpenWrt build 결과물</div><div><br /></div><div>OpenWrt와 관련해서는 본 저자의 아래 posting도 참조해 보기 바란다.</div><div style="text-align: center;"><a href="https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html">https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-gainstrong-minibox3-wireguard.html</a></div><div><br /></div><div><br /></div><div><b><font size="4">3.2 NAND flash에 image 설치하기</font></b></div><div>OpenWrt를 통해 build한 결과물 중, NAND flash writing에 사용할 파일을 추려 보면 다음과 같다.</div><div><br /></div><div><i>- at91bootstrap-sama5d3_xplainednf_uboot</i></div><div><div><i>- openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-root.ubi</i></div><div><i>- openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-zImage</i></div><div><i>- openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained.dtb</i></div></div><div><i>- u-boot-sama5d3_xplained_nandflash/u-boot.bin</i></div><div><i>- uboot.env</i></div><div><br /></div><div>[그림 2.6]의 NAND flash 파티션 map은 FIT image 관련 부분이 반영되어 있으나, 위의 openwrt image에서는 이를 사용하지 않고, dtb와 zImage(kernel)를 별도의 파티션으로 분리할 생각이다. 따라서 아래와 같은 새로운 partition map을 생각해 볼 수가 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwjA3PA0OO_VDaSjIjj6rc-lX8R2zhq1YlQQNgsIWZRgo9iNAtVQZ_4lx-22SGV0S6O7hKwsUOg3u98cCEgEADC_Mdh8Pbx3ddi3ZMXcAYD37T5fSdisx9P_khXXdzolt0T1r3AW9mgnId/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="489" data-original-width="270" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwjA3PA0OO_VDaSjIjj6rc-lX8R2zhq1YlQQNgsIWZRgo9iNAtVQZ_4lx-22SGV0S6O7hKwsUOg3u98cCEgEADC_Mdh8Pbx3ddi3ZMXcAYD37T5fSdisx9P_khXXdzolt0T1r3AW9mgnId/w221-h400/at91_nand_partition.png" width="221" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.3] New NAND flash partition map</div><div><br /></div><div><b><u-boot config 조정></b></div><div>=> setenv bootargs 'console=ttyS0,115200 mtdparts=atmel_nand:256k(bootstrap)ro,768k(uboot)ro,256k(env_redundant),256k(env),<font color="#9c27b0">128k(dtb)ro,6528k(kernel)ro</font>,-(rootfs) rootfstype=ubifs <font color="#9c27b0">ubi.mtd=6</font> root=ubi0:rootfs rw'</div><div><font color="#b51200" size="2">참고: dtb, kernel 영역이 새로 추가되었고, ubifs root file system은 mtd 6(0부터 시작)에 위치하도록 수정되었다.</font></div><div><br /></div><div>=> setenv bootcmd 'nand read 0x22000000 0x00180000 0x20000; nand read 0x21000000 0x1a0000 0x660000; bootz 0x21000000 - 0x22000000'</div><div><font color="#b51200" size="2">참고: nand read 0x22000000 0x00180000 0x20000 명령은 NAND flash 0x00180000 번지의 내용을 0x20000 크기 만큼 읽어서 RAM 0x22000000에 load하라는 의미이다.</font></div><div><br /></div><div><b><Desktop PC></b></div><div><div>$ cd ~/workspace/Boards/SAMA5D3/openwrt/openwrt-at91/bin/targets/at91/sama5d3-glibc</div><div><br /></div><div><b><u-boot.bin writing></b></div><div>$ <font color="#0b8043">sudo sam-ba -p serial -b sama5d3-xplained -a nandflash -c erase:0x040000:0x100000 -c write:u-boot-sama5d3_xplained_nandflash/u-boot.bin:0x040000</font></div></div><div><font color="#b51200" size="2">참고: 위 명령의 의미는 0x040000:0x100000 구간을 우선 erase 한 후, u-boot-sama5d3_xplained_nandflash/u-boot.bin(u-boot) 파일의 내용을 0x040000 번지에서 부터 write하라는 뜻이다.</font></div><div><span style="color: #0b8043;"><br /></span></div><div><b><Target board></b></div><div><div>=> RomBOOT</div><div><br /></div><div><font size="2">Applet 'NAND Flash' from softpack 2.17 (v2.17).</font></div><div><font size="2">Initializing NAND ioSet1 Bus Width 8</font></div><div><font size="2">PMECC configuration: 0xc0902405</font></div><div><font size="2">Sector size: 512</font></div><div><font size="2">Sectors per page: 4</font></div><div><font size="2">Spare size: 64</font></div><div><font size="2">ECC bits: 4</font></div><div><font size="2">ECC offset: 36</font></div><div><font size="2">ECC size: 28</font></div><div><font size="2">PMECC enabled</font></div><div><font size="2">Buffer Address: 0x0030a4a0</font></div><div><font size="2">Buffer Size: 22528 bytes</font></div><div><font size="2">NAND applet initialized successfully.</font></div></div><div><br /></div><div><div><b><dtb 파일 writing></b></div><div>$ <font color="#0b8043">sudo sam-ba -p serial -b sama5d3-xplained -a nandflash -c erase:0x180000:0x1a0000 -c write:openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained.dtb:0x180000</font></div><div><font color="#b51200" size="2">참고: 위 명령의 의미는 0x180000:0x1a0000 구간을 우선 erase 한 후, openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained.dtb(device tree blob) 파일의 내용을 0x180000 번지에서 부터 write하라는 뜻이다.</font></div><div><span style="color: #b51200; font-size: small;"><br /></span></div><div><div><b><Target board></b></div><div></div></div><div><font size="2">Applet 'NAND Flash' from softpack 2.17 (v2.17).</font></div><div><font size="2">Initializing NAND ioSet1 Bus Width 8</font></div><div><font size="2">PMECC configuration: 0xc0902405</font></div><div><font size="2">Sector size: 512</font></div><div><font size="2">Sectors per page: 4</font></div><div><font size="2">Spare size: 64</font></div><div><font size="2">ECC bits: 4</font></div><div><font size="2">ECC offset: 36</font></div><div><font size="2">ECC size: 28</font></div><div><font size="2">PMECC enabled</font></div><div><font size="2">Buffer Address: 0x0030a4a0</font></div><div><font size="2">Buffer Size: 22528 bytes</font></div><div><font size="2">NAND applet initialized successfully.</font></div></div><div><br /></div><div><div><b><kernel image writing></b></div><div><font color="#0b8043">$ sudo sam-ba -p serial -b sama5d3-xplained -a nandflash -c erase:0x1a0000:0x800000 -c write:openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-zImage:0x1a0000</font></div><div><font color="#b51200" size="2">참고: 위 명령의 의미는 0x1a0000:0x800000 구간을 우선 erase 한 후, openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-zImage(kernel image) 파일의 내용을 0x180000 번지에서 부터 write하라는 뜻이다.</font></div><div><span style="color: #b51200; font-size: small;"><br /></span></div><div><b><Target board></b></div><div><font size="2">Applet 'NAND Flash' from softpack 2.17 (v2.17).</font></div><div><font size="2">Initializing NAND ioSet1 Bus Width 8</font></div><div><font size="2">PMECC configuration: 0xc0902405</font></div><div><font size="2">Sector size: 512</font></div><div><font size="2">Sectors per page: 4</font></div><div><font size="2">Spare size: 64</font></div><div><font size="2">ECC bits: 4</font></div><div><font size="2">ECC offset: 36</font></div><div><font size="2">ECC size: 28</font></div><div><font size="2">PMECC enabled</font></div><div><font size="2">Buffer Address: 0x0030a4a0</font></div><div><font size="2">Buffer Size: 22528 bytes</font></div><div><font size="2">NAND applet initialized successfully.</font></div><div><br /></div><div><br /></div><div><b><rootfs ubifs image writing></b></div><div><font color="#0b8043">$ sudo sam-ba -p serial -b sama5d3-xplained -a nandflash -c erase:0x800000: -c write:openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-root.ubi:0x800000</font></div><div><font color="#b51200" size="2">참고: 위 명령의 의미는 0x800000:끝까지 구간을 우선 erase 한 후, openwrt-18.06.2-linux4sam-6.2-at91-sama5d3-at91-sama5d3_xplained-ubifs-root.ubi(ubifs image) 파일의 내용을 0x800000번지에서 부터 write하라는 뜻이다.</font></div><div><span style="color: #b51200; font-size: small;"><br /></span></div><div><b><Target board></b></div><div><font size="2">Applet 'NAND Flash' from softpack 2.17 (v2.17).</font></div><div><font size="2">Initializing NAND ioSet1 Bus Width 8</font></div><div><font size="2">PMECC configuration: 0xc0902405</font></div><div><font size="2">Sector size: 512</font></div><div><font size="2">Sectors per page: 4</font></div><div><font size="2">Spare size: 64</font></div><div><font size="2">ECC bits: 4</font></div><div><font size="2">ECC offset: 36</font></div><div><font size="2">ECC size: 28</font></div><div><font size="2">PMECC enabled</font></div><div><font size="2">Buffer Address: 0x0030a4a0</font></div><div><font size="2">Buffer Size: 22528 bytes</font></div><div><font size="2">NAND applet initialized successfully.</font></div></div><div><br /></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhft2pnbbIRMIt0VTh-cXu-TGqsIIcWJexw7ihjROa6iJtL_cM49ZlGmhRZXKgHUGqXBsMDF9BzFLG3cogrgCmk1_hPt122sFk8jpVADP-gmTsNmwVIUlKuXyS1ckic8tD92Z1jGhVXDF6i/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="382" data-original-width="1778" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhft2pnbbIRMIt0VTh-cXu-TGqsIIcWJexw7ihjROa6iJtL_cM49ZlGmhRZXKgHUGqXBsMDF9BzFLG3cogrgCmk1_hPt122sFk8jpVADP-gmTsNmwVIUlKuXyS1ckic8tD92Z1jGhVXDF6i/w640-h138/openwrt_uboot_config.png" width="640" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.4] 수정된 u-boot config 모습</div><div class="separator" style="clear: both; text-align: left;"><font color="#b51200" size="2">참고: 위의 설정 내용 중, NFS 관련 설정은 이후에 별도로 추가해 본 것이다. 무시하기 바란다.</font></div><div><br /></div><div><br /></div><div>주요 파티션에 대한 erase 및 writing이 모두 정상적으로 진행되었으니, reset 버튼을 눌러 target board를 재부팅해 주도록 하자.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5NKSWZnzlQ41JnjQd47Ah9oQ23wiWa2sdNkfHveZfH07uxECI8Fz0hzHzxDmtdd4twK73crzJucpTMiUWFXtgL67LA9lDktba3O8Hkf7bAP0MK23q2NCAHMoYKHGC_pygK0pxvvILObc-/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="662" data-original-width="921" height="288" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5NKSWZnzlQ41JnjQd47Ah9oQ23wiWa2sdNkfHveZfH07uxECI8Fz0hzHzxDmtdd4twK73crzJucpTMiUWFXtgL67LA9lDktba3O8Hkf7bAP0MK23q2NCAHMoYKHGC_pygK0pxvvILObc-/w400-h288/openwrt_boot1.png" width="400" /></a></div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje-rV-HfbR1MIy5uSob9LPFwC1uDCA5Vt0RuM252CqcCEmNPyv5Ksi2i6ZelflhoVFrbC5R6AxOYtlRxnlKXv3JivPOXVGxgkgDd_M_GErAGXfqQJZ3dhZ5qjMXAgCoMAe2DmUq8htCpjM/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="556" data-original-width="779" height="285" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje-rV-HfbR1MIy5uSob9LPFwC1uDCA5Vt0RuM252CqcCEmNPyv5Ksi2i6ZelflhoVFrbC5R6AxOYtlRxnlKXv3JivPOXVGxgkgDd_M_GErAGXfqQJZ3dhZ5qjMXAgCoMAe2DmUq8htCpjM/w400-h285/openwrt_boot2.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.5] Openwrt image booting 모습</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisgZ6lJ990B7rKy1Wf7qOVTJ6NaYUneGwdL6LvjRbgz3pQ5cHW4AmY9IyQd3qiJ3zkRw1GcInjRTQw91kvhKH7mf9AgdmFp73n0mI4AF18CZh4GvdSS6HG61SA0GDPXOY-6tNO_8tcDDMk/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="758" data-original-width="727" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisgZ6lJ990B7rKy1Wf7qOVTJ6NaYUneGwdL6LvjRbgz3pQ5cHW4AmY9IyQd3qiJ3zkRw1GcInjRTQw91kvhKH7mf9AgdmFp73n0mI4AF18CZh4GvdSS6HG61SA0GDPXOY-6tNO_8tcDDMk/s320/openwrt_at91_ps.png" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.6] Openwrt login 후 ps 명령 실행 모습</div><div><br /></div><div><b><font size="4">3.3 OpenWrt WebUI 및 ssh login</font></b></div><div>OpenWrt에는 (모양은 좀 떨어지지만) Lua를 기반으로 만들어진 LuCI라는 webUI가 기본적으로 탑재되어 있다. 따라서 기본적인 설정(예: ssh port open)은 모두 여기서 할 수가 있다.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicZkELTwqM5udYvBea9Wk9IM4N3La_h5eC27y0hyphenhyphenM-Rox20V9RtAIF-imkE1dL2A8Nsc84Kuop5Xmgexb6AsNr4lwSdOW9VLMkl8M6LRz8hYx8Yz4OV-hdjm9ZTJPFdrKlEXb_-4IleC4x/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="878" data-original-width="1242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicZkELTwqM5udYvBea9Wk9IM4N3La_h5eC27y0hyphenhyphenM-Rox20V9RtAIF-imkE1dL2A8Nsc84Kuop5Xmgexb6AsNr4lwSdOW9VLMkl8M6LRz8hYx8Yz4OV-hdjm9ZTJPFdrKlEXb_-4IleC4x/s320/openwrt_at91_luci.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">[그림 3.7] Openwrt WebUI - LuCI 화면</div><div><br /></div><div><br /></div><div>마지막으로 4장에서 device driver 시험을 진행하기 전에 ssh login이 가능하도록 만들어 두도록 하자.</div><div><br /></div><div><b><target board></b></div><div><div>root@OpenWrt:/# <b>passwd</b></div><div><font size="2">Changing password for root</font></div><div><font size="2">New password: </font></div><div><font size="2">Bad password: similar to username</font></div><div><font size="2">Retype password: </font></div><div><font size="2">passwd: password for root changed by root</font></div></div><div><br /></div><div><b><Desktop PC></b></div><div>$ <b>ssh root@192.168.1.1</b></div><div><div><font size="2">The authenticity of host '192.168.1.1 (192.168.1.1)' can't be established.</font></div><div><font size="2">RSA key fingerprint is SHA256:NdTf/DCS1As/QQ+QoUrtBfIpgGRYq+x5ukAtdpI/zVs.</font></div><div><font size="2">Are you sure you want to continue connecting (yes/no)? yes</font></div><div><font size="2">Warning: Permanently added '192.168.1.1' (RSA) to the list of known hosts.</font></div><div><font size="2">root@192.168.1.1's password:</font></div></div><div><br /></div><div>root@OpenWrt:~# <b>mkdir workspace</b></div><div>앞으로 이 디렉토리에 device driver 예제 파일을 올려 둘 생각이다.</div><div><br /></div><div><br /></div><div><font color="#3367d6" size="6"><b>4. LDD4EP2 book 예제 build해 보기</b></font></div><div>앞선 과정을 통해 device driver 개발을 위한 환경 설정이 마무리되었으니, 이번 장(실제로는 다음번 posting) 부터는 LDD4EP2 book의 예제를 SAMA5D3 Xplained 보드에서 하나씩 돌려 보고, 주요 사항을 분석해 보도록 하겠다.</div><div style="text-align: center;"><div style="text-align: left;"><br /></div></div><div style="text-align: left;"><b><font size="4">4.1 LDD4EP2 book 목차</font></b></div><div style="text-align: left;">LDD4EP2 book의 목차는 대략 아래와 같다. 이중 5 ~ 12장이 핵심 장이라고 볼 수 있는데, 각 장에서는 device tree와 이와 연결될 device driver 예제를 상세히 설명해 주고 있다.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><i><b>1장: </b>Build system 소개 - Yocto project를 이용한 build 방법 및 kernel 단독 build 방법 등 소개</i></div><div style="text-align: left;"><i><b>2장: </b>linux device driver model 소개</i></div><div style="text-align: left;"><i><b>3장:</b> hello world string을 출력하는 device driver 예 소개</i></div><div style="text-align: left;"><i><b>4장:</b> character driver 예 소개</i></div><div style="text-align: left;"><i><font color="#f57c00"><b>5장: </b>platform driver 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>6장:</b> i2c client driver 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>7장:</b> interrupt handling driver 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>8장: </b>MMU의 원리를 설명하고 간단한 예제 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>9장: </b>DMA의 동작 원리를 설명하고 관련 예제 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>10장: </b>Input subsystem 소개 및 관련 driver 예제 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>11장: </b>IIO(Industrial IO) subsystem 소개 및 관련 driver 예제 소개</font></i></div><div style="text-align: left;"><i><font color="#f57c00"><b>12장: </b>Regmap API 사용 예제 driver 소개</font></i></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div>아래 site에 가 보면, 이 책에서 언급하고 있는 예제 source와 practical lab 문서 등을 확인해 볼 수가 있다.</div><div style="text-align: center;"><a href="https://github.com/ALIBERA/linux_book_2nd_edition">https://github.com/ALIBERA/linux_book_2nd_edition</a></div></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div style="text-align: left;">한가지 더, LDD4EP2 book과 더불어 반드시 함께 살펴 보아야 할 문서가 있다. 바로 <a href="https://bootlin.com/">Bootlin</a>에서 작성한 아래 파일이다.</div><div style="text-align: left;"><br /></div><div style="text-align: center;"><a href="https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf">https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf</a></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><br /></div><div><b><font size="4">4.2 LDD4EP2 예제 build 하기</font></b></div><div><div><b><target board></b></div><div>root@OpenWrt:/# uname -a</div><div>Linux OpenWrt <font color="#b51200">4.19.78</font>-linux4sam-6.2 #0 Wed Jan 30 12:21:02 2019 armv7l GNU/Linux</div></div><div><br /></div><div><b><Linux Desktop PC></b></div><div><div>$ <b><font color="#0b8043">export PATH=~/workspace/Boards/SAMA5D3/openwrt/openwrt-at91/staging_dir/toolchain-arm_cortex-a5+vfpv4_gcc-7.4.0_glibc_eabi/bin:$PATH</font></b></div><div>$ <b><font color="#0b8043">export STAGING_DIR=~/workspace/Boards/SAMA5D3/openwrt/openwrt-at91/staging_dir</font></b></div><div>$ <b><font color="#0b8043">export ARCH=arm</font></b></div><div>$ <font color="#0b8043"><b>export CROSS_COMPILE=arm-openwrt-linux-</b></font></div></div><div><br /></div><div>$ cd linux_4.14_sama5d27-SOM_drivers</div><div>$ <b><font color="#0b8043">make clean</font></b></div><div>$ <b><font color="#0b8043">make</font></b></div><div><i> -> 4.14 version 기준으로 되어 있어 OpenWrt kernel(4.19.78 version) 환경에서 build 시, 몇가지 compile error 발생함(적절히 수정함).</i></div><div><i><br /></i></div><div><div>$ <b>scp ./helloworld_sam.ko root@192.168.1.1:~/workspace</b></div><div>root@192.168.1.1's password: </div><div>helloworld_sam.ko 100% 27KB 2.0MB/s 00:00 </div></div><div><br /></div><div><br /></div><div><b><target board></b></div><div><b><br /></b></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNX6pSgXsu1sbgsvfILm1jdNCh1LZ4OCxMqm0RbQj9IWJhUk_ZQ5m-hFjvTFUxO2MpDwtthDOLxbagvmJxQ-XdpeZ0xfTzb_ZTroX1-OWVUDtj4nmx4glaYy59hahNpoh2WXtonWcJZ2dl/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="200" data-original-width="860" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNX6pSgXsu1sbgsvfILm1jdNCh1LZ4OCxMqm0RbQj9IWJhUk_ZQ5m-hFjvTFUxO2MpDwtthDOLxbagvmJxQ-XdpeZ0xfTzb_ZTroX1-OWVUDtj4nmx4glaYy59hahNpoh2WXtonWcJZ2dl/w640-h148/at91_hello_ko.png" width="640" /></a></div><div><br /></div><div><br /></div><div><div><b><font size="4">4.3 Platform driver 예제 소개</font></b></div><div><b>TODO: </b>다음번 posting에서 ...</div></div><div><br /></div><div>==========</div><div>(뭔가 좀 아쉬운 부분이 남긴 하지만) 이상으로 <b>LDD4EP 에피소드 1</b> <span style="text-align: center;">"<b><font color="#0b8043">Atmel SAMA5D3 Xplained 보드의 기본 환경 설정과 LDD4EP2 book의 예제 build해 보기</font></b>" 편의 내용을 마치고자 한다.</span></div><div><span style="text-align: center;">다음 편에서는 4장 LDD4EP2 book 예제를 중심으로 보다 구체적인 device tree & device driver programming에 대해 알아보도록 하겠다.</span></div><div><br /></div><div style="text-align: center;">To be continued ...</div><div style="text-align: center;"><br /></div><div style="text-align: center;"><br /></div><div><b><font color="#3367d6" size="6">5. References</font></b></div><div><font size="2">1. Linux Driver Development for Embedded Processors, 2nd edition, Alberto Liberal de los Rios.</font></div><div><font size="2">2. <a href="https://www.linux4sam.org/">https://www.linux4sam.org/</a></font></div><div><font size="2">3. <a href="https://bootlin.com/doc/training/embedded-linux/embedded-linux-labs.pdf">https://bootlin.com/doc/training/embedded-linux/embedded-linux-labs.pdf</a></font></div><div><font size="2">4. <a href="https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf">https://elinux.org/images/f/f4/Elc2013_Fernandes.pdf</a></font></div><div><font size="2">5. <a href="https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf">https://bootlin.com/doc/training/linux-kernel/linux-kernel-slides.pdf</a>, bootlin</font></div><div><font size="2">6. <font><a href="https://bootlin.com/doc/training/embedded-linux/embedded-linux-slides.pdf" style="color: black;">https://bootlin.com/doc/training/embedded-linux/<font face="Inconsolata, monospace"><span style="box-sizing: inherit; white-space: pre-wrap;">embedded-linux-slides.pdf</span></font></a><font color="#1a1a1a" face="inconsolata, monospace"><span style="background-color: white; white-space: pre-wrap;">, bootlin</span></font></font></font></div><div><span style="background-color: white; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><font color="#1a1a1a" size="2">7. Embedded Linux Primer, 2nd Edition, Christopher Hallinan</font></span></div><div><span style="background-color: white; font-family: inconsolata, monospace; font-size: 16px; white-space: pre-wrap;"><font color="#1a1a1a" size="2">8. Mastering Embedded Linux Programing, Chris Simmonds</font></span></div><div><br /></div><div><br /></div></div><div style="text-align: right;"><b><font color="#0b8043">Slowboot</font></b></div><div><br /></div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0tag:blogger.com,1999:blog-6346200245600677355.post-74462536800436969142020-05-10T16:15:00.002+09:002020-07-22T10:31:13.454+09:00Single Board Computer를 이용한 Embedded Linux 분석 및 Kernel Programming<div style="text-align: justify;">
본 blog에서는 아래 열거한 몇가지 single board computer(TI, Atmel/Microchip, Freescale/NXP, Allwinner, Qualcomm, Marvell, ST Micro, Rockchip, MediaTek 등)(가능한한 <span style="background-color: #6aa84f;">100$ 이하의 보드만을 대상으로 함</span>)를 기초로 하여, bootloader, device tree, linux kernel & device driver, Buildroot, OpenWrt, Yocto project, Android, system programming 및 application programming 등과 관련된 내용을 지속적으로 분석해 봄으로써, 각종 <span style="color: #b45f06;">embedded processor, </span><span style="color: #b45f06;">embedded linux, RTOS 개발에 필요한 기초 지식을 정리 & 공유</span>해 보고자 하고자 한다.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhMsgN36IOs-dK9sH2C8R1vI5Fx5yuQR2iMB-hLELJMvuOoYbKGoD2-R8YPqyf7ESf6ziwYIEqqXJEXZ9mk9ViBnW-2BY6BY89LEiUarMLa39Z3ek38k36dpkixjzuOC4mS0BkFw0fJLd3/s1600/Linux-Image-Header.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="197" data-original-width="787" height="100" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhMsgN36IOs-dK9sH2C8R1vI5Fx5yuQR2iMB-hLELJMvuOoYbKGoD2-R8YPqyf7ESf6ziwYIEqqXJEXZ9mk9ViBnW-2BY6BY89LEiUarMLa39Z3ek38k36dpkixjzuOC4mS0BkFw0fJLd3/s400/Linux-Image-Header.jpg" width="400" /></a></div>
<br />
<b><span style="background-color: white;"><주요 주제></span></b><br />
a) 다양한 SBC & embedded processor 검토(datasheet, schematics 등) - ARMv7-M/A, ARMv8-A, MIPS32, x86, PowerPC ...<br />
b) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/buildroot.html">Buildroot</a>, <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/yocto-project.html">Yocto project</a>, <a href="http://openwrt.org/">OpenWRT</a>, <a href="http://slowbootkernelhacks.blogspot.kr/2017/02/how-to-build-android-sources-for-udoo.html">Android</a> 등 적용<br />
c) Bootloader(<a href="https://www.denx.de/wiki/U-Boot">u-boot</a>, <a href="https://github.com/littlekernel/lk/wiki">Little Kernel</a> 등), device tree, linux kernel 코드 분석<br />
d) <a href="http://slowbootkernelhacks.blogspot.kr/2017/05/yocto-project-linux-device-driver.html">Linux kernel module, device driver programming</a>, RTOS(<a href="https://www.riot-os.org/">RIOT</a>, <a href="https://www.zephyrproject.org/">Zephyr</a> and <a href="https://www.mbed.com/en/platform/mbed-os/">ARM Mbed OS</a>) programming<br />
e) Application programming(<a href="http://slowbootkernelhacks.blogspot.kr/2017/06/yocto-embedded-linux-systems-programming.html">system programming</a>, android app, <a href="http://slowbootqt.blogspot.kr/2017/01/embedded-qt-programming.html">Qt app</a>, Python app, web programming)<br />
f) Networks(TCP/IP, L2/L3, Wired/wireless, LTE), security(<a href="https://www.wireguard.com/">Wireguard</a>, <a href="https://www.softether.org/">SoftEther VPN</a>), LoRaWAN etc.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx_S7S7zJYl2DFTNpys0gk5-aXNqEzY_F1ifZ9vhPO5p3IiZrF0fJHSVKwPoAS5-ZNCv8wQiwMAyn7PgiPWB569BmcpTWJ0Y_g2-bduaqFUNJg1z22pLek9tAyfsKBA0HDGiZPODaEOPU4/s1600/github.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="163" data-original-width="310" height="105" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx_S7S7zJYl2DFTNpys0gk5-aXNqEzY_F1ifZ9vhPO5p3IiZrF0fJHSVKwPoAS5-ZNCv8wQiwMAyn7PgiPWB569BmcpTWJ0Y_g2-bduaqFUNJg1z22pLek9tAyfsKBA0HDGiZPODaEOPU4/s200/github.png" width="200" /></a></div>
<br />
<div style="text-align: center;">
<b><span style="font-size: large;"><a href="https://github.com/ChunghanYi">Slowboot's Github for Kernel Hacks</a></span></b></div>
<br />
<br />
<b style="background-color: #a64d79;"><span style="color: white;">ARMv7-M Series(32 bits)</span></b><br />
<span style="color: #0b5394; font-size: large;">1) <b style="color: #0b5394;"><a href="http://www.st.com/en/evaluation-tools/nucleo-f103rb.html">Nucleo F103RB</a></b></span> - STM32F103RB ARM Cortex-M3 MCU<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXxAsKqCpSMe9-Kr7l2QDmh7nMbKccutPC9Vym9qjZMfgfnDnTsPe0jGTgPx7ESJBYt4o8UBKEj76WABs3Lh52n9yzEByacYpr1hJt9dxdaiSlCMaRqO3USC5PSaDCxYJFGSYyL7i8lKCJ/s1600/NUCLEO-F103RB-3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXxAsKqCpSMe9-Kr7l2QDmh7nMbKccutPC9Vym9qjZMfgfnDnTsPe0jGTgPx7ESJBYt4o8UBKEj76WABs3Lh52n9yzEByacYpr1hJt9dxdaiSlCMaRqO3USC5PSaDCxYJFGSYyL7i8lKCJ/s320/NUCLEO-F103RB-3.jpg" width="320" /></a> <div class="separator" style="clear: both; text-align: center;"><br /></div></div>
<span style="background-color: white;"><span style="color: #0b5394;"><특장점></span></span><br />
<span style="color: #0b5394;"><span style="background-color: white;">ST-Link/V2-1 programmer(debugger)가 on board되어 있어, 별도의 jtag debugger가 필요치 않다(console cable도 필요치 않음). ST micro 보드는 매우 널리 사용되고 있으며, 인터넷에서 관련 자료를 쉽게 찾을 수 있음. ARM Mbed OS, Zephyr Project, RIOT OS에서 지원하고 있는 보드임.</span></span><br />
<br />
<my postings><br />
<div style="text-align: center;">
<div style="text-align: left;">
a) <a href="http://slowbootkernelhacks.blogspot.kr/2017/03/riot-os.html">http://slowbootkernelhacks.blogspot.kr/2017/03/riot-os.html</a><br />
b) <a href="http://slowbootkernelhacks.blogspot.kr/2017/03/riot-os-2.html">http://slowbootkernelhacks.blogspot.kr/2017/03/riot-os-2.html</a><br />
c) <a href="http://slowbootkernelhacks.blogspot.kr/2017/03/zephyr-project.html">http://slowbootkernelhacks.blogspot.kr/2017/03/zephyr-project.html</a><br />
d) <a href="https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html">https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html</a><br />
<br />
<br />
<span style="color: #0b5394; font-size: large;">2) <b style="color: #0b5394;"><a href="https://os.mbed.com/platforms/ST-Discovery-LRWAN1/">DISCO-L072CZ-LRWAN1</a></b></span> - B-L072Z-LRWAN1 LoRa Discovery Kit, ARM 32bit Cortex M0+ CPU<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyA255UvCSRw3bdSMd0-4mK93JMZ6M7d5Y2PZIGZ2UyiOMpvobVkvk3gfrzKzWzlaXHYSrbDZS7feXKx4eCVSHiTdcyLuRQ_Q10N9XlS_itM-58U8KZ8HKKywFGr1QW2ow_yIwC5tBBArR/s1600/disco_board.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="247" data-original-width="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyA255UvCSRw3bdSMd0-4mK93JMZ6M7d5Y2PZIGZ2UyiOMpvobVkvk3gfrzKzWzlaXHYSrbDZS7feXKx4eCVSHiTdcyLuRQ_Q10N9XlS_itM-58U8KZ8HKKywFGr1QW2ow_yIwC5tBBArR/s1600/disco_board.jpeg" /></a></div>
<br />
<span style="background-color: white;"><span style="color: #0b5394;"><특장점></span></span><br />
<span style="background-color: white;"><span style="color: #0b5394;">LoRaWAN 센서를 만들기에 적합한 보드이며, ARM Mbed OS를 지원한다. 원문 내용을 그대로 옮겨 보았다. </span></span><br />
<div style="box-sizing: border-box; color: #333e48; font-family: lato, sans-serif; font-size: 16px; margin-bottom: 1rem;">
<i>"The B-L072Z-LRWAN1 LoRa®Discovery kit is a development tool to learn and develop solutions based on LoRa®and FSK/OOK technologies. This Discovery kit features an all-in-one open module CMWX1ZZABZ-091 (by Murata). The module is powered by an STM32L072CZ and an SX1276 transceiver."</i></div>
<my postings><br />
<div style="text-align: center;">
<div style="text-align: left;">
a) <a href="https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html">https://slowbootkernelhacks.blogspot.com/2020/05/posting-linux-os-arm-mbed-os-disco.html</a></div>
</div>
<br />
<br />
<br /></div>
</div>
<b style="background-color: #a64d79;"><span style="color: white;">ARMv7-A Series(32 bits)</span></b><br />
<span style="color: #0b5394; font-size: large;">3) <a href="http://beagleboard.org/" style="color: #0b5394;"><b>BeagleBone Series</b></a></span> - Sitara AM335x 1GHz ARM Cortex-A8 <b style="background-color: #ffe599;">(***** Best website for developers)</b><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikVe0yBY3wrxouMI-iksvBzlvk-Q-6bfvHzdE0kONQ4G2IRRWjwjJUE7iry7YejLkjlpePQ3TzrvKicZcVxR4j62RpATe9p2ck-NhXYkFW4NZrCjbrHto7tDAbm9Bt88Qd3dJih0OLopAv/s1600/beaglebone_blue.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikVe0yBY3wrxouMI-iksvBzlvk-Q-6bfvHzdE0kONQ4G2IRRWjwjJUE7iry7YejLkjlpePQ3TzrvKicZcVxR4j62RpATe9p2ck-NhXYkFW4NZrCjbrHto7tDAbm9Bt88Qd3dJih0OLopAv/s320/beaglebone_blue.jpg" width="320" /></a></div>
<span style="background-color: white; color: #0b5394;"><특장점></span><br />
<span style="background-color: white;"><span style="color: #0b5394;">현재 다른 보드에 비해 널리 알려져 있어, 관련 자료(book 포함)를 확보하기에 매우 유리하다. 2~3년 전에 BBB를 사용해 보았는데, 최근에 출시된 BB Green, BB Blue(Robot, Drone 용)도 사용해 보고 싶은 마음이다.</span></span><br />
<br />
<my postings><br />
<div style="text-align: center;">
<div style="text-align: left;">
a) <a href="http://slowbootkernelhacks.blogspot.kr/2014/03/beaglebone-linux-kernel310x-programming.html">http://slowbootkernelhacks.blogspot.kr/2014/03/beaglebone-linux-kernel310x-programming.html</a></div>
</div>
<div style="text-align: center;">
<div style="text-align: left;">
b) <a href="http://slowbootkernelhacks.blogspot.kr/2014/03/device-tree-i2c-programming.html">http://slowbootkernelhacks.blogspot.kr/2014/03/device-tree-i2c-programming.html</a></div>
<div style="text-align: left;">
c) <a href="http://slowbootkernelhacks.blogspot.kr/2014/03/device-tree-uart-programming.html">http://slowbootkernelhacks.blogspot.kr/2014/03/device-tree-uart-programming.html</a></div>
<div style="text-align: left;">
d) <a href="http://slowbootkernelhacks.blogspot.kr/2014/04/device-tree-spi-programming.html">http://slowbootkernelhacks.blogspot.kr/2014/04/device-tree-spi-programming.html</a></div>
</div>
e) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/booting-beaglebone-black-with-yocto.html">http://slowbootkernelhacks.blogspot.kr/2016/12/booting-beaglebone-black-with-yocto.html</a><br />
<br />
<br />
<span style="font-size: large;"><span style="color: #0b5394;">4) <a href="http://www.at91.com/linux4sam/bin/view/Linux4SAM" style="color: #0b5394;"><b>SAMA5DX Series</b></a></span> </span>- Atmel ARM Cortex-A5 (536Mhz ~) <b style="background-color: #ffe599;">(</b><b style="background-color: #ffe599;">***** </b><b style="background-color: #ffe599;">Best website for developers)</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzwPJnw_EEL5lu8ocX4KZJsV2bAKrWEcmndTJRErkXR0TDGiLfRicLScT0MF5hFefHHYTO8HmefEZRVuybo1EcOgkYNSGOVIMH4GqXWloBL2h-kDNQt9-SQKZF5amNB0SKbocpfPcn3P_/s1600/sama5d3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzwPJnw_EEL5lu8ocX4KZJsV2bAKrWEcmndTJRErkXR0TDGiLfRicLScT0MF5hFefHHYTO8HmefEZRVuybo1EcOgkYNSGOVIMH4GqXWloBL2h-kDNQt9-SQKZF5amNB0SKbocpfPcn3P_/s1600/sama5d3.jpg" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">Atmel 공식 site에 올라와 있는 내용이 매우 잘 정리되어 있어, 보고 따라 하는데 매우 효과적이다. 개인적으로 (여러가지 면에서) 매우 좋은 보드라고 생각한다 :)</span><br />
<br />
<my postings><br />
<div style="text-align: center;">
<div style="text-align: left;">
a) <a href="http://slowbootkernelhacks.blogspot.kr/2016/11/atmel-sama5d3-xplained-board-openvpn.html">http://slowbootkernelhacks.blogspot.kr/2016/11/atmel-sama5d3-xplained-board-openvpn.html</a></div>
</div>
<div style="text-align: center;">
<div style="text-align: left;">
b) <a href="http://slowbootkernelhacks.blogspot.kr/2016/11/atmel-sama5d3-xplained-board-i2c-device.html">http://slowbootkernelhacks.blogspot.kr/2016/11/atmel-sama5d3-xplained-board-i2c-device.html</a></div>
</div>
<div style="text-align: center;">
<div style="text-align: left;">
c) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/yocto-project.html">http://slowbootkernelhacks.blogspot.kr/2016/12/yocto-project.html</a></div>
<div style="text-align: left;">
d) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/buildroot.html">http://slowbootkernelhacks.blogspot.kr/2016/12/buildroot.html</a></div>
<div style="text-align: left;">
e) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/how-to-connect-tft-lcd-to-atmel-sama5d3.html">http://slowbootkernelhacks.blogspot.kr/2016/12/how-to-connect-tft-lcd-to-atmel-sama5d3.html</a><br />
f) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/how-to-connect-usb-camera-with-sama5d3.html">http://slowbootkernelhacks.blogspot.kr/2016/12/how-to-connect-usb-camera-with-sama5d3.html</a><br />
g) <a href="http://slowbootkernelhacks.blogspot.kr/2016/12/connecting-gps-click-board-to-atmel.html">http://slowbootkernelhacks.blogspot.kr/2016/12/connecting-gps-click-board-to-atmel.html</a><br />
h) <a href="http://slowbootkernelhacks.blogspot.kr/2017/01/sama5d3-xplained-board-qt-application.html">http://slowbootkernelhacks.blogspot.kr/2017/01/sama5d3-xplained-board-qt-application.html</a><br />
i) <a href="http://slowbootkernelhacks.blogspot.kr/2017/01/atmel-sam-ice-u-boot-linux-kernel.html">http://slowbootkernelhacks.blogspot.kr/2017/01/atmel-sam-ice-u-boot-linux-kernel.html</a></div>
<div>
<br />
<br /></div>
</div>
<span style="font-size: large;">5) <a href="http://riotboard.org/"><b>RIoTBoard</b></a></span> - Freescale(NXP) i.MX 6Solo, ARM Cortex-A9<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis80P2rT4_MDVqBFy4OVtNEZJCHAZUvB1bIQvVEI4n1ZEX-TlqLNIMOuAwPnW7ej3vHWsgA6xO_beqadN4ryqTeX8CzmkNd1-Nc400zXh3jIMMojZnbylVxmD6HYM03YJ81y4CL2KU9Dhh/s1600/riotboard.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEis80P2rT4_MDVqBFy4OVtNEZJCHAZUvB1bIQvVEI4n1ZEX-TlqLNIMOuAwPnW7ej3vHWsgA6xO_beqadN4ryqTeX8CzmkNd1-Nc400zXh3jIMMojZnbylVxmD6HYM03YJ81y4CL2KU9Dhh/s1600/riotboard.jpg" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">Freescale(NXP를 거쳐 현재는 Qualcomm에 인수됨)보드가 대부분 가격이 비싼데 반해, 상대적으로 저렴한 편이다. 공식 site의 관련 내용이 상대적으로 빈약한 편이지만, <a href="http://freescale.github.io/">freescale community site</a>를 활용하면 충분할 것으로 보인다.</span><br />
<br />
<my postings><br />
a) <a href="http://slowbootkernelhacks.blogspot.kr/2017/01/riot-board-based-on-freescale-imx-6solo.html">http://slowbootkernelhacks.blogspot.kr/2017/01/riot-board-based-on-freescale-imx-6solo.html</a><br />
b) <a href="http://slowbootkernelhacks.blogspot.kr/2017/01/riot-board-device-tree-analysis.html">http://slowbootkernelhacks.blogspot.kr/2017/01/riot-board-device-tree-analysis.html</a><br />
c) <a href="http://slowbootkernelhacks.blogspot.kr/2017/05/yocto-project-linux-device-driver.html">http://slowbootkernelhacks.blogspot.kr/2017/05/yocto-project-linux-device-driver.html</a><br />
d) <a href="http://slowbootkernelhacks.blogspot.kr/2017/06/yocto-embedded-linux-systems-programming.html">http://slowbootkernelhacks.blogspot.kr/2017/06/yocto-embedded-linux-systems-programming.html</a><br />
<br />
<br />
<span style="font-size: large;">6) <a href="http://www.udoo.org/" style="font-weight: bold;">UDOO NEO</a></span><a href="http://www.udoo.org/"> </a>- Freescale(NXP) i.MX6 SoloX(ARM Cortex-A9 core + Cortex-M4 core)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-iSBiH-QunPLM8M-O-WyKriU3cp03OOBMnO6pumQMQ5mL9wSY1bd5bFMAXnOB9vyeIb7OelZ9oJFSM9lvhoP6VoQ9ZpG-KcExg_Hr2sFODL-AJemDPf6G3BZLhOmbbvohnhMtqH363Btc/s1600/udoo.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="251" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-iSBiH-QunPLM8M-O-WyKriU3cp03OOBMnO6pumQMQ5mL9wSY1bd5bFMAXnOB9vyeIb7OelZ9oJFSM9lvhoP6VoQ9ZpG-KcExg_Hr2sFODL-AJemDPf6G3BZLhOmbbvohnhMtqH363Btc/s320/udoo.jpg" width="320" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">ARM Cortex-A9와 Cortex-M4 I/O real-time co-processor(아두이노 용)를 통합한 processor를 사용. Freescale(NXP) chip을 사용하며, Wi-Fi/Bluetooth, 9 Axis sensor(accelerometer, Gyroscope, Magnetometer)를 장착하고 있음. 관련 <a href="http://www.udoo.org/docs-neo/Introduction/Introduction.html">website의 자료</a>가 잘 정리되어 있어 개발자에게 충분한 도움이 될 것으로 보인다. 현재 Android 6.0.x Marshmallow version을 지원함.</span><br />
<br />
<my postings><br />
a) <a href="http://slowbootkernelhacks.blogspot.kr/2017/02/how-to-build-android-sources-for-udoo.html">http://slowbootkernelhacks.blogspot.kr/2017/02/how-to-build-android-sources-for-udoo.html</a><br />
b) <a href="http://slowbootkernelhacks.blogspot.kr/2017/02/device-tree-analysis-for-udoo-neo-board.html">http://slowbootkernelhacks.blogspot.kr/2017/02/device-tree-analysis-for-udoo-neo-board.html</a><br />
c) <a href="http://slowbootkernelhacks.blogspot.kr/2017/03/linux-kernel-programming-guide.html">http://slowbootkernelhacks.blogspot.kr/2017/03/linux-kernel-programming-guide.html</a><br />
d) <a href="http://slowbootkernelhacks.blogspot.kr/2017/03/efficient-linux-kernel-4x-programming.html">http://slowbootkernelhacks.blogspot.kr/2017/03/efficient-linux-kernel-4x-programming.html</a><br />
e) <a href="http://slowbootkernelhacks.blogspot.kr/2017/04/linux-device-driver-programming-using.html">http://slowbootkernelhacks.blogspot.kr/2017/04/linux-device-driver-programming-using.html</a><br />
<br />
<br />
<span style="font-size: large;">7) <b><a href="https://developer.android.com/things/hardware/pico.html">NXP PICO-IMX6UL</a></b></span> - Freescale(NXP) i.MX6UL(Cortex-A7) 528Mhz, <a href="http://www.wandboard.org/">hobbitboard</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1z_ASLFg7-4n1OwOFq2AZNCJF6sqHclKXT9-nVg8AQgIbFpcqC9e5jTHZiKLGzVvIPYgAo_LHXCQvz4GYbc00JHLWUxldBU6kOIvdyte7U8wGHw71JJugKiE6QijI6kjf8NAZlnWlICMP/s1600/NXP-Pico-Board.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1z_ASLFg7-4n1OwOFq2AZNCJF6sqHclKXT9-nVg8AQgIbFpcqC9e5jTHZiKLGzVvIPYgAo_LHXCQvz4GYbc00JHLWUxldBU6kOIvdyte7U8wGHw71JJugKiE6QijI6kjf8NAZlnWlICMP/s320/NXP-Pico-Board.jpg" width="320" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;"><a href="https://developer.android.com/things/sdk/index.html">Android things(Android 기반의 IoT)</a>를 지원하는 보드(이 밖에도 Google이 지원하는 Android things용 보드로는 <a href="https://developer.android.com/things/hardware/edison.html">Intel Edison</a>, <a href="https://developer.android.com/things/hardware/raspberrypi.html">Raspberry Pi 3</a> 등이 있음). Base board와 SOM board가 분리되어 있는 특징이 있음. Android 기반의 IoT를 생각하고 있다면 한번 써 보는 것도 좋을 듯 .. 근데, 아직은 Android things가 개발자 preview 상태인 듯 함(Brillo source를 내려 받았으나, build가 안됨).</span><br />
<span style="color: #0b5394;"><br /></span>
<br />
<span style="font-size: large;">8) <b><a href="http://www.banana-pi.org/r2.html">MediaTek BPI-R2</a></b></span> - MediaTek MT7623N Quad-core ARM Cortex-A7, 2GB DDR3, 8GB eMMC, 5 10/100/1000 Ethernet Ports<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEMFIBkpgphUPtrkePHWTP64OKTn_yKnPWZbhtPg2lVxyPGerHgCM8eSDT2HZCdkt4v7FGnBDtBawnfkwzenHtAdOfGiyTZvs9OELTSw1NBra1jmyWuWW1Oy0dQ_-DRMuMQ1iB0cQVQC8K/s1600/bpi_r2.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="185" data-original-width="273" height="216" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEMFIBkpgphUPtrkePHWTP64OKTn_yKnPWZbhtPg2lVxyPGerHgCM8eSDT2HZCdkt4v7FGnBDtBawnfkwzenHtAdOfGiyTZvs9OELTSw1NBra1jmyWuWW1Oy0dQ_-DRMuMQ1iB0cQVQC8K/s320/bpi_r2.jpeg" width="320" /></a></div>
<br />
<span style="color: #0b5394;"><특장점></span><br />
Wi-Fi AP를 만들어 보는 시험을 하기에 적합할 듯 하다. BSP가 OpenWrt 기반으로 되어 있다. 같은 회사에서 만든 <a href="http://www.banana-pi.org/r64.html">BPI-R64</a>도 괜찮아 보인다.<br />
<span style="color: #0b5394;"><br /></span>
<my postings><br />
a) <a href="https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-access-point.html">https://slowbootkernelhacks.blogspot.com/2020/05/openwrt-access-point.html</a><br />
<br />
<br /><span style="font-size: large;">9) <b><a href="https://www.st.com/en/evaluation-tools/stm32mp157c-dk2.html">ST STM32MP157C-DK2</a></b></span> - STM32MP157 ARM Cortex-A7(32 bit) + Cortex-M4(32 bit) MPU, ST PMIC STPMIC1, 4-Gbit DDR3L, 4" TFT 480x800 LCD, 5V/3A USB Type-C power supply ...<br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2iUvwwuugTRpJWZJkTXCFTSTzbr4a8lpZsZHOu4tLDPvQ5KdaZcdQTrSlONlgIQ_jgmwuTvhvpWsU1aBzoEAt9OPmmhquaouJTF3ryc8Ow-AgPzlq92HbUNt9HQipxi7C-NzpPoMsKEkV/s225/stm32mp157_dk2.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="225" data-original-width="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2iUvwwuugTRpJWZJkTXCFTSTzbr4a8lpZsZHOu4tLDPvQ5KdaZcdQTrSlONlgIQ_jgmwuTvhvpWsU1aBzoEAt9OPmmhquaouJTF3ryc8Ow-AgPzlq92HbUNt9HQipxi7C-NzpPoMsKEkV/" /></a></div><br /><font color="#4285f4"><span><특장점></span><br />ST의 장점을 살려 Cortex-M4 MPU(coprocessor)와 ARM Cortex-A7 MPU(main processor)를 하나로 통합하였으며, main processor에는 Yocto로 생성한 OpenSTLinux를 기본으로 탑재하고 있다. TFT LCD가 기본으로 장착되어 있어, GUI나 동영상 관련 app을 개발 & 실험하기에 적합하다. 뿐만아니라 (모양은 좀 허접해 보이지만) STM32 MPU wiki page의 내용이 아주 잘 정리되어 있어, 개발에 많은 도움이 될 것으로 보인다.</font><br /><span style="color: #0b5394;"><br /></span><my postings><br /><div>a) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded.html</a></div><div><br /></div><div>b) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_10.html</a></div><div><br /></div><div>c) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_16.html</a></div><div><br /></div><div>d) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_17.html</a></div><div><br /></div><div>e) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-driver-for-embedded_18.html</a></div><div><br /></div><div>f) <a href="https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html">https://slowbootkernelhacks.blogspot.com/2020/06/linux-device-drivers-for-embedded.html</a></div><div><br /></div>g) <a href="https://slowbootkernelhacks.blogspot.com/2020/07/linux-kernel-programming-gpio-interrupt.html">https://slowbootkernelhacks.blogspot.com/2020/07/linux-kernel-programming-gpio-interrupt.html</a><div><br /><br />
<b style="background-color: #a64d79;"><span style="color: white;">ARMv8-A Series(64 bits)</span></b><br /><span style="font-size: large;">10) <a href="https://developer.qualcomm.com/hardware/dragonboard-410c"><b>DragonBoard 410c</b></a></span> - Qualcomm Snapdragon 410, Quad-core ARM Cortex A53, 1.2GHz, 64bit capable<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz_s-a51nWJMDr3D3jXgL0boh8kkMnaOIR5zVysf0N38FT3i8widvJndQLYCHGI69fK29_lXSUYVPOVD21DiduwuxB_8Fazrt-v-_MaTJER2QU9FwRNcQAS1fe5wL0xEfDmgD9VGq1kl8G/s1600/dragonboard.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiz_s-a51nWJMDr3D3jXgL0boh8kkMnaOIR5zVysf0N38FT3i8widvJndQLYCHGI69fK29_lXSUYVPOVD21DiduwuxB_8Fazrt-v-_MaTJER2QU9FwRNcQAS1fe5wL0xEfDmgD9VGq1kl8G/s1600/dragonboard.jpg" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">휴대폰 시장의 최강자인 Qualcomm chip을 사용한다는 점... 관련 site의 내용이 그럭 저럭 잘 정리되어 있는 듯 보인다. 또한, ARM Cortex A53, 64bit라는 점도 특이점이다. <a href="http://www.96boards.org/">96board</a> !</span><br />
<br />
<br />
<span style="font-size: large;">11) <b><a href="https://www.pine64.org/">PINE64</a></b></span> - Allwinner A64, Quad-core ARM Cortex A53, 1.2GHz, 64bit capable<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcELxSriiez4icDa0mN7ULIDA6hxTACaxjBAdcieTbCACbny7IhhTEwx9KGPBlcA1-6UhXj5FZ7LY6wEMTyK-QKU4Bv1d78JDCX39xyBa1LJDbKk2Mnr1826DTaJwUzgdK-jafck2q9HNH/s1600/pine64.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="355" data-original-width="600" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcELxSriiez4icDa0mN7ULIDA6hxTACaxjBAdcieTbCACbny7IhhTEwx9KGPBlcA1-6UhXj5FZ7LY6wEMTyK-QKU4Bv1d78JDCX39xyBa1LJDbKk2Mnr1826DTaJwUzgdK-jafck2q9HNH/s400/pine64.png" width="400" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">Mobile application processor 중, 나름 강자인 Allwinner 사의 A64 chip을 사용하고 있으며, 아주 저렴한 가격($15 ~ $29)을 자랑한다. 주변 accessory 가격(예: 7인치 LCD가 $35.99)도 대부분 저렴한 편이다. 다양한 OS 즉, Armbian, Android, Remix(PC용 android), Windows IoT 등을 지원한다. 뿐만아니라 같은 chip으로 PINEBOOK이라는 매우 탐나는 노트북을 만들어 판매(주문하면 2달후 쯤에 받을 수 있는 듯)하고 있는데 가격이 $99(14인치 LCD 기준)이다.</span><br />
<span style="color: #0b5394;"><br /></span>
<my postings><br />
a) <a href="https://slowbootkernelhacks.blogspot.kr/2017/07/pine-a64-64-bit-arm-linux.html">https://slowbootkernelhacks.blogspot.kr/2017/07/pine-a64-64-bit-arm-linux.html</a><br />
<br />
<span style="font-size: medium;"><b><a href="https://www.pine64.org/?page_id=7147">ROCK64</a></b></span> - Rockchip RK3328, Quad-core ARM Cortex A53, 64bit, 4GB DDR3, USB 3.0<br />
같은 회사(Pine microsystems Inc.)에서 개발한 아래 보드도 관심이 간다.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBmo0GWIMbBhAND6eRaC4hN2CPlHDmZEi6vjoqqUoYg3hJHnutkep9V0AfJF7Bs0TMQUAF4y4UYSksYgqUWF7GG1QZUsyLmI2x31fd7CKWciqfHeYnvX7SWuUflq_QzLK8zQwaBdfA01F2/s1600/rock64.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="238" data-original-width="214" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBmo0GWIMbBhAND6eRaC4hN2CPlHDmZEi6vjoqqUoYg3hJHnutkep9V0AfJF7Bs0TMQUAF4y4UYSksYgqUWF7GG1QZUsyLmI2x31fd7CKWciqfHeYnvX7SWuUflq_QzLK8zQwaBdfA01F2/s200/rock64.png" width="179" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<span style="font-size: large;">12) <a href="https://www.kickstarter.com/projects/874883570/marvell-espressobin-board"><b>ESPRESSObin</b></a></span> - Marvell ARMADA 3700 chip, dual-core ARM Cortex A53, 1.2GHz, 64bit capable, <a href="http://espressobin.net/">Official website</a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9TP4PnUsBSnr6GA91AYUTThdtLma80ZV30Te5OF6eDq35hCSBj7E7hOG7SwZPwCyn38GpbiACEpxuu09WhxQjLloOm-gAmqABOKu9dqtIZia-9e0wsgpfFURZJN7Ri48L5ZKk-7lzIMri/s1600/espressobin.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9TP4PnUsBSnr6GA91AYUTThdtLma80ZV30Te5OF6eDq35hCSBj7E7hOG7SwZPwCyn38GpbiACEpxuu09WhxQjLloOm-gAmqABOKu9dqtIZia-9e0wsgpfFURZJN7Ri48L5ZKk-7lzIMri/s640/espressobin.png" width="640" /></a></div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">Marvell이 network에서 강점을 보인다고 할 수 있는데, Marvell chip을 사용하고 있다는 점이 장점이라면 장점임. 또한 앞서 소개한 SBC에 비해 <u><b>Router(Gateway)를 target</b></u>으로 한다는 점이 특이하다고 볼 수 있음. 물론 ARM Cortex A53, 64bit라는 점도 특이점임 ...</span><br />
<br />
<my postings><br />
a) <a href="https://slowbootkernelhacks.blogspot.com/2020/04/espressobin-wireguard-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/04/espressobin-wireguard-vpn.html</a><br />
<br />
<br />
<span style="font-size: large;">13) <b><span style="color: blue;"><a href="https://www.gl-inet.com/">Gl-iNet MV1000</a></span></b></span> - Marvell ARMADA 88F3720 chip, dual-core ARM Cortex A53, 1.0GHz, 64bit capable, <a href="https://www.gl-inet.com/products/gl-mv1000/">Official website</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiALVmKp-BnASeRL4ns5ua8W-V_JHdGcoFcLx0mtAzObW5fgMglnRgJKxZnu34ARL88QKyLJJwK3Jt591rHv5DGTUzXuxSBzIuAUzS_SMyGSwycrLQsAoM6XrA1XNxAkwB6wqKY2rcA7WSl/s1600/glinet_mv1000_2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="420" data-original-width="524" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiALVmKp-BnASeRL4ns5ua8W-V_JHdGcoFcLx0mtAzObW5fgMglnRgJKxZnu34ARL88QKyLJJwK3Jt591rHv5DGTUzXuxSBzIuAUzS_SMyGSwycrLQsAoM6XrA1XNxAkwB6wqKY2rcA7WSl/s200/glinet_mv1000_2.png" width="200" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<span style="color: #0b5394;"><특장점></span><br />
<span style="color: #0b5394;">ESPRESSObin board 보드와 거의 동일 spec의 완제품임. OpenWrt가 기본으로 탑재되어 있으나, Ubuntu를 올릴 수도 있음.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Q8tcwvYTCYgnpakAgNH-PBVxWSFozUjs73_0Gn1cFTmYKGeb_7LcggqVbLt6BR_iVPDgdqM4Tukaf88y18-Ukuvo_vDNoBc8iDHNiZ0QO7Fphr7v61ku85BcYZlJLhXQVw22KHPQ3X8R/s1600/mv1000_spec.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="203" data-original-width="1043" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9Q8tcwvYTCYgnpakAgNH-PBVxWSFozUjs73_0Gn1cFTmYKGeb_7LcggqVbLt6BR_iVPDgdqM4Tukaf88y18-Ukuvo_vDNoBc8iDHNiZ0QO7Fphr7v61ku85BcYZlJLhXQVw22KHPQ3X8R/s400/mv1000_spec.png" width="400" /></a></div>
<br />
<my postings><br />
a) <a href="https://slowbootkernelhacks.blogspot.com/2020/05/glinet-mv1000-softether-vpn.html">https://slowbootkernelhacks.blogspot.com/2020/05/glinet-mv1000-softether-vpn.html</a><br />
<br />
<br />
<span style="background-color: #ffd966;">=========================================================================================</span><br />
<br />
<br />
<br />
현재 예정은 이와 같으나, 상황(새로운 것, 사용해보고 싶은 것)에 따라 다른 board로 대체될 수 있음을 미리 밝힌다.<br />
<br />
<div class="separator" style="clear: both; text-align: right;">
</div>
<div class="separator" style="clear: both; text-align: right;">
</div>
<div class="separator" style="clear: both; text-align: right;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyGO1NXbO-ZfZ3Ri1zwfBSJkTu7UVv8ViyBwpZnJTY3eKrJMNcGGQYqsqAD9vM2LBgpMskBg8zOWPdeKY0M0WkY00RDNjwr02doIW_a1e2pVfkN-_M25x-G82motMNzXoCX3srytE7k2lR/s1600/slowboot3.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="128" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyGO1NXbO-ZfZ3Ri1zwfBSJkTu7UVv8ViyBwpZnJTY3eKrJMNcGGQYqsqAD9vM2LBgpMskBg8zOWPdeKY0M0WkY00RDNjwr02doIW_a1e2pVfkN-_M25x-G82motMNzXoCX3srytE7k2lR/s1600/slowboot3.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: right;">
Slowboot </div>
</div>Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com12tag:blogger.com,1999:blog-6346200245600677355.post-53163535860334010912020-05-04T16:14:00.002+09:002020-07-16T13:52:36.745+09:00ARM Mbed OS 위에 LoRaWAN 코드 올리기이번 posting에서는 머리도 식힐겸, 비 Linux OS인 <a href="https://www.mbed.com/en/platform/mbed-os/">ARM Mbed OS</a>를 이용하여 <span style="font-family: "arimo" , sans-serif; white-space: pre-wrap;"><a href="https://os.mbed.com/platforms/ST-Discovery-LRWAN1/">DISCO-L072CZ-LRWAN1 보드</a>에</span> <a href="https://lora-alliance.org/about-lorawan">LoRaWAN </a>코드를 올리는 과정을 소개해 보고자 한다. <i><span style="color: #666666;">오래 전에 Google Docs로 작성했던 내용인데, ARM Mbed OS 관련 기초편 정도로 보면 될 듯 하다.</span></i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA5b58QAiH71-OtxBTpYYJqCL6krP-XWSo0gFYEuIDNchjfnJesuAlxda8BR3XTLNgvDXIFmuHQ-1Q88wBJXraAjgg71YblxOqIouh-nHhF6OkhucOJW_nWNLnXvjPNYfNVMeVWlF0N0Hh/s1600/arm_mbed_os.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="141" data-original-width="357" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA5b58QAiH71-OtxBTpYYJqCL6krP-XWSo0gFYEuIDNchjfnJesuAlxda8BR3XTLNgvDXIFmuHQ-1Q88wBJXraAjgg71YblxOqIouh-nHhF6OkhucOJW_nWNLnXvjPNYfNVMeVWlF0N0Hh/s320/arm_mbed_os.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMJ8jUQDnq3wP_3pKoeNe4H1MmDlthz00O0_YvtcPTLA0ulYaF_5PaLQW7yXC3E4BLw-R4b06UKA3RrKQxX6J6JBbL4jz3UkMupn9A35Lb6O7HDwHEMZGs-zMwh0xu1w2Gl9kIHlGbcos/s1600/disco.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="247" data-original-width="204" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTMJ8jUQDnq3wP_3pKoeNe4H1MmDlthz00O0_YvtcPTLA0ulYaF_5PaLQW7yXC3E4BLw-R4b06UKA3RrKQxX6J6JBbL4jz3UkMupn9A35Lb6O7HDwHEMZGs-zMwh0xu1w2Gl9kIHlGbcos/s1600/disco.jpeg" /></a></div>
<br />
참고로 본 blog를 통해 이미 소개된 바 있는 RTOS는 다음과 같다.<br />
<br />
<b><span style="color: #b45f06;"><Zephyr Project></span></b><br />
<div style="text-align: center;">
<a href="https://slowbootkernelhacks.blogspot.com/2017/03/zephyr-project.html">https://slowbootkernelhacks.blogspot.com/2017/03/zephyr-project.html</a></div>
<div style="text-align: center;">
<br /></div>
<div style="text-align: left;">
<b><span style="color: #b45f06;"><RIOT OS></span></b></div>
<div style="text-align: center;">
<a href="https://slowbootkernelhacks.blogspot.com/2017/03/riot-os.html">https://slowbootkernelhacks.blogspot.com/2017/03/riot-os.html</a></div>
<div style="text-align: center;">
<br /></div>
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="background-color: transparent; font-family: "pt sans narrow" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: large;">Contents</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>1. ARM Mbed OS 소개</i></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "lora" , serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>2. Mbed CLI w/ STM32 Nucleo F103RB</i></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "lora" , serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>3. Mbed Studio</i></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "lora" , serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>4. Mbed Online Compiler</i></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>5. DISCO-L072CZ-LRWAN1 보드</i></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><i>6. LoRaWAN의 (진짜^^)모든 것</i></span></div>
<b id="docs-internal-guid-179b9972-7fff-17ab-f942-cab2be6f534d" style="font-weight: normal;"><br /><br /><br /><span style="color: #ff5e0e; font-family: "arimo" , sans-serif; font-weight: 700; white-space: pre-wrap;"><span style="font-size: x-large;">1. ARM Mbed OS 소개</span></span></b><br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ARM Mbed OS(이하 Mbed OS로 통칭)는 FreeRTOS(</span><a href="https://www.freertos.org/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://www.freertos.org/</span></a><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">), Zephyr(</span><a href="https://www.zephyrproject.org/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://www.zephyrproject.org/</span></a><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 등과 견줄만한 open source IoT OS 이다(ARM 사가 밀고 있어 파급력이 매우 큰 느낌이다. 그래서 선택했다^^). Security, Connectivity, RTOS 적인 특징을 갖추고 있으며, 주로 ARM Cortex-M micro controller에 탑재하는 용도로 사용할 수 있다. 따라서 Arduino(AVR 계열) 등에 올리기에는 좀 덩치가 크다고 볼 수 있다~</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 360px; overflow: hidden; width: 539px;"><img height="360" src="https://lh4.googleusercontent.com/rMmTQ3PSVBhvL8VdC6zmInZ5baNRKlq-8d7qDMm_w--7QmOaSPrvBfNQRNPYPzYruYnDAXcnCiHPM_WylJ2R7WzH_HghuuMhxAFSqPIh-wGQ7KxojziVQaPvX-ThYmM9pnawpzY" style="margin-left: 0px; margin-top: 0px;" width="539" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.1] ARM Mbed OS home page</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS가 활용되는 분야는 매우 다양하다. 이를 확인해 볼 수 있는 site가 아래에 있으니 </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">한번 훑어 보시기 바란다. 재밌는 내용이 아주 많다~</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://www.mbed.com/built-with-mbed/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://www.mbed.com/built-with-mbed/</span></a></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 430px; overflow: hidden; width: 513px;"><img height="430" src="https://lh3.googleusercontent.com/L2SuUHWDL8dQZNFu6p2xwjpPGDPDxFbp1yelX9vNCMhmgXQwWJM26QlR6-wFlWeLy316yWLukXZE9MLFaWHUgK8DasmonPfL8MX-ctpunhn2WILUwSTtVpGpXk_A8I0YCYsfOY8" style="margin-left: 0px; margin-top: 0px;" width="513" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.2] ARM Mbed OS가 사용된 다양한 예</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">가 갖고 있는 가장 </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">큰 장점</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">은 뭐니 뭐니 해도 </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">다양한 connectivity 환경을 지원</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">한다는 점이 아닐까 싶다. </span><span style="color: #cccccc;"><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">이 중 우리는</span><span style="background-color: transparent; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> LoRaWAN</span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">에 관심이 큰 만큼 앞으로 이 부분을 집중적으로 살펴 보아야 할 것이다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 204px; overflow: hidden; width: 368px;"><img height="204" src="https://lh4.googleusercontent.com/zZhC51RRh8gxpbZvut-zTRMJfkmuzvXsvKwesaTuLhb-b8wUHMT-dZUzaIwUsGWU1iASSVfnIl3ZFL_AcnWtki6BvKlBxNuFVpyu_oLBN_nFJIaV9K-mPPOeaoD_lJ75Ivg5FCA" style="margin-left: 0px; margin-top: 0px;" width="368" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.3] ARM Mbed OS Connectivity</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS의 전체 architecture는 다음과 같다. 이와 관련해서는 추후 하나씩 세세하게 뜯어 보아야 할 것이다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 275px; overflow: hidden; width: 579px;"><img height="275" src="https://lh6.googleusercontent.com/xnpXV-WR2Ajp6WfI7f0ayONbe0KlhAFX16tCpNtO1aRGg1Z5zGtYu9m5BFK60TLLQFfUlGxygWLPrh9SLwLy6rsZ14uVW81ivNAIP5IG636ZBYrooaLnlmzYmvlWwPhYNg9Ln7I" style="margin-left: 0px; margin-top: 0px;" width="579" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.4] ARM Mbed OS Architecture</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">먼저, </span><span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS를 사용하기 전에 자신의 계정을 등록</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(그림 1.1의 아래 버튼 선택) 하도록 하자. 계정 등록 방법은 아주 간단한 사항이라 여기서는 별도로 정리하지는 않겠다. 각자 시도해 보기 바란다~</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 64px; overflow: hidden; width: 325px;"><img height="64" src="https://lh4.googleusercontent.com/bnGSA2Ee--OH7651NokpVibYX3bak6_PCyIMsgdihkorOCq9kRaiCk_Yf-q6SBueiqxMO-BsGGFRJObH4Ys3SJUJQgFVZhu1QnxZiYqK0ojgaHXFRP6JnVXFkiUT9rElCaF_0_Q" style="margin-left: 0px; margin-top: 0px;" width="325" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.5 계정 등록 버튼]</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">참고: Mbed OS 사용자 계정은 Mbed Studio, Mbed Online Compiler 사용시 반드시 필요하다.</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 246px; overflow: hidden; width: 342px;"><img height="246" src="https://lh6.googleusercontent.com/MenT13OflDJHmq5NgotQS806PpTaaONjNnPJFZV3OLU_9MkocXNzbpnqfA4_Ryh5cXP4sP0m8k40kOuJuDTPiYgRFawCbkl5QrZsC79VJo4ZS3B92YIkJv1aMxqp6ZWsFJFy_gw" style="margin-left: 0px; margin-top: 0px;" width="342" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.6] Mbed OS 계정 등록 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Mbed OS 교육 과정></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">국내 ARM 교육 기관에서 시행하는 </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS 교육 과정</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">을 참고삼아 정리해 보았다. 앞으로 이런 정도의 내용을 파악해야 한다는 야그^^</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: #ff5e00; color: white; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> 1 일차 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">1. Open-source Hardware Platform</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> - Open source hardware 소개</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed 소개</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed를 이용한 개발 사례 소개</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">2. ARM Processor</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Arm Processor 소개</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Arm Processor 종류</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Arm Interrupt Controller (GIC, NVIC)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Arm SysTick Timer</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - STM32 Cube & Hal Library </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Discussion</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">3. Mbed</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Mbed ?</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed 개발환경 소개</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed 프로그래밍 흐름</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed 시작하기 : 웹컴파일러를 이용한 예제 빌드 및 실행</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed CLI : 환경 설정 및 예제 빌드 및 실행</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed Studio 설치 및 기본예제 실행</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: #ff5e00; color: white; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> 2 일차 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">4. Mbed DataType</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed 데이터형 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed.h 분석</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">5. Peripheral 이론 및 실습</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - GPIO (LED, Button)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - GPIO BusOut (7Segment)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Analog Input/Output (가변저항, LED)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Timer & Interrupt</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - PWM (LED, Brightness)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - I2C (STM Sensor Hub Control)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - SPI (SD Block Driver)</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - QSPI, Little FileSystem</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Watchdog & ResetReason</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - MbedCRC</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: #ff5e00; color: white; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> 3 일차 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">6. Mbed-OS</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - RTOS</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Thread</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Mutex</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Semaphore</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Queue</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os MemoryPool</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Mail</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os EventFlags</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os ConditionVariable</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os RtosTimer</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: #ff5e00; color: white; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> 4 일차 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os EventQueue 인터럽트 처리</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os EventQueue Shared Event</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Event</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed-os Callback</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">7. Mbed-OS Configuration System</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - configuration parameter 정의</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed_lib.json 분석</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - mbed_app.json 분석</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: #ff5e00; color: white; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> 5 일차 </span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">8. Pelion Device Management</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Pelion Service ?</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - LWM2M</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 0pt; margin-top: 0pt; padding: 0pt 0pt 21pt 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - Pelion 계정생성</span></span></div>
<div dir="ltr" style="background-color: white; line-height: 1.3800000000000001; margin-bottom: 21pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #666666; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> - DISCO_L475E_IOT01A 보드를 사용하여 Pelion 연결하기</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">교육 기관에 불필요하게 돈을 기부(?)할 필요는 없다. 적당한 개발 보드를 하나 구입한 후, 아래 책 정도를 보면서 study를 진행하는 것으로 충분하다 :) </span><span style="background-color: transparent; color: #85200c; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">사실 Mbed OS와 같은 RTOS ~ 그렇게 어렵지 않다 ?! 그냥 하는 소리가 아니다 :) Linux가 (상대적으로) 훨씬 어렵다...</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 255px; overflow: hidden; width: 196px;"><img height="255" src="https://lh3.googleusercontent.com/tHJ7qTrTjl_z5j0CZZexzhTln-RhfvmVSuXLswEnK_AGa7VodfA0b_0oaisg8cBcwj9E-Yx9PSyD4xqkUlIuY9JtdjDFn_tJLFBUC76kJlcDEiZe4IjL7OgttKBEnlnCueFGZBI" style="margin-left: 0px; margin-top: 0px;" width="196" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 1.7] 참고 도서</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="font-size: x-large;"><span style="background-color: transparent; color: #ff5e0e; font-family: "pt sans narrow" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">2. Mbed CLI w/STM32 Nucleo F103RB</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed OS 환경에서 firmware를 개발하는데 사용되는 도구로는 "</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed Studio</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">”, “</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed Online Compiler</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">”, “</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed CLI</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">” 세 종류가 있다. 이를 하나씩 하나씩 사용해 보기로 하자.</span></div>
<div style="text-align: justify;">
<b style="font-weight: normal;"><br /></b></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">먼저, 이번 절에서는 (linux 개발자를 위해)Mbed OS CLI를 이용하여 sample code(mbed-os 포함)를 build하는 과정을 소개해 보기로 하겠다. 동작 시험을 위해서는 아래 </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">STM32 Nucleo-F103RB</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 보드를 사용하였다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">"Mbed CLI 만 있어도 개발하는데 아무런 문제가 없다 - chunghan.yi@gmail.com”</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 160px; overflow: hidden; width: 165px;"><img height="160" src="https://lh5.googleusercontent.com/OYvphwtZ5xsB9oB5nupaCyTuK7fv4_gv5JQz9pZdRQ6WBOYCPJzE-FYFrHwz6E2zEvU5eW81Ek5pQ3dob7KLRwOYWNDtbzOAPEDBHzzSvBpkChqATsfombZi64HhRi42BvzF50o" style="margin-left: 0px; margin-top: 0px;" width="165" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.1] mbed CLI</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 192px; overflow: hidden; width: 262px;"><img height="192" src="https://lh4.googleusercontent.com/-nUl-645i9YHB7w9xkD_4MWoBKnNVz5P17KLt4m73TD2BjsghopK6dzQqQVGplg-L2qMehlbAM7d07nlqMyjtHdoBQIp98ywM5KMpH8Uu0v46rFxdrC_CcK_rKWVkWhADInTI2Y" style="margin-left: 0px; margin-top: 0px;" width="262" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.2] Nucleo F103RB 보드</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/platforms/ST-Nucleo-F103RB/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/platforms/ST-Nucleo-F103RB/</span></a></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">참고: Nucleo F103RB 보드는 가격이 저렴(만원이 조금 넘음)하다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a) Ubuntu 18.04에 Mbed CLI 설치하기</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">지금부터 설명하는 내용은 Ubuntu 18.04 desktop을 기준으로 하며, 아래 site의 내용을 기초로 하였다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/docs/mbed-os/v5.14/tools/manual-installation.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/docs/mbed-os/v5.14/tools/manual-installation.html</span></a></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Install dependencies></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sudo apt install python2.7 python-pip git mercurial</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">보통 이정도는 이미 설치되어 있다. 혹시 설치 되어 있지 않다면, 각자 설치하기 바란다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Install Mbed CLI></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">pip install mbed-cli</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Mbed CLI는 python으로 구현되어 있다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed --help</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">mbed가 정상적으로 설치되었는지를 확인하기 위해 위의 명령 실행</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Install a compiler></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<a href="https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads</span></a></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">헐, 여기서는 download할 수 가 없군...</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><a href="https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads">https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads</a></span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">그럼 여기서 받도록 하자.</span></li>
<li><span style="color: #695d46; font-family: "open sans" , sans-serif; white-space: pre-wrap;">gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">참고: ARM Mbed OS를 build하기 위해 사용 가능한 compiler로는 </span><a href="https://os.mbed.com/docs/mbed-os/v5.14/tools/index.html#compiler-versions" style="text-decoration: none;"><span style="background-color: white; color: #4a97b7; font-family: "arial"; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GCC Arm, Arm Compiler 5, Arm Compiler 6 or IAR</span></a><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 등을 생각해 볼 수 있다. </span><span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">우리는 이중에서 open source인 GCC Arm compiler를 사용할 것이다.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 329px; overflow: hidden; width: 506px;"><img height="329" src="https://lh4.googleusercontent.com/gkHqa9iA8Xtttku2nQKJPAVAqsJ9mvnsbL6SYq8cwid1R8Nv3Xs24R-HqoMSsl7BGOPuRpqxCC2juKgPaq2MbFfFJjkZmUbBqaMoIHclCBd2vWRYCASOTG1GPU1iSijsAWaeGrA" style="margin-left: 0px; margin-top: 0px;" width="506" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.3] </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GNU-RM Downloads site</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd ~/workspace/MbedOS</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tar xvjf gcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sudo mv ./gcc-arm-none-eabi-9-2019-q4-major /opt</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">반드시 /opt 아래로 이동시켜야 하는 것은 아니다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vi ~/.bashrc</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">export MBED_GCC_ARM_PATH=/opt/gcc-arm-none-eabi-9-2019-q4-major/bin</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">export PATH=/opt/gcc-arm-none-eabi-9-2019-q4-major/bin:$PATH</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">~</span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">source ~/.bashrc</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">터미널을 다시 실행해도 된다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="color: #990000;"><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">참고</span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">이상의 내용은 (일반적으로) toolchain 설정시 공통적으로 수행하는 부분에 해당한다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 80px; overflow: hidden; width: 624px;"><img height="80" src="https://lh4.googleusercontent.com/QdGImpGugPa9ecluhbTLzP1Ef8ely7lE1PKQ7oLpsWIuui_bnx6MFgXTYtJ0piV0NqG5ijLheC5TgVhBUN1h4IifFCSIJuymL2Tc79jiUS5FF9q9WrKOlH8aj4LJaLeP8rIcEwg" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.4] ARM gcc version - gcc 9.2.1 버젼</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed config -G GCC_ARM_PATH /opt/gcc-arm-none-eabi-9-2019-q4-major/bin</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Mbed CLI가 arm compiler의 위치를 알 수 있도록 해 줌.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Bash completion></span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">mbed-cli bash completion(자동 완성 기능)을 설치하기 위해서는 아래 절차를 따른다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="color: #990000;"><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">참고</span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">bash completion은 bash 환경에서 명령 전체를 입력할 필요 없이 <TAB> 키를 사용하여 명령을 좀 더 편하게 입력하는 방식을 말한다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">git clone </span><a href="https://github.com/ARMmbed/mbed-cli" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://github.com/ARMmbed/mbed-cli</span></a></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Mbed-cli를 내려 받는다.</span></li>
</ul>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">'mbed-cli'에 복제합니다...</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">remote: Enumerating objects: 49, done.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">remote: Counting objects: 100% (49/49), done.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">remote: Compressing objects: 100% (39/39), done.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">remote: Total 3693 (delta 23), reused 26 (delta 9), pack-reused 3644</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">오브젝트를 받는 중: 100% (3693/3693), 1.31 MiB | 1.40 MiB/s, 완료.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">델타를 알아내는 중: 100% (2078/2078), 완료.</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cd mbed-cli/tools/bash_completion</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mkdir -p ~/.bash_completion.d/</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cp mbed ~/.bash_completion.d/</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">이후 터미널을 다시 실행해야 한다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">chyi@earth:~/workspace/MbedOS$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed config --list</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Global config:</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GCC_ARM_PATH=/opt/gcc-arm-none-eabi-9-2019-q4-major/bin</span></div>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Local config (/home/chyi/workspace/MbedOS):</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Couldn't find valid mbed program in /home/chyi/workspace/MbedOS</span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">b) LED Blinky 예제 코드 돌려 보기</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 346px; overflow: hidden; width: 504px;"><img height="346" src="https://lh5.googleusercontent.com/2RkkwgVeYtyT-7WZWOBf1SM6sAeUp0L_1CSfVhFln2WLjWIrbbFrDeNHql8uPmmAAiG6G49giqHFa3vN0neRtKmWXBSaWAj9d6VvVwEsO-GxlqLbh8sjbIyINQtCI8NElivNo4o" style="margin-left: 0px; margin-top: 0px;" width="504" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.5] mbed-os 예제 코드(1)</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 460px; overflow: hidden; width: 529px;"><img height="460" src="https://lh5.googleusercontent.com/zCaY-U_OrUD--it8tIqoF9TqvXLpdzePHB-bX5_FNvx6PDa-0GXvsdJ_Kdk96j8dgjKyaefjz9llzwdMbb4k5J6c1x-dikGEA6B13sbVdBpYKnn0meY-hXKpgPIfetAnyh5rJls" style="margin-left: 0px; margin-top: 0px;" width="529" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.6] mbed-os 예제 코드(2)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd ~/workspace/MbedOS</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ mkdir projects; cd projects</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed import https://github.com/ARMmbed/mbed-os-example-blinky#mbed-os-5.11.0</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Working path "/home/chyi/workspace/MbedOS/projects" (directory)</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Importing program "mbed-os-example-blinky" from "https://github.com/ARMmbed/mbed-os-example-blinky" at branch/tag "mbed-os-5.11.0"</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at rev #6a0a86538c0b</span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cd mbed-os-example-blinky</span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ ls -la</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">합계 52</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 4 chyi chyi 4096 12월 14 17:27 .</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 6 chyi chyi 4096 12월 14 17:27 ..</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 8 chyi chyi 4096 12월 14 17:27 .git</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 32 12월 14 17:27 .gitignore</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 7 12월 14 17:27 .mbed</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 5942 12월 14 17:27 README.md</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 522 12월 14 17:27 main.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 18 chyi chyi 4096 12월 14 17:27 mbed-os</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 77 12월 14 17:27 mbed-os.lib</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 354 12월 14 17:27 mbed_app.json</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 1339 12월 14 17:27 mbed_settings.py</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 3699 12월 14 17:27 stats_report.h</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 344px; overflow: hidden; width: 551px;"><img height="344" src="https://lh5.googleusercontent.com/z20IldTtBVM28cz3RANs7fLKr0-fzyF2D8cMRuKvyD1uIkws93qypN-HQfSUfzZVpNwF_6OWM8xq573YDMzR4DCeX1COqsGtiHASeGJfQOdFv-yXUgZWetarIqX1qXx71vENVvg" style="margin-left: 0px; margin-top: 0px;" width="551" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.7] LED blinky 예제 코드 - main.cpp</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -m K64F -t GCC_ARM</span></div>
<ul>
<li><span style="color: #695d46; font-family: "open sans" , sans-serif; white-space: pre-wrap;">-m: target board, -t: toolchain</span></li>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">NXP K64F board(가격: $35정도 함)는 아래 그림과 같이 생겼는데, 여기서는 이 board에 올릴 수 있는 firmware image를 생성해 보도록 해 보겠다.</span></li>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">참고: mbed OS 문서 내용이 이 보드를 기준으로 설명되어 있다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 182px; overflow: hidden; width: 217px;"><img height="182" src="https://lh3.googleusercontent.com/reNwHXr081PVyoOV_jOJh0rDm66_ICl0lTk_yPbV6Yy7rXso0xohttzdDzYUSLRrh5OPPuwtS6M7jNXIR_mpg7LbfYbciDvO7zR3QNzY1emIC5CJERJHJblWoxXhlC2wM4xHLyQ" style="margin-left: 0px; margin-top: 0px;" width="217" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.8] NXP FRDM-K64F 보드</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/MbedOS/projects/mbed-os-example-blinky" (program)</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Building project mbed-os-example-blinky (K64F, GCC_ARM)</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Scan: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.1%]: except.S</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.3%]: mbed_tz_context.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.4%]: rf_configuration.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] rf_configuration.c@104,25: comparison of integer expressions of different signedness: 'uint32_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.5%]: MCR20Drv.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.7%]: mbed_fault_handler.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.8%]: at24mac.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.9%]: psa_prot_internal_storage.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.1%]: fslittle_test.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.2%]: fsfat_test.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.3%]: pits_impl.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.5%]: main.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.6%]: FlashIAPBlockDevice.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.7%]: AnalogIn.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 1.9%]: NanostackRfPhyMcr20a.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.0%]: SDBlockDevice.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] SDBlockDevice.cpp@794,24: this statement may fall through [-Wimplicit-fallthrough=]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.2%]: NanostackRfPhyAtmel.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.3%]: NanostackRfPhys2lp.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.4%]: BusIn.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.6%]: CAN.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.7%]: BusInOut.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 2.8%]: ESP8266.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] mbed_error.h@52,55: left shift of negative value [-Wshift-negative-value]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] mbed_error.h@52,55: left shift of negative value [-Wshift-negative-value]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 3.0%]: BusOut.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 3.1%]: Ethernet.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">...[중간 생략]...</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.6%]: sleep.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.7%]: i2c_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.9%]: fsl_common.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [100.0%]: rtc_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Link: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Elf2Bin: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Module | .text | .data | .bss |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">|--------------------|---------------|-------------|-------------|</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [fill] | 160(+160) | 4(+4) | 2122(+2122) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/c.a | 32042(+32042) | 2472(+2472) | 89(+89) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/gcc.a | 3104(+3104) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/misc | 180(+180) | 4(+4) | 28(+28) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/nosys.a | 32(+32) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/stdc++.a | 4(+4) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| main.o | 906(+906) | 0(+0) | 12(+12) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/cmsis | 1033(+1033) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/components | 210(+210) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/drivers | 633(+633) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/features | 156(+156) | 0(+0) | 192(+192) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/hal | 2311(+2311) | 8(+8) | 152(+152) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/platform | 4507(+4507) | 260(+260) | 226(+226) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/rtos | 9379(+9379) | 168(+168) | 6029(+6029) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/targets | 9235(+9235) | 12(+12) | 382(+382) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Subtotals | 63892(+63892) | 2928(+2928) | 9232(+9232) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Static RAM memory (data + bss): 12160(+12160) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Flash memory (text + data): 66820(+66820) bytes</span></span></div>
<span style="font-size: x-small;"><br /></span>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Image:</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ./BUILD/K64F/GCC_ARM/mbed-os-example-blinky.bin</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd BUILD/</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ ls -la</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">합계 12</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 12월 14 17:28 .</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 12월 14 17:28 ..</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 12월 14 17:28 GCC_ARM</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">chyi@earth:~/workspace/MbedOS/projects/mbed-os-example-blinky/BUILD/K64F$ cd GCC_ARM/</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">chyi@earth:~/workspace/MbedOS/projects/mbed-os-example-blinky/BUILD/K64F/GCC_ARM$ ls -la</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">합계 5728</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 12월 14 17:28 .</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 3 chyi chyi 4096 12월 14 17:28 ..</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 13879 12월 14 17:28 .includes_90b1235f63435861e0c680c5463f9e2f.txt</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 0 12월 14 17:28 .includes_d41d8cd98f00b204e9800998ecf8427e.txt</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 62218 12월 14 17:28 .link_options.txt</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 4526 12월 14 17:28 .link_script.ld</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 356 12월 14 17:28 .profile-asm</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 2687 12월 14 17:28 .profile-c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 2729 12월 14 17:28 .profile-cxx</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 2634 12월 14 17:28 .profile-ld</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 10111 12월 14 17:28 main.d</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 62912 12월 14 17:28 main.o</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">drwxr-xr-x 11 chyi chyi 4096 12월 14 17:28 mbed-os</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">-rwxr-xr-x 1 chyi chyi 67552 12월 14 17:28 </span><span style="background-color: transparent; color: #85200c; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed-os-example-blinky.bin ⇐ 얘가 실제 board에 탑재될 firmware 이미지 파일임.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rwxr-xr-x 1 chyi chyi 1548092 12월 14 17:28 mbed-os-example-blinky.elf</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 3946951 12월 14 17:28 mbed-os-example-blinky.map</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 2227 12월 14 17:28 mbed-os-example-blinky_map.csv</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 44670 12월 14 17:28 mbed-os-example-blinky_map.html</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 3935 12월 14 17:28 mbed-os-example-blinky_map.json</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">-rw-r--r-- 1 chyi chyi 46172 12월 14 17:28 mbed_config.h</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">c) Nucleo F103RB 보드에 mbed-os(firmware) 올리기</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(개인적으로) mbed-os를 지원하는 STM32 </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Nucleo F103RB 보드</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">가 하나 있어, 여기에 mbed-os를 올려 보도록 하겠다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd ~/workspace/new_boards/MbedOS/mbed-os-example-blinky</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed target NUCLEO_F103RB</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Target을 지정한다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">or</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed target detect</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">특정 target 명을 알 수 없을 경우, 이렇게 할 수도 있다.</span></li>
</ul>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-blinky" (program)</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] detect now set as default target in program "mbed-os-example-blinky"</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed toolchain GCC_ARM</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Toolchain을 지정한다. 이렇게 지정하는 이유는 compile 시 일일히 지정하지 않기 위함이다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> mbed compile -c</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">clean build를 한다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -f</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">flash writing을 한다.</span></li>
</ul>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-blinky" (program)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] Detected "</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">NUCLEO_F103RB</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">" connected to "/media/chyi/NODE_F103RB" and using com port "</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/dev/ttyACM0</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">"</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] @,: Compiler version mismatch: Have 9.2.1; expected version >= 6.0.0 and < 7.0.0</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Building project mbed-os-example-blinky (NUCLEO_F103RB, GCC_ARM)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Scan: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Link: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Elf2Bin: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Module | .text | .data | .bss |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">|--------------------|-----------|----------|----------|</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [fill] | 92(+0) | 12(+0) | 32(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/c.a | 27650(+0) | 2472(+0) | 89(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/gcc.a | 4152(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/misc | 208(+0) | 12(+0) | 28(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| main.o | 918(+0) | 4(+0) | 36(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/cmsis | 1033(+0) | 0(+0) | 84(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/components | 70(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/drivers | 855(+0) | 4(+0) | 100(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/features | 172(+0) | 4(+0) | 192(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/hal | 2067(+0) | 4(+0) | 68(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/platform | 4027(+0) | 260(+0) | 210(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/rtos | 8100(+0) | 168(+0) | 5969(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/targets | 6774(+0) | 4(+0) | 368(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Subtotals | 56118(+0) | 2944(+0) | 7176(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Static RAM memory (data + bss): 10120(+0) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Flash memory (text + data): 59062(+0) bytes</span></span></div>
<span style="font-size: x-small;"><br /></span>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Image: ./BUILD/NUCLEO_F103RB/GCC_ARM/mbed-os-example-blinky.bin</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">자, flash writing에 성공하였다. F103RB 보드에 LED가 1초 간격으로 깜빡거린다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 354px; overflow: hidden; width: 472px;"><img height="354" src="https://lh5.googleusercontent.com/7-5hcM-U5RmE1_-DUxuldK33nUQf_4_JgTUs2TvTkR_WFQRig-s7Q8rjgrdHa-bg6UzLtEiSGbWcei9DgOzDLHk1nyhPl9Ow-QD50H3lJ381B2Ojouc0UWRjeSZAfmdjS35Z9L8" style="margin-left: 0px; margin-top: 0px;" width="472" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.9] Nucleo F103RB 보드에 firmware(mbed-os)를 올린 모습 - 가운데 녹색 LED blinking 중</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -f --sterm</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Minicom 등과 같은 serial console emulator를 통해 board 상태를 확인하기 위해 설정해 준다.</span></li>
</ul>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-blinky" (program)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Detected "NUCLEO_F103RB" connected to "/media/chyi/NODE_F103RB" and using com port "/dev/ttyACM0"</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] @,: Compiler version mismatch: Have 9.2.1; expected version >= 6.0.0 and < 7.0.0</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Building project mbed-os-example-blinky (NUCLEO_F103RB, GCC_ARM)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Scan: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Link: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Elf2Bin: mbed-os-example-blinky</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Module | .text | .data | .bss |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">|--------------------|-----------|----------|----------|</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [fill] | 92(+0) | 12(+0) | 32(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/c.a | 27650(+0) | 2472(+0) | 89(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/gcc.a | 4152(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/misc | 208(+0) | 12(+0) | 28(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| main.o | 918(+0) | 4(+0) | 36(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/cmsis | 1033(+0) | 0(+0) | 84(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/components | 70(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/drivers | 855(+0) | 4(+0) | 100(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/features | 172(+0) | 4(+0) | 192(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/hal | 2067(+0) | 4(+0) | 68(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/platform | 4027(+0) | 260(+0) | 210(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/rtos | 8100(+0) | 168(+0) | 5969(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/targets | 6774(+0) | 4(+0) | 368(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Subtotals | 56118(+0) | 2944(+0) | 7176(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Static RAM memory (data + bss): 10120(+0) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Flash memory (text + data): 59062(+0) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Image: ./BUILD/NUCLEO_F103RB/GCC_ARM/mbed-os-example-blinky.bin</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sudo minicom -s</span></div>
<ul>
<li><span style="color: #695d46; font-family: "open sans" , sans-serif; white-space: pre-wrap;">/dev/ttyACM0, 115200, 8N1</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 449px; overflow: hidden; width: 450px;"><img height="449" src="https://lh6.googleusercontent.com/WOJaLIr6zG_23TQigWa1sbqVc3XPNbdXzWBW6Irv8vhurKnjAtD96dwyKOwXefIwdqX16prIN4foGO6sar00E_u4A_P8DnB9UOKxe8QuQdu2WuFAvc0egq8jakbNpLviYULllyQ" style="margin-left: 0px; margin-top: 0px;" width="450" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 2.10] Nucleo F103RB 보드 - minicom 설정</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">어떤가 ? 간단하지 않은가 ?</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="background-color: transparent; color: #ff5e0e; font-family: "pt sans narrow" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-large;">3. Mbed Studio</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Mbed Studio는 MS Visual Studio 처럼 IDE 환경에서 개발하고자 할 때 설치하여 사용한다. 현재는 Windows & MacOS 만을 지원한다. Linux 개발자라면 Mbed CLI를 이용하면 된다. 따라서 본 문서에서는 Mbed Studio 설치 과정만 간단히 정리해 보았다. 나머지 build 이후의 작업은 직접 해 보시길~</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/studio/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/studio/</span></a></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 300px; overflow: hidden; width: 435px;"><img height="300" src="https://lh6.googleusercontent.com/F0SH56H_X1l3HvhjJBO6RgDpwagvsQ8XT9T8VxbeBww3JSPgCBh9JyvHzu2e1p_FriK6gVEExIOx42oBgDR3ihq4Rx2FFv86GYriRdnIrtvUOlcHU2o3sNvpWoUNTlAopLsLtRA" style="margin-left: 0px; margin-top: 0px;" width="435" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 3.1] Mbed Studio 설치 Page</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">그럼, 이제 부터 Windows 10에 설치해 보도록 하겠다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 271px; overflow: hidden; width: 347px;"><img height="271" src="https://lh6.googleusercontent.com/7NbirS6-LW-xhYLyQTycSaRMEl9bod3RYdO-pQAbeBP-6BdTOCHHH29OT2xvbPhInVc4dUwRiVMWfmtLq4v8Z1XHJgv-6azhRPPNnqw0OjRtYZDlA4NkNjTpgYR_VumxnPHEyJg" style="margin-left: 0px; margin-top: 0px;" width="347" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 3.2] Mbed Studio 설치 과정(1)</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 272px; overflow: hidden; width: 349px;"><img height="272" src="https://lh4.googleusercontent.com/VjkosqyEY4ioQbkaVe1_u4OFEWfRiYcOzYV3Z7nrrVHpeQh7ZmIfPwZ_Ka9ibXnrnIqNF1wiBp7ORKmqsRAMshtJVZ2BKyCsoOJmxOHp_3e9EEUOX3YdM5Mb7F79I_m9sssjlVw" style="margin-left: 0px; margin-top: 0px;" width="349" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 3.3] Mbed Studio 설치 과정(2)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 290px; overflow: hidden; width: 513px;"><img height="290" src="https://lh6.googleusercontent.com/Ecalv4LLt9lW_Oi5vXCW3IvU8cPxgx8g87cnscgVFqUto6WBAMi_jAENiBkEl1bojklqFm9WZvZxsxjhst9sWwAzHigSl4_QDar45qag-NoRTHZdGHaThqbj-0B7dJQIApZ9fvc" style="margin-left: 0px; margin-top: 0px;" width="513" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 3.4] Mbed Studio 설치 과정(3) - 1장에서 등록한 사용자 계정 사용</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 371px; overflow: hidden; width: 624px;"><img height="371" src="https://lh5.googleusercontent.com/NNni36M-Gq8ypvgY2uFJLuestRim0-_r4hVgyOeyAjtMAfU8b9HYlF7cAIkcH9J5_k1o8MW4zWjxcWSH4Vhzb_frLB1PiAvh3FUr3hWw9NvU1IVpyU8-vgIa2qdSOFZ0PneAbAo" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 3.5] Mbed Studio 실행 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Example code를 내려 받아 build해 보자. 어렵지 않으니 이부분은 독자 여러분의 몫으로 돌리겠다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="background-color: transparent; color: #ff5e0e; font-family: "pt sans narrow" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-large;">4. Mbed Online Compiler</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">지금 부터는 Mbed Online Compiler를 사용하여 firmware를 개발하는 방법을 소개해 보도록 하겠다. </span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Web을 통해 개발을 할 수 있는 아주 편리한 방법이다 :)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/docs/mbed-os/v5.14/quick-start/online-with-the-online-compiler.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/docs/mbed-os/v5.14/quick-start/online-with-the-online-compiler.html</span></a></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 274px; overflow: hidden; width: 399px;"><img height="274" src="https://lh6.googleusercontent.com/M9uUPVYP-RS2OATlKYLVZTi1tJaXVnIrwt_MXSxKBw-gbYtESNUNi4uReEb8PnExJFuyn6Ekkndb6YNaP9iLAHHFcWd98tAbDfEBZseKiltqgG6UAWlcH00iFVvbnS5Y3s-ZovQ" style="margin-left: 0px; margin-top: 0px;" width="399" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 4.1] Mbed OS Online Compiler - 사용하려는 보드 선택(검색)(1)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 290px; overflow: hidden; width: 419px;"><img height="290" src="https://lh5.googleusercontent.com/9AaMK0GkjuSkT9OPwwfiPeyc7grlnIoh-xDQtM5HHE8viijLb-beEUV9Vx9wI02ZdSWUX19TUserJ757nVd0IL_7sQyOVzpu3gJte_Kzt_cnnaJBbZWFgdgP_UpnuRKhgXDoB7c" style="margin-left: 0px; margin-top: 0px;" width="419" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 4.2] Mbed OS Online Compiler - 우측 "Add to your Mbed Compiler” 버튼 선택</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 316px; overflow: hidden; width: 458px;"><img height="316" src="https://lh4.googleusercontent.com/W3Iw7PvntIvrZitgW3tY97UuXgm9N-boLTza9AR8MiZoK7rMpZFNv-NFUvXFBBSvawR3znCdWJZY0X9G29rPYYGUR76uXLmh0tGE2QL2XOJH9uByz-2F3Ybt3P2Mi7n8qPmchGQ" style="margin-left: 0px; margin-top: 0px;" width="458" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 4.3] Mbed OS Online Compiler - 우측 "Open Mbed Compiler” 버튼 선택</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 337px; overflow: hidden; width: 489px;"><img height="337" src="https://lh5.googleusercontent.com/ziF_xFYAYTqdRHBEPEEIDznQff4N5hDgqiJYTRevjhGhwwxYIs7Cy86MYoLWfwkjx1ACS6sOOvtqFANYYvDqEXROjE0Y0pP9jIDOg9b740VfIUjsvs6BPG4g8FpKLbtlUy1XnWM" style="margin-left: 0px; margin-top: 0px;" width="489" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 4.4] Mbed OS Online Compiler 화면</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 311px; overflow: hidden; width: 451px;"><img height="311" src="https://lh4.googleusercontent.com/TLHBZCbI4ZebG-Q492diF77NeS75YroSq_XsLXdDAZY3dWXV9Us-jzYHjl32S4kFND8dkScuAgFV4vXyIQPDzlTvqOJjzsmZs2319yVXUUwM7Yeyx0_Fuj-ENusSZEohqondr3Q" style="margin-left: 0px; margin-top: 0px;" width="451" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 4.5] Mbed OS Online Compiler - Compile 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">참고: Compile이 정상적으로 완료되면 bin 파일이 자동으로 download 된다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><firmware writing하기></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Online compiler에서 compile하여 생성한 bin 파일을 Mbed 보드의 USB device folder로 복사한 후, reset 해 주면 된다.</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">F103RB 상에서 이렇게 했는데, 잘 안되는 것 같다(물론 LED Blinky code를 테스트해 봄)… 나중에 다시 시도해 보기로 하자.</span></li>
</ul>
<br />
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="background-color: transparent; color: #ff5e0e; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-large;">5. DISCO-L072CZ-LRWAN1 보드</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">이번 장에서는 DISCO_L072CZ-LRWAN1 보드에 lorawan firmware를 올려 보도록 하겠다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a) STM32 LoRa and Sigfox Discovery Kit</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/platforms/ST-Discovery-LRWAN1/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/platforms/ST-Discovery-LRWAN1/</span></a></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 421px; overflow: hidden; width: 569px;"><img height="421" src="https://lh5.googleusercontent.com/xvGJYh-E3qQT66UrtcJbbAiKsZE6XKom9kwLtD5fRWdUAbB9g2MHFARW1vZuCTt5TEsEVQuXjx-OLLwYciVT-JS2YfWvIsSoU3SByMp458MMwlgQVjrDGG_Ac6e9pn8ToLaQMR4" style="margin-left: 0px; margin-top: 0px;" width="569" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.1] DISCO_L072CZ-LRWAN1 보드</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: left;">
<span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://kr.mouser.com/ProductDetail/STMicroelectronics/B-L072Z-LRWAN1?qs=PzRbFReKxL2UVPVODSIYig%3D%3D&gclid=EAIaIQobChMI9bXag6m55gIVy2kqCh0uSAiwEAQYASABEgL7BPD_BwE</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">참고(가격): </span><span style="background-color: white; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">₩60,915 (좀 비싸다)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">아래에 Microcontroller(줄여서 micom)와 보드의 주요 특징을 열거해 보았다.</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 411px; overflow: hidden; width: 342px;"><img height="411" src="https://lh3.googleusercontent.com/3YIjZ3QZRVEmfM9O7rEX2WMQhd9Z-gXUug3fQeJwVJDDl-5mNHIfUmG47XV9vQWHPTRjJjHZl4kuaXDUr8UBtueptDP6_xcraa1sOlqpupCmrJn2m96SCrRMOn_gBY7HTAP2QzA" style="margin-left: 0px; margin-top: 0px;" width="342" /></span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 299px; overflow: hidden; width: 462px;"><img height="299" src="https://lh6.googleusercontent.com/yy8CuB-gWltB2ERWB30suQ-2ELr1QSD6J_X9cHFYN4fjXtLO52M8AGDdAP7Z5cpMVQjuxnwTrZQkxzZyUsb57h6rraEqGwXpyb5SBOKAV4NK3wENeqKOGmud0eOFaAIiSjFkmJ8" style="margin-left: 0px; margin-top: 0px;" width="462" /></span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">다음 4개의 그림은 실제 programming 시 중요한 부분(센서 연결시 필요)이라고 할 수 있는 확장 pin header에 대한 pin map 정보를 표현한 것이다.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 324px; overflow: hidden; width: 431px;"><img height="324" src="https://lh5.googleusercontent.com/VrgsulyJnGISy3H2ygmr1wbklhQy4p7g60uXXHCnQx0vMQk78kPt-vaUN05PJgQ_atv4UUDja9nnz_vrI6PpQc_HJhMKBaB2lUAJQw72tCM52WgiGYx2JX6M8uXI3ksdwo3Iu9g" style="margin-left: 0px; margin-top: 0px;" width="431" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.2] Arduino-compatible pin header(보드 top 왼쪽 pin - CN4, CN6)</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="color: #990000;"><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">참고</span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">위의 그림은 Antenna가 아래 방향에 있는 그림이다.</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 332px; overflow: hidden; width: 441px;"><img height="332" src="https://lh6.googleusercontent.com/V9eMqnNVodCC2ogHAq-IZrTnNiropC4ZMzWbsie9ngdePn9IDSp2-3mWLsmTaW-S-0vMfBO5yoaFgjXihIYYG4fVSwVtlYFQT3N0HWNiPN88uSN_jYyO3fDsKrBhKRW2CQXd8CA" style="margin-left: 0px; margin-top: 0px;" width="441" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.3] Arduino-compatible pin header(보드 top 오른쪽 pin - CN1)</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 315px; overflow: hidden; width: 418px;"><img height="315" src="https://lh6.googleusercontent.com/_abLsxdtL2zyDJG10XaG0plxxMBMUznKNNIvN_74cAd5mLoZuiiDagCcRuVSG-driWR9BgCfaeEOji8u6fv8LTA5ylJXKfXKDkTa-dV2uqJplBa7FHqifX2w_eWgFPM3bx7aYu0" style="margin-left: 0px; margin-top: 0px;" width="418" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.4] Morpho pin header(보드 top 왼쪽 pin - CN2)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 327px; overflow: hidden; width: 434px;"><img height="327" src="https://lh6.googleusercontent.com/ruhkA-tGLIv_xpP4LaBVzdHdo6DHnjwOCuuR4KviZIK8pFPvvU0le0rEIY1UJ8ma1tCySeEXzsdGtNqFEC1Q6UJo8b0DXiVkGmWbmYFu7gEH9md0cl15CXzr-zLO6p4ADEX67go" style="margin-left: 0px; margin-top: 0px;" width="434" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.5] Morpho pin header(보드 top 왼쪽 pin - CN3)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">b) lorawan example build하기</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">지금 부터 설명하는 내용은 아래 site를 기초로 한다.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<a href="https://os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-lorawan/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">https://os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-lorawan/</span></a></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd ~/workspace/new_boards/MbedOS</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed import mbed-os-example-lorawan</span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS" (directory)</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Importing program "mbed-os-example-lorawan" from "https://github.com/ARMmbed/mbed-os-example-lorawan" at latest revision in the current branch</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Adding library "mbed-lora-radio-drv" from "https://github.com/ARMmbed/mbed-semtech-lora-rf-drivers" at rev #6012fa43cf9f</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at rev #b6e5a0a8afa3</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Auto-installing missing Python modules (pycryptodome, psutil, click)...</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[mbed] </span><span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ERROR: Missing Python modules were not auto-installed.</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> The Mbed OS tools in this program require the following Python modules: pycryptodome, psutil, click</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> You can install all missing modules by running "pip install -r requirements.txt" in "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-lorawan/mbed-os"</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;"> On Posix systems (Linux, etc) you might have to switch to superuser account or use "sudo"</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">---</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cd mbed-os-example-lorawan/mbed-os</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sudo pip install -r requirements.txt</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">pycryptodome, psutil, click 등 필요한 python package를 자동으로 설치해 준다.</span></li>
</ul>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #bf9000; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><Supported MCUs></span></div>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARCH_BLE, ARCH_BLE_BOOT, ARCH_BLE_OTA, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARCH_GPRS, ARCH_LINK, ARCH_LINK_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARCH_LINK_OTA, ARCH_MAX, ARCH_PRO, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARDUINO_NANO33BLE, ARM_CM3DS_MPS2, ARM_IOTSS_BEID, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARM_MPS2_M0, ARM_MPS2_M0P, ARM_MPS2_M3, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARM_MPS2_M4, ARM_MPS2_M7, ARM_MUSCA_A1_NS, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ARM_MUSCA_A1_S, B96B_F446VE, BLUEPILL_F103C8, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">CC3220SF_LAUNCHXL, CY8CKIT_062S2_43012, CY8CKIT_062_BLE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">CY8CKIT_062_WIFI_BT, CY8CPROTO_062_4343W, CY8CPROTO_064_SB, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">CYW943012P6EVB_01, DELTA_DFBM_NQ620, DELTA_DFCM_NNN40, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DELTA_DFCM_NNN40_BOOT, DELTA_DFCM_NNN40_OTA, DELTA_DFCM_NNN50, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DELTA_DFCM_NNN50_BOOT, DELTA_DFCM_NNN50_OTA, DISCO_F051R8, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DISCO_F100RB, DISCO_F303VC, DISCO_F334C8, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DISCO_F401VC, DISCO_F407VG, DISCO_F413ZH, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DISCO_F429ZI, DISCO_F469NI, DISCO_F746NG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-size: x-small;"><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DISCO_F769NI, DISCO_L053C8, </span><span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DISCO_L072CZ_LRWAN1</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, ⇐ 이거네 ...</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DISCO_L475VG_IOT01A, DISCO_L476VG, DISCO_L496AG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">DISCO_L4R9I, EFM32GG11_STK3701, EFM32GG_STK3700, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">EFM32HG_STK3400, EFM32LG_STK3600, EFM32PG12_STK3402, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">EFM32PG_STK3401, EFM32WG_STK3800, EFM32ZG_STK3200, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">ELEKTOR_COCORICO, ELMO_F411RE, EP_AGORA, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">EV_COG_AD3029LZ, EV_COG_AD4050LZ, FF1705_L151CC, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">FF_LPC546XX, FUTURE_SEQUANA, FUTURE_SEQUANA_M0, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">FVP_MPS2_M0, FVP_MPS2_M0P, FVP_MPS2_M3, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">FVP_MPS2_M4, FVP_MPS2_M7, GD32_E103VB, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">GD32_F307VG, GD32_F450ZI, GR_LYCHEE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">HEXIWEAR, HRM1017, HRM1017_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">HRM1017_OTA, IM880B, K20D50M, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">K22F, K64F, K66F, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">K82F, KL05Z, KL25Z, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">KL26Z, KL27Z, KL43Z, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">KL46Z, KL82Z, KW24D, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">KW41Z, LPC1114, LPC11C24, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC11U24, LPC11U24_301, LPC11U34_421, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC11U35_401, LPC11U35_501, LPC11U35_501_IBDAP, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC11U35_Y5_MBUG, LPC11U37H_401, LPC11U37_501, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC11U68, LPC1347, LPC1549, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC1768, LPC1769, LPC4088, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC4088_DM, LPC4330_M0, LPC4330_M4, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC4337, LPC54114, LPC546XX, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC55S69_NS, LPC55S69_S, LPC810, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">LPC812, LPC824, LPCCAPPUCCINO, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MAX32600MBED, MAX32620FTHR, MAX32620HSP, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MAX32625MBED, MAX32625NEXPAQ, MAX32625PICO, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MAX32630FTHR, MAXWSNENV, MBED_CONNECT_ODIN, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MCU_LPC4088, MICRONFCBOARD, MIMXRT1050_EVK, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MOTE_L152RC, MTB_ACONNO_ACN52832, MTB_ADV_WISE_1510, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_ADV_WISE_1530, MTB_ADV_WISE_1570, MTB_LAIRD_BL600, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_LAIRD_BL652, MTB_LAIRD_BL654, MTB_MTS_DRAGONFLY, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_MTS_XDOT, MTB_MURATA_ABZ, MTB_MURATA_WSM_BL241, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_MXCHIP_EMW3166, MTB_RAK811, MTB_STM32_F439, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_STM_L475, MTB_STM_S2LP, MTB_UBLOX_NINA_B1, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTB_UBLOX_ODIN_W2, MTB_USI_WM_BN_BM_22, MTM_MTCONNECT04S, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTM_MTCONNECT04S_BOOT, MTM_MTCONNECT04S_OTA, MTS_DRAGONFLY_F411RE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTS_DRAGONFLY_L471QG, MTS_GAMBIT, MTS_MDOT_F405RG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">MTS_MDOT_F411RE, NCS36510, NRF51822, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51822_BOOT, NRF51822_OTA, NRF51822_Y5_MBUG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51_DK, NRF51_DK_BOOT, NRF51_DK_LEGACY, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51_DK_OTA, NRF51_DONGLE, NRF51_DONGLE_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51_DONGLE_LEGACY, NRF51_DONGLE_OTA, NRF51_MICROBIT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51_MICROBIT_B, NRF51_MICROBIT_BOOT, NRF51_MICROBIT_B_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF51_MICROBIT_B_OTA, NRF51_MICROBIT_OTA, NRF52840_DK, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NRF52_DK, NUCLEO_F030R8, NUCLEO_F031K6, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F042K6, NUCLEO_F070RB, NUCLEO_F072RB, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F091RC, NUCLEO_F103RB, NUCLEO_F207ZG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F302R8, NUCLEO_F303K8, NUCLEO_F303RE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F303ZE, NUCLEO_F334R8, NUCLEO_F401RE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F410RB, NUCLEO_F411RE, NUCLEO_F412ZG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F413ZH, NUCLEO_F429ZI, NUCLEO_F439ZI, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F446RE, NUCLEO_F446ZE, NUCLEO_F746ZG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_F756ZG, NUCLEO_F767ZI, NUCLEO_H743ZI, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_H743ZI2, NUCLEO_L011K4, NUCLEO_L031K6, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_L053R8, NUCLEO_L073RZ, NUCLEO_L152RE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_L432KC, NUCLEO_L433RC_P, NUCLEO_L476RG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_L486RG, NUCLEO_L496ZG, NUCLEO_L496ZG_P, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUCLEO_L4R5ZI, NUCLEO_L4R5ZI_P, NUCLEO_WB55RG, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUMAKER_IOT_M263A, NUMAKER_IOT_M487, NUMAKER_PFM_M453, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NUMAKER_PFM_M487, NUMAKER_PFM_NANO130, NUMAKER_PFM_NUC472, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">NU_PFM_M2351_NPSA_NS, NU_PFM_M2351_NPSA_S, NZ32_SC151, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">OC_MBUINO, OSHCHIP, RAPIDIOT_K64F, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">RAPIDIOT_KW41Z, RBLAB_BLENANO, RBLAB_BLENANO2, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">RBLAB_BLENANO_BOOT, RBLAB_BLENANO_OTA, RBLAB_NRF51822, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">RBLAB_NRF51822_BOOT, RBLAB_NRF51822_OTA, RDA5981X, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">REALTEK_RTL8195AM, RHOMBIO_L476DMW1K, RM6100, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">RM7100, RO359B, RZ_A1H, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">RZ_A1XX, SAKURAIO_EVB_01, SAMD21G18A, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SAMD21J18A, SAMG55J19, SAML21J18A, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SAMR21G18A, SARA_NBIOT_EVK, SDP_K1, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SDT32620B, SDT32625B, SDT51822B, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SDT52832B, SDT64B, SEEED_TINY_BLE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SEEED_TINY_BLE_BOOT, SEEED_TINY_BLE_OTA, SILICA_SENSOR_NODE, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">SSCI824, STEVAL_3DP001V1, TB_SENSE_1, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">TB_SENSE_12, TEENSY3_1, TMPM066, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">TMPM3H6, TMPM3HQ, TMPM46B, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">TMPM4G9, TT_M3HQ, TT_M4G9, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">TY51822R3, TY51822R3_BOOT, TY51822R3_OTA, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">UBLOX_C027, UBLOX_C030_N211, UBLOX_C030_R410M, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">UBLOX_C030_R412M, UBLOX_C030_R41XM, UBLOX_C030_U201, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">UBLOX_EVA_NINA, UBLOX_EVK_NINA_B1, UBLOX_EVK_ODIN_W2, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">UBRIDGE, UHURU_RAVEN, UNO_91H, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">USENSE, VBLUNO51, VBLUNO51_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">VBLUNO51_LEGACY, VBLUNO51_OTA, VBLUNO52, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">VK_RZ_A1H, WALLBOT_BLE, WALLBOT_BLE_BOOT, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">WALLBOT_BLE_OTA, WIO_3G, WIO_BG96, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">WIZWIKI_W7500, WIZWIKI_W7500ECO, WIZWIKI_W7500P, </span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">XADOW_M0, XBED_LPC1768, XDOT_L151CC</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ cd ..</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -m </span><span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DISCO_L072CZ_LRWAN1</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> -t </span><span style="background-color: transparent; color: #38761d; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GCC_ARM</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-lorawan" (program)</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] @,: Compiler version mismatch: Have 9.2.1; expected version >= 6.0.0 and < 7.0.0</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Building project mbed-os-example-lorawan (DISCO_L072CZ_LRWAN1, GCC_ARM)</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Scan: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.1%]: mbed_tz_context.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.2%]: MCR20Drv.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.3%]: at24mac.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.5%]: main.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] main.cpp@160,44: format '%d' expects argument of type 'int', but argument 2 has type 'int32_t' {aka 'long int'} [-Wformat=]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] main.cpp@167,70: format '%d' expects argument of type 'int', but argument 3 has type 'int32_t' {aka 'long int'} [-Wformat=]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] main.cpp@167,25: '%d' directive writing between 1 and 11 bytes into a region of size 8 [-Wformat-overflow=]</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.6%]: rf_configuration.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.7%]: NanostackRfPhyMcr20a.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 0.8%]: SX126X_LoRaRadio.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">...[중간 생략]...</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.2%]: rtc_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.3%]: trace_helper.cpp</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.4%]: serial_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.5%]: sleep.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.7%]: trng_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.8%]: watchdog_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [ 99.9%]: us_ticker.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Compile [100.0%]: stm_spi_api.c</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Link: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Elf2Bin: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Module | .text | .data | .bss |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">|----------------------------|-----------------|-------------|-------------|</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [fill] | 126(+126) | 8(+8) | 27(+27) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/c.a | 29124(+29124) | 2472(+2472) | 89(+89) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/gcc.a | 12740(+12740) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/m.a | 552(+552) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/misc | 192(+192) | 4(+4) | 28(+28) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| main.o | 978(+978) | 0(+0) | 4020(+4020) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX126X | 54(+54) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX1272 | 292(+292) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX1276 | 8474(+8474) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/components | 80(+80) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/drivers | 2192(+2192) | 0(+0) | 596(+596) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/events | 1560(+1560) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/features | 26910(+26910) | 4(+4) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/hal | 1732(+1732) | 8(+8) | 130(+130) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/platform | 4714(+4714) | 260(+260) | 412(+412) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/rtos | 10598(+10598) | 168(+168) | 3164(+3164) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/targets | 13180(+13180) | 4(+4) | 1230(+1230) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| trace_helper.o | 2(+2) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Subtotals | 113500(+113500) | 2928(+2928) | 9696(+9696) |</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Static RAM memory (data + bss): 12624(+12624) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Flash memory (text + data): 116428(+116428) bytes</span></span></div>
<span style="font-size: x-small;"><br /></span>
<div dir="ltr" style="line-height: 1.2; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Image: ./BUILD/DISCO_L072CZ_LRWAN1/GCC_ARM/mbed-os-example-lorawan.bin</span></span></div>
</td></tr>
</tbody></table>
</div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #38761d; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">c) lorawan firmware 수정해서 보드에 올리기</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">보드(이하 disco 보드로 통칭)가 도착했으니, 이제 부터 firmware를 올려 보도록 하자. :)</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 338px; overflow: hidden; width: 449px;"><img height="338" src="https://lh6.googleusercontent.com/0ndBgNmb0haY0qZeMNCjYl5tN1mN5uGffApY4chEsgLUf066aGTIbECGh-qFMmQWMj-bOHIX0_ar_DKbYHrQ1YX9M4UyHkbA0hrbXG_wcaor1B_Efz73d1ypqB8i9zk5F_fFQU0" style="margin-left: 0px; margin-top: 0px;" width="449" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.6] DISCO_L072CZ-LRWAN1 보드 전원 연결 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">먼저 mbed-os-example-lorawan/</span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed_app.json</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 파일을 열고, KR920 주파수 설정 및 OTAA 설정 변경을 해 보자.</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 488px; overflow: hidden; width: 624px;"><img height="488" src="https://lh3.googleusercontent.com/MCRBvldoi_doAxg7gkCUz5oFnVW2mdWMBkzFB_ee7JVksLwo5lDYgnBSYjPdOuNfkK47UvVJBZxzpnhJTh_Tfwlxa14TdHn7WRei2bpgN5RnPbS-Qn0wumyxVBiPneVlhBmhDwQ" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.7] mbed_app.json 파일 내용</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 160px; overflow: hidden; width: 624px;"><img height="160" src="https://lh4.googleusercontent.com/M6GDhneADWdnv5eGAUikg_QTfcpGcaxWeJ-UEn5qN-DWtb1cCaY4XWEEmnetUGn2Ipd-gH_BGoH9Zm2Z0BAzURYA8OPr-QPpPCTgdDrvL9FoCElFyWougLZubJhAC_Q8rHnMJs4" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.8] mbed_app.json 파일 수정</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">참고: LoRaServer에서는 application-eui를 사용하지 않는다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">수정한 내용을 반영하기 위해 코드를 재 build해 보도록 하자.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -m DISCO_L072CZ_LRWAN1 -t GCC_ARM</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Build에 문제가 없으니, 바로 flash writing을 해 보기로 하자.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">chyi@mars:~/workspace/new_boards/MbedOS/mbed-os-example-lorawan$ </span><span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mbed compile -m DISCO_L072CZ_LRWAN1 -t GCC_ARM -f</span></div>
<ul>
<li><span style="color: #695d46; font-family: "arimo" , sans-serif; white-space: pre-wrap;">Flash에 write하자.</span></li>
</ul>
<div align="left" dir="ltr" style="margin-left: 0pt;">
<table style="border-collapse: collapse; border: none;"><colgroup><col width="624"></col></colgroup><tbody>
<tr style="height: 0pt;"><td style="border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[mbed] Working path "/home/chyi/workspace/new_boards/MbedOS/mbed-os-example-lorawan" (program)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">[Warning] @,: Compiler version mismatch: Have 9.2.1; expected version >= 6.0.0 and < 7.0.0</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Building project mbed-os-example-lorawan (DISCO_L072CZ_LRWAN1, GCC_ARM)</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Scan: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Link: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Elf2Bin: mbed-os-example-lorawan</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Module | .text | .data | .bss |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">|----------------------------|------------|----------|----------|</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [fill] | 126(+0) | 8(+0) | 27(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/c.a | 29124(+0) | 2472(+0) | 89(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/gcc.a | 12740(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/m.a | 552(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| [lib]/misc | 192(+0) | 4(+0) | 28(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| main.o | 978(+0) | 0(+0) | 4020(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX126X | 54(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX1272 | 292(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-lora-radio-drv/SX1276 | 8474(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/components | 80(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/drivers | 2192(+0) | 0(+0) | 596(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/events | 1560(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/features | 27678(+0) | 4(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/hal | 1732(+0) | 8(+0) | 130(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/platform | 4714(+0) | 260(+0) | 412(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/rtos | 10598(+0) | 168(+0) | 3164(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| mbed-os/targets | 13180(+0) | 4(+0) | 1230(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| trace_helper.o | 2(+0) | 0(+0) | 0(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">| Subtotals | 114268(+0) | 2928(+0) | 9696(+0) |</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Static RAM memory (data + bss): 12624(+0) bytes</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #85200c; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Total Flash memory (text + data): 117196(+0) bytes</span></span></div>
<span style="font-size: x-small;"><br /></span>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-small;">Image: ./BUILD/DISCO_L072CZ_LRWAN1/GCC_ARM/mbed-os-example-lorawan.bin</span></span></div>
</td></tr>
</tbody></table>
</div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="color: #990000;"><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">주의</span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">장치를 PC에서 인식 못할 경우, PC를 재 부팅해 주면 해결될 수 있다.</span></span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Flash에 writing은 정상적으로 진행된 듯 한데, LoRaWAN 연결(<=> LoRaServer)이 안되는 것 같다.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">참고: LoRaServer에 disco board를 Application으로 등록하는 절차는 (반복되는 내용이라) 별도로 정리하지 않았다.</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 351px; overflow: hidden; width: 624px;"><img height="351" src="https://lh5.googleusercontent.com/eCHyrhtKP_hgiVLRJMEzYFogcnPnLyDjyvj4fcxaTqsDmjmzo2xtyOkKNYsyovGLEUxVH1jCb3shKeS6Z3ngNlF1X7KPwWud6EoQxSsugAvqaEu7zedodWvV1xCU1S46IV2oxEc" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.9] minicom(/dev/ttyACM0, 115200, 8N1) 실행 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">어라, <a href="https://www.chirpstack.io/">LoRaServer</a> application key 설정이 잘 못 되었다. 아래와 같이 다시 조정해 보니, 정상 동작한다.</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 340px; overflow: hidden; width: 461px;"><img height="340" src="https://lh5.googleusercontent.com/_aLH4LZ3vzTGFcXvIMEcHC6DAvpwlb8EKGKkgZk54cfunnGHknBzbYZCWVL12_xhot5Cju93yAoIfSjZvv5QxB1ye3CCFpATeFO9Mq4TCub0bxIiRgbiwo4e9Kw9puRmtoeIqic" style="margin-left: 0px; margin-top: 0px;" width="461" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.10] LoRaServer OTAA 설정 변경</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 331px; overflow: hidden; width: 495px;"><img height="331" src="https://lh5.googleusercontent.com/_ay_q1q2O-ofC4GX57HRJOG_2B4-PsOwlc3Hqw7k5qN3IV6FutOaTFRm7BepTI4_oRh5hiiz4VInMoDCCZ8QKkeKjWA2xMlqZT7mVfTL4MPauyNflxOGP5LPzikHlCeYsurmZgk" style="margin-left: 0px; margin-top: 0px;" width="495" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.11] minicom(/dev/ttyACM0, 115200, 8N1) 실행 모습 - OK</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 314px; overflow: hidden; width: 426px;"><img height="314" src="https://lh4.googleusercontent.com/lkDrNBUUWRgknpJdOx0Rk2acKuVNs8pfznZfsohHVpSJsjtDciAhVxr6N4F5c1Mu35jrnplmBUSI3pnaIhrrXXWH4IEsrhnwUig7b4lGJZOT-zYER10AkyjBrbpiT3XOXgAq6UM" style="margin-left: 0px; margin-top: 0px;" width="426" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.12] LoRaServer application page 모습</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">근데, 왜 에러 packet이 보일까 ?</span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "open sans" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 306px; overflow: hidden; width: 415px;"><img height="306" src="https://lh4.googleusercontent.com/MXE1uuQgvidLqTdAcF2V8_XysHbmD5BvocyXxkUe311xlqfUyi_QBWYyw5LOTmr2yryHCi1I9LekqOVGpVQnAqomxgrbBjibZh0axH23CJJRTb6SBcQ2tEjtPRFcnWBtx3Pemng" style="margin-left: 0px; margin-top: 0px;" width="415" /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: center;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[그림 5.13] LoRaServer application page - error packet</span></div>
<b style="font-weight: normal;"><br /></b>
<br />
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">내용을 보니, </span><span style="background-color: white; color: #427af5; font-family: "roboto" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">error:</span><span style="background-color: white; color: #40af6c; font-family: "roboto" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">"invalid data type: 117"</span><span style="background-color: white; color: #40af6c; font-family: "roboto" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: white; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">인데 ...</span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 실제 sensor를 달지 않아서 제대로 된 data가 없어서 그런가 ? </span><span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #666666;">아직은 정확한 이유를 알 수 없으니, 좀 더 두고 볼 일이다. :(</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="background-color: transparent; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #990000;">[나중에 정리한 것임]</span></span><span style="background-color: transparent; color: #695d46; font-family: "arimo" , sans-serif; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> <a href="https://thingsboard.io/">ThingsBoard</a>로 전달할 message format(Codec 설정)이 안 맞아서 발생한 에러이다.</span></div>
<br />
<b style="font-weight: normal;"><br /></b>
<br />
<h1 dir="ltr" style="line-height: 1.56; margin-bottom: 0pt; margin-top: 24pt;">
<span style="color: #ff5e0e; font-family: "arimo" , sans-serif; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: x-large;">6. LoRaWAN의 모든 것</span></span></h1>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="font-family: "arimo" , sans-serif; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #695d46;">이번 장에서는 LoRaWAN 관련하여 필자가 작성한 몇가지 문서를 소개하고자 한다. 아래 4개의 문서에서는 </span><b><span style="color: #0b5394;">LoRaWAN Sensor(Node) => Gateway => LoRa Server => Application Server</span></b><span style="color: #695d46;">에 이르는 전반적인 내용을 다루고 있으니, 관심있는 분들은 한번 읽어보시기 바란다.</span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="font-family: "arimo" , sans-serif; vertical-align: baseline; white-space: pre-wrap;"><span style="color: #695d46;"><br /></span></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<span style="color: #695d46; font-family: "arimo" , sans-serif; vertical-align: baseline; white-space: pre-wrap;"><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b><LoRaWAN & security 1></b></i><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><a href="https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_1.pdf" style="background: rgb(255, 255, 255); color: #2196f3; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; text-decoration-line: none; white-space: normal;">https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_1.pdf</a><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b><L</b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b>oRaWAN & security </b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b>2></b></i><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><a href="https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_2.pdf" style="background: rgb(255, 255, 255); color: #2196f3; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; text-decoration-line: none; white-space: normal;">https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_2.pdf</a><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b><L</b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b>oRaWAN & security</b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b> 3></b></i><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><a href="https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_3.pdf" style="background: rgb(255, 255, 255); color: #2196f3; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; text-decoration-line: none; white-space: normal;">https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_3.pdf</a><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b><L</b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b>oRaWAN & security</b></i><i style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;"><b> 4></b></i><br style="background-color: white; color: #757575; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; white-space: normal;" /><a href="https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_4.pdf" style="background: rgb(255, 255, 255); color: #2196f3; font-family: Roboto, sans-serif; font-size: 15px; text-align: start; text-decoration-line: none; white-space: normal;">https://github.com/ChunghanYi/spnhacks/blob/master/lorawan_security_solution/SPNBox_LoRa_Dev_Guide15_4.pdf</a></span></div>
<div dir="ltr" style="line-height: 1.44; margin-bottom: 0pt; margin-top: 6pt; text-align: justify;">
<br /></div>
<br />
<div style="text-align: right;">
<b>Slowboot</b></div>
<br />
<br />Slowboothttp://www.blogger.com/profile/16580188960257697703noreply@blogger.com0