웹페이지 내에 오디오를 넣고 싶을 때는 audio element로 넣을 수 있다. src attribute 혹은 source element로 하나의 오디오 소스를 가지거나 audio element의 children으로 source element 리스트를 넣어서 여러개의 오디오 소스를 가질 수 있다.
<audio controls src="media/dasomoli.mp3">여러분의 브라우저가 audio 태그를 지원하지 않는 것 같네요..</audio>
위처럼 <audio>와 </audio> 사이에 브라우저가 지원하지 않을 때 나타낼 메시지를 넣을 수 있다. controls attribute는 여러분이 오디오를 재생할 수 있도록 할 수 있다. 다음과 같은 contol이 나타난다.
다음과 같은 속성들이 있다.
autoplay (boolean)
preload (none / metadata / auto)
loop (boolean)
controls
autoplay는 전부 다운로드 받지 않더라도 재생이 가능할만큼만 되면 바로 재생한다. 사람들이 웹페이지에 들어왔을 때 오디오가 바로 재생되면 싫어하므로 사용에 주의하라.
preload는 미디어 소스의 로딩을 어떻게 할지를 정하고 싶을 때 사용한다. none은 preload하지 않고, metadata는 metadata만 로드한다. auto는 empty string(“”)과 동등한데, 전체 파일이 로드된다.
loop는 반복 재생하도록 한다.
controls는 브라우저의 기본 미디어 컨트롤을 추가한다. 사용자가 오디오의 재생을 제어할 수 있다. 브라우저마다 UI가 다른데, 공통적인 기능은 비슷하다. UI가 다르므로 controls attribute를 셋팅하지 않고 HTML, CSS, Javascript를 사용해서 customize한 control을 생성, 원하는 디자인을 할 수도 있다.
webm, mp3, ogg등 브라우저마다 지원하는 format이 다르다. 이에 대해서는 MDN의 다음 글을 참고하자.
여러개의 source를 넣고 싶을 때는 source element를 이용한다. src attribute를 사용하지 않고 여러개의 source를 사용했음에 주목하라. 이 중 지원하지 않는 format이 있으면 다음 것을 시도한다.
<audio controls>
<source src="media/dasomoli.webm" type="audio/webm">
<source src="media/dasomoli.mp3" type="audio/mp3">
<source src="media/dasomoli.ogg" type="audio/ogg">
여러분의 브라우저가 <code>audio</code>를 지원하지 않는 것 같아요!
</audio>
동영상 (Video)
video element와 audio element는 둘 모두 HTML media elements이다. 사실 video element로 audio를, audio element로 video를 재생하는 것도 가능하다. video element는 display 영역을 제공한다는 것이 차이이다.
video element의 attribute는 audio element 것을 모두 가진다. 추가로 다음 attribute를 제공한다:
height
width
poster
width와 height attribute는 video display area의 width와 height을 각각 조정한다. 둘 모두 pixel로 조정된다. %로 비율을 쓸 수 없다.
poster attribute는 video가 다운로드되는 동안 보여줄 이미지를 지정한다. 지정하지 않으면 video의 첫 frame의 다운로드 전에는 빈 네모가 보이고, 첫 frame을 다운로드 받으면 그 첫 frame이 보일 것이다.
Text track
track element는 media element와 연관된 시간 기준의 글을 지정한다. 이는 미디어 재생과 싱크가 맞는 시간에 어떤 글을 보여줄 수 있다는 뜻이다. 자막이나 해당 미디어에 대한 설명은 물론, 앞이 안보이거나 소리가 안들리는 사람들에게도 어떤 것인지 설명할 수 있도록 해준다.
video의 source element와 같이 하나의 media element 에 여러개의 track element를 넣어서 그 media에 대한 여러 track을, 예를 들면 다른 언어 자막 같은 식으로 제공할 수 있다.
track element의 attribute는 다음과 같다:
src: text track file의 위치
default: media element 당 하나의 track element가 default track으로 지정될 수 있다. 사용자 설정에 따라 override될 수 있다.
kind: text track이 무엇으로 사용되는지를 지정한다. subtitles, captions, descriptions, chapters, metadata같은 여러 옵션이 있다. default는 subtitles이다.
위에서 source element는 media attribute를 갖는다. 위 코드는 첫번째 것부터 media attribute가 참인지를 보고 맞다면, 위 코드에서는 viewport가 639 픽셀 이하인지를 보고 맞다면 해당 이미지를 보여준다. 아니라면 다음 것으로 넘어간다. 다 안맞으면 마지막의 img의 것을 보여주게 된다. 브라우저가 picture를 지원하지 않을 때도 picture의 가장 마지막 것을 보여주게 된다.
조건으로 media 외에도 type attribute나 mime type도 사용할 수 있다.
위의 .jpeg, .gif, .png, .webp 같은 foramt외에도 SVG (Scalable vector graphics)나 canvas element 처럼 프로그래밍한 그래픽을 생성할 수 있다. SVG는 vector graphics를 위한 XML 기반의 format이고, canvas element는 웹페이지 상에서 rasterized graphics를 생성하는데 사용되는 JavaScript drawing API로 접근 할 수 있는 element다.
svg element
svg는 vector graphics를 정의하는 XML 기반 format이다. Vector graphics는 깨지는 문제없이 비율에 따라 계산되기 때문에 반응형 웹에 매우 유용하다. 간단한 예로 play와 stop button을 만든다고 하자.
viewBox attribute로 x좌표 0, y좌표 0에서 100 dimension으로 설정했다. viewBox는 pixel로 표시하지 않는다. width와 height attribute로 비율을 정할 수 있다. 안에 들어가는 children들은 viewBox의 상대적 위치에 놓이게 된다.
circle element로 x좌표 50, y좌표 50의 위치에 반지름 50짜리 원을 그렸고, 안을 black으로 채웠다. hex value #rrggbb로도 당연히 설정 가능하다. 그 후 path로 3점을 정해서 삼각형을 하나 그리고 이를 white로 채웠다. 비슷하게 stop 버튼은 사각형을 하나 그리고 이를 white로 채웠다. 위 소스는 다음과 같이 렌더링된다.
svg는 canvas처럼 javaScript가 필요하지 않고 바로 접근 가능하지만, shape들이 많으면 성능 문제가 일어날 수 있다.
canvas Element
canvas element로는 rasterized graphics를 렌더링할 수 있다. 이를 위해서 JavaScript의 drawing API를 사용한다. 2D와 WebGL의 두가지 렌더링 모드가 있다. WebGL은 GPU acceleration과 같은 shader support를 제공한다.
browser가 canvas를 지원하는지를 확인한 후 이용하는 것이 좋다. 확인하는 코드는 다음과 같이 쓸 수 있다.
moveTo(x, y) 로 옮기고, lineTo(x, y) 로 경로를 정한 후, strokeStyle을 정한 후 stroke()로 외곽선을 그린다. lineTo로 이어서 그린 후 해당 경로를 fillStyle로 정한 후 fill()로 채울 수도 있다.
사각형(Rectangle) 그리기
속이 빈 사각형을 외곽선 만으로 그리고 싶으면, strokeStyle로 외곽선의 style을 정하고, lineWidth로 외곽선 굵기를 정한 후, strokeRect(x, y, width, height)로 그린다.
안이 채워진 사각형을 그리고 싶으면 fillStyle로 style을 정하고, fillRect(x, y, width, height)로 그린다. fillStyle은 CSS에서 사용하는 값이면 다 쓸 수 있다. color, backgroundColor같은 property나 black, red, white 같은 color값, hex value #rrggbb나, rgba(25, 35, 45, 0.7) 같은 rgba 값도 가능하다.
외곽선과 안이 채워진 것을 모두 적용하고 싶다면, strokeStyle과 fillStyle을 모두 설정하고, rect(x, y, width, height)로 사각형 경로를 설정하고, fill()로 채우고, stroke()로 외곽선을 그리면 된다.
명령어만 덜렁 써놓기 뭐해서 설명을 덧붙인다.
가끔 undefined instrunction 예외가 날 때, 코드 메모리의 이상 여부를 확인해야 할 때가 있다.
커널은 알다시피 zImage를 Decompressed 하여 메모리상에 올린 후 실행하는데, 그 Decompressed Image가 Image 이다. Image는 커널의 빌드 과정에서 아래와 같이 objcopy를 이용해서 만든다. Makefile 을 참고해보면 알 수 있을 것이다. ARM의 경우는 arch/arm/boot/ 와 그 아래의 Makefile을 살펴보면 된다.
Android JB MR1의 경우 아래 경로의 prebuilt 된 툴체인을 사용한다.
나온 Image를 Trace32로 실제 커널 메모리를 dump 해서 Binary Diff 해보면 메모리의 H/W적인 이상여부나 코드 메모리를 어디서 건드려서 깨지진 않았는지 확인해 볼 수 있다.
커널 프로그램이 물리메모리 0x40008000과 같은 주소에 로딩되므로, 특정 모듈이나 특정 루틴의 경우 objcopy로 걸러낸 후, 해당 주소의 프로그램을 실제 메모리에서 offset을 뺀 값으로 Image파일에서 찾아야 한다.
Windows에서는 HxD와 같은 툴로 Binary Diff 할 수 있다. Beyond compare를 써도 되고(근데 유료라는 점)…
While every precaution has been taken in the preparation of this article, the publisher assumes no responsibility for errors or omissions, or for damages resulting from the use of the information contained herein.
2004-06-04
Revision History
Revision 1.00
10th May 2004
VRS
Initial Release.
Revision 1.10
4th June 2004
VRS
Update example code to be more complete.
Improve wording in places, changes suggested by NicolasPitre.
4. 시스템의 메모리 설정하기
5. 커널 이미지 로딩
6. 램디스크 로딩
7. 콘솔 초기화
8. 커널 파라미터
9. ARM 리눅스 머신 타입 얻기
10. 커널 시작
A. 태그 레퍼런스
B. 완전한 예제
참고문헌
요약
이 문서는 ARM 리눅스 커널을 시작하기 위한 부트 로더의 필요사항과 절차를 구현 가이드, 예제와 함께 명확히 간결한 용어로 정의합니다.
1. 이 문서에 관해서
이 문서는 2.4.18 이후의 커널이 사용하는 “새로운” 부팅 절차를 설명합니다. 이전의 “struct” 메소드는 사용하지 마세요.
이 문서는 광범위한 종류의 출처(참고문헌 참고)와 저자들로부터의 정보를 포함하고 있습니다. 메인테이너들 또는 ARM 리눅스 메일링 리스트 상에 질문하기 전에 이 출처들을 찾아보는 것이 좋습니다. 이 분야의 대부분의 것들은 이전에 반복적으로 문의 및 답변되었고, 만약 여러분이 기본적인 조사도 하지 않았다면 여러분은 무시될 가능성이 큽니다.
추가적으로 이 문서에서 제공하는 가이드를 따르고, 커널을 시작하는 어셈블러의 모든 미묘한 차이를 이해하는 개발자가 될 필요는 없다는 것을 알아두세요. 또한 대부분의 부팅 문제는 여기 있는 코드와 상관없는 경우가 많았고, 많은 사람들이 말하는 코드는 매우 까다롭고 그 문제에 대해 간파할 수 없는 경우가 많았습니다.
2. 다른 부트로더
새 부트 로더의 작성을 시작하기 전에 개발자들은 이미 존재하는 부트 로더가 적절하지는 않은지 한번 생각해보는 것이 좋습니다. 간단한 GPL 부트 로더에서부터 상용으로 제공하는 것까지 다양한 영역의 부트 로더 예제가 있습니다. 여기서 다음 작은 표를 제공합니다만 참고문헌에 있는 문서는 더 많은 솔루션을 제공합니다.
ARM 리눅스는 시스템을 초기화하는 특정 머신에서만 동작하는 작은 코드 없이는 시작될 수 없습니다. 몇몇 부트로더는 더 많은 추가 기능을 제공하긴 하지만, ARM 리눅스는 이 작은 일을 하는 부트 로더가 필요합니다. 최소한의 필요사항은 다음과 같습니다:
시스템의 메모리 설정하기.
정확한 메모리 주소에 커널 이미지 로딩.
필요하면 정확한 메모리 주소에 램디스크 로딩.
커널로 전달할 부트 파라미터 초기화.
ARM 리눅스 머신 타입 얻기
적당한 레지스터 값으로 커널로 진입.
부트로더는 일반적으로 이런 기본적인 작업들 뿐만 아니라 시리얼 또는 비디오 콘솔을 초기화해야 합니다. 사실 시리얼 포트는 거의 대부분의 설정을 위해 필수사항으로 생각됩니다.
위의 각 단계를 다음 절들에서 설명합니다.
4. 시스템의 메모리 설정하기
부트 로더는 커널이 시스템의 임시 저장 장소로 사용할 모든 램을 찾아 초기화해야 합니다. 이는 특정 머신에서만 동작하는 방법(모든 램의 크기와 위치를 찾는 내부 알고리즘을 사용하거나, 머신에 달린 램에 관한 정보를 사용하거나, 또는 부트 로더 설계자 관점의 다른 방법 등)으로 수행됩니다.
어떠한 경우에도 모든 셋업은 부트 로더에 의해서 수행되어야 합니다. 커널은 시스템 안의 램의 셋업 또는 설정에 대해서 부트 로더가 제공하는 것 외에는 아무 것도 몰라야 합니다. 커널 안의 machine_fixup()의 사용은 이런 것을 하기 위한 것이 절대 아닙니다. 이 부분에서의 커널과 부트 로더 간의 책임 구별은 명확합니다.
물리 메모리 배치는 ATAG_MEM 파라미터를 사용해서 커널로 전달됩니다. 메모리가 가장 적게 분리되어 있는 것이 좋긴 하지만, 완전히 연속적일 필요는 없습니다. 여러 메모리 지역을 위한 여러개의 ATAG_MEM 블록도 상관없습니다. 연속된 물리 메모리 지역이 있다면 커널은 그 블록들을 합칠 겁니다.
부트 로더는 또한 linux/Documentation/kernel-parameters.txt 에 완벽히 문서화되어 있는 ‘mem=’ 파라미터를 사용해서 커널의 커맨드라인으로 메모리를 조작할 수도 있습니다.
커널 커맨드 라인 ‘mem=’ 는 정의된 메모리 영역의 물리 메모리 위치와 크기를 위해서 mem=<size>[KM][,@<phys_offset>] 문법을 가집니다. mem= 파라미터는 각기 다른 곳의 여러개의 연속되지 않은 메모리 블록을 나타내기 위해 여러 번 쓸 수 있습니다.
5. 커널 이미지 로딩
커널 이미지는 커널 빌드 과정에서 생성된 압축되지 않은 “Image” 파일 또는 압축된 zImage 파일입니다.
압축되지 않은 Image 파일은 식별 가능한 매직 넘버를 포함하고 있지 않아서 일반적으로 사용되지 않습니다. 압축된 zImage 형식이 거의 보편적으로 사용됩니다.
zImage 파일은 매직 넘버 뿐만 아니라 여러 장점을 갖고 있습니다. 일반적으로 이미지의 압축 해제는 외부 저장 장치를 읽는 것보다 빠릅니다. 압축 해제 실패의 결과로 이미지의 무결성도 보장할 수 있습니다. 커널은 일반적인 외부 압축 방법보다 더 나은 결과를 알 수 있는 그 내부 구조와 상태에 대한 정보를 가집니다.
zImage는 그 앞 부분 근처에 유용한 정보와 매직 넘버를 가집니다.
표 2. zImage head 코드 안의 유용한 정보
zImage안의 오프셋
값
설명
0x24
0x016F2818
ARM 리눅스 zImage를 나타내는데 사용하는 매직 넘버
0x28
시작 주소
zImage가 시작하는 주소
0x2C
끝 주소
zImage가 끝나는 주소
시작과 끝 오프셋은 압축된 이미지의 크기(크기 = 끝 – 시작)를 결정하는데 사용됩니다. 몇몇 부트 로더들은 어떤 데이터가 커널 이미지에 추가된다면 이 정보를 사용합니다. 이 데이터는 일반적으로 초기 램디스크(initrd)를 위해 사용됩니다. 시작 주소는 일반적으로 zImage 코드가 위치에 무관하므로 0 입니다.
zImage 코드의 이용 가능한 주소 공간 안의 어떤 곳에도 로딩될 수 있는 위치에 무관한 코드(Position Independent Code – PIC) 입니다. 압축해제 된 후의 커널 크기는 최대 4 메가 바이트 입니다. 이는 bootpImage 타겟이 사용되었을 때의 initrd를 포함한 제약 사항입니다.
주의
zImage가 어느 곳이든 위치할 수 있다 하더라도 주의해야 합니다. 압축된 커널을 시작하는 것은 이미지를 압축해제할 추가적인 메모리를 필요로 합니다. 이 공간은 확실한 제약사항입니다.
zImage 압축해제 코드는 압축된 데이터를 덮어쓰지 않도록 확인할 겁니다. 커널이 어떤 충돌 같은 것을 발견한다면, 압축된 zImage 데이터 바로 뒤에 이미지를 압축 해제하고, 압축 해제 후에 커널을 재위치시킬 겁니다. zImage가 로딩된 메모리 영역은 그 뒤에 4 메가 바이트보다 큰 공간을 가져야 한다는 것, 즉 ZRELADDR로서 같은 4 메가 바이트 뱅크에 위치한 커널이 기대하는대로 동작하지 않는 것을 명확히 알 수 있습니다.
메모리 안에 어느 곳이든 zImage가 위치할 수 있지만 관례상 물리 메모리의 베이스에서 0x8000 (32K) 오프셋에 로딩됩니다. 이 것은 파라미터 블록이 일반적으로 위치하는 0x100 오프셋, Zero page exception 벡터와 페이지 테이블을 위한 공간을 남겨둡니다. 이 관례는 매우 일반적입니다.
6. 램디스크 로딩
램디스크는 많은 시스템상에서 일반적인 요구사항입니다. 그 것은 다른 드라이버나 설정에 접근할 필요없이 사용가능한 루트 파일 시스템을 제공합니다. 완전한 세부사항은 linux/Documentation/initrd.txt 에서 볼 수 있습니다.
ARM 리눅스가 램디스크를 얻는 방법은 두가지입니다. 첫번째는 빌드 할 때 램디스크를 가져와서 zImage 에 덧붙인 target bootpImage를 따로 빌드하는 겁니다. 이 방법은 부트 로더와의 상호 약속된 것이 없어도 된다는 장점이 있는 반면에 커널 빌드 과정에서 램디스크가 위치할 물리 주소를 (INITRD_PHYS 정의를 사용해서) 알려 주어야 한다는 단점이 4있습니다. 압축 해제된 커널과 initrd의 크기는 4 메가 바이트로 제한됩니다. 이 제한 사항 때문이 이 타겟은 실제로는 별로 사용되지 않습니다.
두번째 방법은 더 널리 사용되는 방법으로 부트로더가 어떤 저장 장치에서 램디스크를 받아 메모리의 지정된 위치에 위치시키는 것입니다. 이 위치는 커널에게 ATAG_INITRD2 와 ATAG_RAMDISK를 사용해서 전달됩니다.
관례적으로 initrd는 물리 주소 베이스의 8메가 바이트에 위치합니다. 위치된 곳이 어디 건간에 부팅 후에 램디스크를 실제 램디스크로 압축해제 하기 위한 충분한 메모리, 즉 zImage + 압축 해제된 zImage + initrd + 압축 해제된 램디스크를 위한 메모리가 있어야 합니다. 압축된 램디스크 메모리는 압축이 해제되고 나면 할당 해제될 겁니다. 램디스크의 위치 제한은 다음과 같습니다:
한 개의 메모리 영역안에 있어야 합니다(다른 ATAG_MEM 파라미터에 의해 정의된 다른 영역에 걸쳐 있으면 안됩니다).
한 페이지 경계(일반적으로 4k)로 맞추어져 있어야 합니다.
zImage head 코드가 커널을 압축해제 하기 위해서 사용하는 메모리와의 충돌이 없어야 합니다, 아니면 체크 없이 덮어쓰게 될 것입니다.
7. 콘솔 초기화
콘솔은 시스템이 초기화될 때 커널이 무엇을 수행하는 지를 볼 수 있는 방법으로 매우 권장됩니다. 일반적인 경우인 비디오 프레임 버퍼 드라이버나 시리얼 드라이버 같은 적절한 드라이버로 어떤 입출력 장치도 사용될 수 있습니다. ARM 리눅스가 실행되는 시스템은 거의 항상 시리얼 콘솔 포트를 가지고 있습니다.
부트 로더는 부트로더 상에서 한 개의 시리얼 포트를 초기화하고 쓸 수 있도록 만들어야 합니다. 이 것은 그 포트를 사용하기 위한 하드웨어적인 파워 관리 같은 것들을 포함합니다. 이 것은 커널 시리얼 드라이버가 (일반적으로 디버깅 목적이나 타겟과의 통신 용도로 사용되는) 커널 콘솔로 사용되는 시리얼 포트를 자동으로 찾을 수 있도록 합니다.
아니면 부트로더는 linux/Documentation/kernel-parameters.txt에 설명된 Serial format 옵션과 포트를 지정하는 tagged list를 통해 이에 관련된 ‘console=’ 옵션을 커널로 전달할 수 있습니다.
8. 커널 파라미터
부트로더는 커널로 수행한 셋업, 시스템의 메모리의 크기와 영역, 그리고 필요시에는 다른 여러 값들을 설명하는 파라미터를 넘겨야 합니다.
Tagged list는 다음 제약 사항을 따라야 합니다.
리스트는 램에 저장 되어져야만 하고 커널 압축 해제기나 initrd 처리가 덮어쓰지 않는 메모리 영역에 위치해야만 합니다. 권장되는 곳은 RAM의 첫번째 16KiB 안이고, 일반적으로 물리 RAM의 시작에서 (Zero page exception 벡터를 피하기 위해서) 0x100 더하여 진 곳에 위치합니다.
Tagged list의 물리 주소는 커널로의 진입 시점에 R2 레지스터에 저장되어져 있어야 합니다. 예전에는 이 것이 필수적이지는 않았고, 커널이 물리 램의 시작에서 0x100 더한 곳을 고정값으로 사용했었습니다. 앞으로는 이렇게 하지 않을 겁니다.
리스트는 커널이 초기 페이지 테이블을 생성하는 0x4000 경계까지 확장되면 안됩니다.
리스트는 (권장되는 위치를 사용하지 않는다면) word 크기(32비트, 4바이트)로 맞추어져야 합니다.
리스트는 ATAG_CORE로 시작해서 ATAG_NONE으로 끝나야 합니다.
리스트는 ATAG_MEM을 적어도 하나는 포함해야 합니다.
리스트의 각 태그는 양수 32비트로 된 size와 tag, 두개의 값을 포함하는 헤더와 그 태그의 값들로 구성됩니다.
struct atag_header {
u32 size; /* legth of tag in words including this header */
u32 tag; /* tag value */
};
데이터를 갖지 않는 ATAG_NONE와 필요하면 데이터를 쓰는 ATAG_CORE를 제외한 각 태그 헤더에는 그 태그와 관련된 데이터가 뒤따릅니다. 데이터의 크기는 헤더 안의 size 필드에 의해 결정되는데 이 값은 헤더 크기를 포함하기 때문에 최소 사이즈는 2입니다. ATAG_NONE은 size 필드를 0으로 셋팅해야 하는 유일한 태그입니다.
한 태그에는 덧붙여지는 정보 크기를 제공하는 필수 구조체 뒤에 추가 데이터를 포함할 겁니다. 이 것은 추후에 커널로 제공하는 데이터를 확장하기 위해서 사용될 수 있습니다. 예를 들면 부트 로더는 ATAG_SERIAL 안에 추가적인 제품 일련 번호 정보를 제공하여 이를 위해 수정된 커널이 이를 읽어갈 수 있도록 할 수 있습니다.
파라미터 리스트의 태그의 순서는 중요하지 않습니다. 중복된 태그에 대한 해석은 태그에 따라 다를 수는 있지만 필요한 만큼 여러번 포함 될 겁니다.
#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
static struct atag *params; /* used to point at the current tag */
static void
setup_core_tag(void * address,long pagesize)
{
params = (struct tag *)address; /* Initialise parameters to start at given address */
params->hdr.tag = ATAG_CORE; /* start with the core tag */
params->hdr.size = tag_size(atag_core); /* size the tag */
params->u.core.flags = 1; /* ensure read-only */
params->u.core.pagesize = pagesize; /* systems pagesize (4k) */
params->u.core.rootdev = 0; /* zero root device (typicaly overidden from commandline )*/
params = tag_next(params); /* move pointer to next tag */
}
static void
setup_mem_tag(u32_t start, u32_t len)
{
params->hdr.tag = ATAG_MEM; /* Memory tag */
params->hdr.size = tag_size(atag_mem); /* size tag */
params->u.mem.start = start; /* Start of memory area (physical address) */
params->u.mem.size = len; /* Length of area */
params = tag_next(params); /* move pointer to next tag */
}
static void
setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE; /* Empty tag ends list */
params->hdr.size = 0; /* zero length */
}
static void
setup_tags(void)
{
setup_core_tag(0x100, 4096); /* standard core tag 4k pagesize */
setup_mem_tag(0x10000000, 0x400000); /* 64Mb at 0x10000000 */
setup_mem_tag(0x18000000, 0x400000); /* 64Mb at 0x18000000 */
setup_end_tag(void); /* end of tags */
}
여기 있는 코드가 완전하긴 하지만 이 코드는 파마리터 셋을 위한 절대적으로 최소한의 필요사항만을 나타내고 있고, 앞서 설명된 이 절에서의 컨셉을 보여주기 위한 용도로 작성되었습니다. 실제 부트로더는 아마 추가적인 값들을 전달하고 고정값을 사용하는 것보다는 실제 시스템 메모리에서 알아낸 값을 사용할 것입니다. 더 완전한 예제는 부록 B. 완전한 예제에서 볼 수 있습니다.
9. ARM 리눅스 머신 타입 얻기
부트 로더가 제공할 필요가 있는 추가 정보는 각 ARM 시스템에서 MACH_TYPE으로 불리는 간단하고 유일한 수, 머신 타입 뿐입니다.
머신 타입 넘버는 ARM 리눅스 웹사이트의 Machine Registry 페이지에서 획득할 수 있습니다. 머신 타입은 가능한한 프로젝트 초기에 획득해야 합니다. 커널이 그 스스로(머신 정의값들 등)를 포팅하는 것은 수많은 결과를 만들 수 있고 이후에 정의값들을 바꾸는 것은 수많은 원치 않는 문제를 만들 수 있습니다. 이 값들은 커널 소스 (linux/arch/arm/tools/mach-types) 안에 정의된 리스트에 의해 표현됩니다.
부트 로더는 어떤 방법으로든 실행될 머신의 타입을 획득해야 합니다. 그 방법이 하드 코딩된 값이던 연결된 하드웨어에서 탐색하는 어떤 알고리즘이던 상관없습니다. 그 구현 방법은 문서의 범위를 넘어섭니다.
10. 커널 시작하기
부트 로더가 다른 모든 단계를 수행했다면 CPU 셋팅에 정확한 값들로 커널의 실행을 시작해야 합니다.
진입 제약 사항은:
CPU 는 IRQ 와 FIQ 모두 꺼진 상태로 SVC (supervisor) 모드에 있어야 합니다.
MMU는 반드시 꺼져 있어야, 즉 물리 램에서 주소를 변환하지 않는 상태로 코드가 실행되어야 합니다.
데이터 캐시는 반드시 꺼져 있어야 합니다.
인스트럭션 캐시는 켜져 있건 꺼져있건 상관없습니다.
CPU 레지스터 0 은 0 이어야 합니다.
CPU 레지스터 1 은 ARM 리눅스 머신 타입이어야 합니다.
CPU 레지스터 2 는 파라미터 리스트의 물리 주소여야 합니다.
부트 로더는 커널 이미지의 첫번째 명령으로 직접 점프하여 커널 이미지를 호출할 것입니다.
A. 태그 레퍼런스
ATAG_CORE
ATAG_CORE — 리스트의 시작으로 사용되는 시작 태그
값
0x54410001
크기
5 (빈 데이터면 2)
구조체 멤버
struct atag_core {
u32 flags; /* bit 0 = read-only */
u32 pagesize; /* systems page size (usually 4k) */
u32 rootdev; /* root device number */
};
설명
어떤 부트 로더도 전달해야만 하는 기본 정보를 포함하는 리스트의 시작은 다른 구조가 뒤에 붙지 않는 것을 나타내는 길이 2의 이 태그가 되어야 합니다.
ATAG_NONE
ATAG_NONE — 리스트의 끝으로 사용되는 끝 태그
값
0x00000000
크기
2
구조체 멤버
없음
설명
이 태그는 리스트의 끝을 나타내는데 사용됩니다. 헤더 안의 size 필드가 (2가 아닌) 0 이 되는 유일한 태그입니다.
ATAG_MEM
ATAG_MEM — 물리 메모리 영역을 설명하는데 사용되는 태그
값
0x54410002
크기
4
구조체 멤버
struct atag_mem {
u32 size; /* size of the area */
u32 start; /* physical start address */
};
설명
커널이 사용하는 물리 메모리 영역을 설명합니다.
ATAG_VIDEOTEXT
ATAG_VIDEOTEXT — VGA test 타입 디스플레이를 설명하는 데 사용되는 태그
일반적으로 ATAG_RAMDISK와 같이 사용되는 압축된 램디스크 이미지의 위치. 커맨드 라인 파라미터의 ‘root=/dev/ram’으로써 초기 루트 파일 시스템으로 사용될 수 있습니다. 이 태그는 원래 가상 주소를 사용하는 ATAG_INITRD를 대신함으로써 문제가 될 수 있습니다. 모든 새로운 부트 로더는 이 태그를 사용하는 것이 좋습니다.