docker에 대해 알아보던 중 docker를 이미지로 설치할 때 우분투 환경에서만 링크로 설정하여야 한다는 것을 보게되었다.


왜 그런지 알아보던 중 한 분이 해당 url을 알려주셨다. 


ubuntu 패키지에는 이미 그래픽환경을 위한 system tray로 docker라는 것이 존재한다. (새삼 깨달았다.. 그 이름이 docker라는 걸..)


이것과의 혼동을 피하기 위해 docker.io 형태로 지원을 한다. 이것을 사용하려면 링크를 걸어줘야 한다.



해당 url은 Docker가 무엇인지 대략적으로 간단하게 설명하고 있다.

https://www.maketecheasier.com/running-docker-io-under-ubuntu-linux/




Running Docker.io Under Ubuntu Linux


우분투 리눅스에서 Docker.io 실행





As powerful hardware has become more and more of a commodity, the ability to run multiple virtual machines on a single piece of hardware has become an industry norm. From web hosting to cloud computing, many services are run on virtualized environments. As well as desktop virtualization solutions like VirtualBox, there are also quick provisioning solutions like Vagrant. The problem with a virtual machine is that it needs to emulate every aspect of the guest computer including all the system RAM which will be allocated exclusively to the virtual machine. As a result, virtualization can be resource hungry.

파워풀한 하드웨어가 상품화 되어지면서, 하나의 하드웨어에서 여러 virtual machines을 실행하는 능력은 업계의 표준이 되었다.

클라우드 컴퓨팅을 위한 웹 호스팅으로 부터, 많은 서비스들은 가상 환경에서 동작한다.

VirtualBox같은 가상화 솔루션을 더불어 Vagrant와 같은 빠른 프로비저닝 솔루션 또한 있다.

가상머신의 문제는 오직 가상머신을 위해 할당 될 모든 시스템 메모리를 포함하여 게스트 컴퓨터의 모든 측면을 에뮬레이트 해야할 필요가 있다는 것이다. 결과적으로 가상화는 자원부족이 될 수 있다.



At the other end of the spectrum is a “chroot” environment, which changes the underlying root directory for a process so that it runs in its own environment and has no access to other files on the host operating system. However, there is no virtualization at all, just a different directory tree.

극단적으로??, 프로세스를 위해 원래의 root directory를 바꾸며 자신의 환경에서 실행되고 호스트 OS상의 다른 파일에게 액세스하지 않는 "chroot" 환경이다. 하지만 이것은 가상환경이 아니며 단지 다른 device tree일 뿐이라는 것이다.



The mid-point between these two systems is a container. Containers offer many of the advantages of a virtualized machine but without the high resource overhead. Containers are more functional than chroot environments in that there is some virtualization. For example, processes that are created in a container are assigned IDs (PIDs) separately from those in the host OS. In technical terms, the container has its own PID namespace. In fact, containers have their own namespace for the networking subsystem and for InterProcess Communication (IPC). That means that a container can run network services, like a SSH server or a web server.

이 두 시스템 사이에서의 중간 포인트는 컨테이너이다. 컨테이너는 많은 자원의 오버헤드 없이 가상화된 머신에서 많은 어드밴티지를 제공한다. 컨테이너는 가상화 환경에서 chroot 환경보다 더 functional하다. 예를들어 컨테이너 기술로 생성된 프로세스들은 Host OS로부터 각각 PIDs를 가진다. 즉 컨테이너는 그들 자신의 PID namespace를 갖는다. 사실 컨테이너는 네트워킹 서브시스템과 IPC를 위해 스스로의 namespace를 갖고있다. 이 말은 컨테이너는 SSH 서비스나 web server 같은 네트워크 서비스를 수행할 수 있다는 의미이다.



From the outside, the container looks like a virtual machine with its own IP address and its own networking services, but on the inside the container uses much more of the host operating system than a virtual machine, more like a “chroot” environment. For example, you can use a CentOS container running on a Ubuntu host. The commands and files are all from CentOS, but if you ask the container which kernel it is running, it will report it is running the Ubuntu kernel, because the container is running on the kernel from the host OS.

외부로부터, 컨테이너는 자신만의 IP address와 자신만의 네트워크 서비스들을 갖는 가상머신처럼 보이지만 컨테이너 내부에서는 가상머신보다 "chroot"환경에 더 가까운 host OS를 사용한다. 예를들어 Ubuntu host 위에서 CentOS 컨테이너를 동작시킬 수 있다. 모든 명령과 파일들은 CentOS 기반으로 동작하지만 만약 컨테이너에게 실행중인 커널을 물어본다면 컨테이너는 Host OS의 커널에서 동작하므로 Ubuntu 커널에서 동작하고 있음을 알릴 것이다. 



Docker is a container based virtualization framework that allows you to create containers holding all the dependencies for an application. Each container is kept isolated from any other, and nothing gets shared.

Docker는 가상 framwork 기반의 컨테이너 기술로 application을 위한 모든 dependencies에 대해 홀딩상태의 컨테이너를 생성할 수 있다. 각각의 컨테이너는 독립을 유지하며 공유를 하지 않는다. 



To install Docker on a 64-bit Ubuntu 14.04 system, run the following commands:

Ubuntu 14.04 시스템 기반에서 Docker를 설치하기 위해서는 다음 명령어를 수행한다.






There is an existing Ubuntu package called docker, which is a system tray for KDE3/GNOME2. To avoid confusion, the container runtime is called docker.io. The last command creates a link from “/usr/local/bin/docker” to “/usr/bin/docker.io”, which enables the docker command from the command line rather than docker.io.

Ubuntu 패키지에는 "docker"라고 불리는 KDE3/GNOME2를 위한 시스템 트레이가 있다. 혼란을 피하기 위해 컨테이너 실행시간은 docker.io라고 불린다. 마지막 명령에서는 “/usr/local/bin/docker”로부터 “/usr/bin/docker.io”에게 링크를 생성하며, 이것은 docker.io 대신 커맨드라인으로 docker 명령의 수행을 가능하게 한다.



Note: Docker.io is also available for other distro. Here is the installation instructions if you are not using Ubuntu.

Docker.io는 다른 리눅스 배포판에서도 사용할 수 있다. 만약 Ubuntu를 사용하지 않는 다면 여기 설치 명령이 있다.



To execute a shell inside the container, run:

container에서 shell을 실행하기, "run" :





The “-i” flag makes the session interactive, and the “-t” flag tells docker to emulate a terminal session. The “ubuntu” parameter tells docker to run a container based on Ubuntu 14.04 and “/bin/bash” is the command that should be run once the container is up, i.e. run the Bash shell.

"-i" 플래그는 session 상호작용을 만들고, "-t" 플래그는 docker에게 terminal session을 에뮬레이트하라고 한다. "ubuntu"는  Ubuntu 14.04 기반으로 container를 수행하라는 파라미터이며, "/bin/bash"는 컨테이너가 뜰 때 수행할 필요가 있는 명령이다. 즉, Bash shell을 실행한다. 



When docker runs it checks if the desired base image file has been previously downloaded. If it hasn’t, it will download the image from index.docker.io, which is also the site to use to see which images are officially supported by docker.

docker가 run 할때, 만약 원했던 base image 파일이 이미 다운되어져 있다면 확인한다. 만약 다운되어있는 base image 파일이 없다면 docker로 부터 공식적으로 지원되는 이미지를 사용하고 볼 수 있는 사이트인 index.docker.io에서 이미지를 다운로드 할 것이다. 



To download other images without starting a container, use the “docker pull” command. For example, to download the CentOS base image use:

컨테이너의 사작없이 다른 이미지를 다운로드 하려면 "docker pull" 명령을 사용하면 된다. 예를들어, CentOS base image 다운로드는 다음과 같다.





You can also run single commands in a container and then let the container exit. Use the following command to run the “ps aux” command inside the CentOS container:

또한 컨테이너에서 하나의 명령을 실행한 다음 컨테이너를 종료할 수 있다. 실행을 위한 명령은 CentOS 컨테이너 내부의 "ps aux"를 사용한다. 





When a container shuts down, all changes are lost. The advantage of this approach is that when a container starts, it is in a known state. This is essential for test environments and for build services, etc. It is also important for running cloud services, as the container can be quickly reset and rebooted into a stable state.

컨테이너가 shutdown 될 때, 모든 변경사항은 지워진다. 이것의 장점은 컨테이너가 시작할 때의 알려진 상태에 있다는 것이다. 이것은 테스트환경과 서비스 빌드와 기타 등등에 필수적인 것이다. 또한 컨테이너가 안정된 상태의 빠른 reset과 reboot 을 할 수 있는 것과 같의 클라우드 서비스의 실행을 위해 중요하다. 



However, it also means that any configuration performed or any files created in the container will be lost. The solution is to create a new image with all your changes. Try the following commands:

하지만 이것은 컨테이너에서 설정한 구성과 생성된 파일들의 손실될 것을 의미한다. 해결방법은 모든 변경사항에 대해 새로운 이미지를 생성하는 것이다. 다음의 명령어이다. 





The first command will start a container and install nmap. The second command will list the latest (-l) created container, even if it isn’t running.

첫번째 명령은 컨테이너를 실행하고 nmap을 설치할 것이다.

두번째 명령은 명령이 실행되지 않더라도 최신의 생성된 컨테이너 순으로 리스트업 할 것이다.





You can now create a snapshot of that container and save it to a new image:

이제 새로운 이미지를 위해 컨테이너를 스냅샷을 생성하고 저장할 수 있다. 





“1b498c2d502c” is the ID of the container as listed by the “docker ps -l” command. Now if you start a shell for the ubuntu-with-nmap container, it will have the nmap command pre-installed.

“1b498c2d502c”는 "docker ps -l" 명령어에 의해 리스트업 될 컨테이너의 ID이다. 이제 ubuntu-with-nmap 컨테이너를 위해 shell을 시작하려면, 설치 전 nmap 명령을 수행해야 한다.






There is plenty of information about docker in docker.io’s documentation, and there are also several example setups explained, including how to perform common tasks like running a python web app and running a SSH service.

docker.io's documentation에 docker에 대한 많은 정보가 있으며 설치를 설명하는 몇가지 예제와 python web app과 SSH 서비스 실행과 같은 작업을 수행하는 방법이 나와있다.


If you have any questions about docker, there is a strong docker community which should be able to help. You can also ask questions in the comment section below and we will see if we can help.

만약 docker에 대해 질문이 있다면 docker community를 이용할 수 있다. 해당 글에대한 질문은 아래에  comment를 남겨주면 우리가 보고 도움을 주겠다.




ARM System Developer's Guide  

- Designing and Optimizaing System Software




#####

Protected Regions

Initializing the MPU, Caches, and Write Buffer

Demonstration of an MPU System




#### 13. 메모리 보호 장치 (MPU, Memory Protection Units)


- protection : 원치 않는 액세스로부터 시스템 자원과 태스크들을 막아주는 것


- 시스템 자원 액세스를 제어하는 방법 : unprotected(비보호), protected(보호)

 unprotected systems

 소프트웨어에만 의존하여 시스템 자원을 보호

 protected systems

 하으뒈어와 소프트웨어 둘다에 의존하여 시스템 자원을 보호

* 프로세서의 기능과 제어 시스템의 요구사항에 맞춰 제어 방법을 선택


# Unprotected Embedded Systems

- 동작 중 메모리와 주변장치를 사용하돋록 강요하는 전용 하느웨어가 없음

- 시스템 자원을 액세스하기 위해 각 태스크들이 다른 모든 태스크와 동기를 맞춰야 함


# Protected Embedded Systems

- 시스템 자원의 액세스를 확인하고 제한하는 정용 하드웨어를 가짐

- 전용 하드웨어는 자원의 소유권을 가짐 (하드웨어 레벨에서 자원들을 모니터링하고 제어하는 특별한 권한)

- 소프트웨어 루틴보다 시스템을 더 잘 관리할 수 있음


# MPU : 능동적으로 시스템 자원을 보호하는 하드웨어

- 보호 시스템의 주요 보호대상 자원 : 메모리 시스템, 주변장치

- ARM의 주변장치는 일반적으로 메모리 매핑이 되어 있어 MPU는 두 자원을 보호하기 위해 동일한 방법을 제공(region을 이용)


# Region(영역) : 메모리 영역과 관련되어 있는 속성들의 집합

프로세서 코어는 몇몇의 CP15 레지스서 안에 속성값들을 저장(각 영역은 0-7의 번호로 규정)

- 메모리 경계는, 시작주소와 4KB와 4GB사이의 2의 지수로 설정되는 크기두 속성 값을 사용해 설정됨

=> 이 영역에 접근권한, 캐시쓰기정책(캐시 및 write buffer)와 같은 추가의 속성을 할당

* 접근권한 : RW, RO, no-access, 추가권한 : 현재 프로세서 모드(유저/특권 모드)

- 프로세서의 메인메모리 영역에 대한 접근 제어 : 

프로세서의 접근권한 및 현재 프로세서 모드를 비교하여 메모리 액세서를 허용하거나 abort 신호를 발생하여 메모리 액세스를 차단

- abort 신호 : exception 처리로 abort  handler로 분기하도록 한 후 처리를 위해 적절한 서비스 루틴으로 분기

* abort type : prefetch abort, data abort



### 13.1. Protected Regions


- ARM740T, ARM940T, ARM946E-S, ARM1026EJ-S


ARM940T

- 16개의 Protected Regions

- 명령어 메모리와 데이터 메모리를 제어하기 위한 분리된 영역을 가짐

- 코어는 명령어와 데이터 영역에ㅐ 대해 다른 영역 크기와 시작주소를 할당할 수 있음

- region 번호 : 0-7 사이의 번호로 할당되지만 명령어 영역과 데이터 영역의 pair로 이루어짐(8개씩)


ARM740T, ARM946E-S, ARM1026EJ-S

- 8개의 Protected Regions

- 명령어 영역과 데이터 영역이 통합

=> 데이터영역과 명령어영역은 크기와 시작주소를 설정하기 위해 똑같은 레지스터를 사용

메모리 접근 권한과 캐시 정책

ARM740T : 명령어와 데이터 액세스를 동일하게 적용 

ARM946E-S, ARM1026EJ-S : 명령어 액세스와 데이터 액세스를 독립적으로 설정 가능

- region 번호 : 코어가 폰노이만 아키텍처인지 하버디 아키텍처인지에 상관없이 독립적이며, 

각 영역은 0-7 사이의 번호로 할당


> region 제어를 위한 몇가지 규칙 <

1. 영역은 다른 영역에 overlap 될 수 있음

2. 영역은 영역에 할당되어 있는 특권에 독립적인 우선순위가 할당

3. 영역이 overlap 되면, 가장 높은 우선순위를 가진 영역 속성이 다른 영역에 대해 우선순위를 가짐.

* 우선순위는 overlap된 영역내의 주소에 대해서만 적용

4. 영역의 시작주소는 그 크기의 배수여야 함

5. 영역의 크기는 4KB-4GB 사이의 2의 지승의 값이여야 함(4KB, 8KB, 16KB, 32KB, 64KB, ...., 2GB, 4GB)

6. 정의된 영역 밖에 있는 메인메모리의 영역에 액세스를 시도하면, abort를 발생

- 명령어를 페치하고 있었다면 prefetch abort가 발생,

- 데이터를 위한 메모리 요청이었다면 data abort가 발생



## 13.1.1. Overlapping Regions

- Overlapping : 한 영역에 할당되어 있는 메모리 공간의 일부가 다른 메모리 영역에 할당되어있는 메모리 공간 안에 있는경우

* 접근 권한은 할당 할 때 overlap을 지원하지ㅏ 않는 영역보다 큰 유연성을 제공


ex. 가정 : 0x000000000 주소에서 시작하는 256KB의 메모리에서, user mode로 액세스가 불가능하도록 특권 시스템 영역에서 보호 중


특권영역의 코드와 데이터 스택이 벡터테이블 0x00000000에서 시작하는 32KB의 영역안에 맞춰져 있음

남은 공간은 user 공간으로 할당되어 있음

- overlap 영역과 함께 시스템은  256KB의 유저영역과 32KB의 특권 영영의 두 영역을 사용

- 특권영역 1은 속성이 유저역역 0보다 우선순위가 높음


## 13.1.2. Background Regions

- 큰 메모리 영역에 동일한 속성을 할당하는 데 사용되는 가장 낮은 우선순위의 영역

- 더 높은 우선순위를 가진 다른 영역들은,

 정의된 background 영역보다 적은 영역의 속성을 변경하기 위해서 background 영역에 overlapping 됨.

=> 더 높은 우선순위의 영역은 background 영역의 속성 일부를 변경하면 됨

- background 영역의 또 다른 부분은 다른 영역의 제어하에 활성화 됨

=> 원치 않는 액세스로 부터 몇몇 사용되지 않은 메모리 영역을 보호함


- 커다란 특권 영역을 정의하고 있을 때, background 영역이 오버랩되어 더 작은 비특권 영역을 정의할 수 있음

- 더 작은 비특권 영역은 다른 유저 공간을 나타내기 위해 background 영역의 다른 영역으로 이동 할 수 있음

이전에 관리되던 영역은 background 영역에 의해 보호됨

=> user 영역은 특권 배경의 다른 부분을 액세스 하지만, user 레벨 속성을 갖는 윈도우로 동작


> 3개의 간단한 태스크 보호 방법 < 

- 영역 3은 active task의 보호 속성을 정의

- background 영역 0은 non-active한 태스크로의 액세스를 통제

- task 1이 active 할 때, background 영역은 task 1로부터 task 2와 task 3을 보호

- task 2가 active 할 때, background 영역은 task 2로부터 task 1과 task 3을 보호

task 3이 active 할 때, background 영역은 task 3로부터 task 1과 task 2를 보호

=> 영역 0이 특권모드로써 더 높은 특권을 가지고는 있지만, 영역 3이 우선순위가 더욱 높기 때문



### 13.2. Initializing the MPU, Caches, and Write Buffer


MPU, Caches, Write Buffer의 초기화를 위해, 제어 시스템은 타겟이 동작하는 동안 필요로하는 보호 영역을 정의해야 함

- 최소한 보호 장치를 enable하기 전 적어도 하나의 데이터 영역과 하나의 명령어 영역을 정의해야 함

- 제어 시스템은 기본 CP15 레지스터인 c1, c2, c3, c4, c5, c6의 값을 설정하여 MPU를 설정


> MPU 동작 제어를 위한 CP15의 레지스터들

* c1 : 기본 컨트롤 레지스터


- c2, c3으로 영역의 cache와 write buffer의 속성이 설정

- c5 : 영역 접근 권한 제어

- c6 : 각 영역의 위치와 크기를 정의하며 8 or 16개의 보조 레지스터를 가짐


> MPU, caches, write-buffer의 초기화 수행 단계

1. CP15:c6를 사용하여 명령어 및 데이터 영역의 크기와 위치를 정의

2. CP15:c5를 사용하여 각 영역에 대한 접근 권한을 설정

3. 캐시를 위해서는 CP15:c2, write-buffer를 위해서는 CP15:c3를 사용하여 각 영역을 위한 cache, write-buffer의 속성을 지정

4. CP15:c1을 사용하여 캐시와 MPU를 enable.


# 13.2.1. Defining Region Size and Location

- CP15:c6:c0:0 - CP15:c6:c7:0 까지의 8개의 보조 레지스터 중 하나의 값을 설정하여 각 영역의 크기와 주소 범위를 정의

=> 보조 코프로세서 레지스터 숫자는 각 영역의 ID에 매핑

- 각 영역의 시작주소는 그 크기의 배수인 주소로 정렬

ex. 영역의 크기 128KB, 0x20000의 배수가 되는 어떤 주소에서 시작


> 8개의 보조 레지스터 CP15:c6:c0 - CP15:c6:c7의 포맷과 비트필드



- base address : 상위 [31-12], 비트필드의 배수여야 함.

- 비트필드 : [5-1]

- E 필드 : [0]. 영역을 enable/disable

=> 영역은 정의 된 후 E비트가 0으로 disable되어 있다가, 1로 설정되면 enable 됨

- 사용하지 않는 비트들은 0으로 설정되어야 함

- 영역의 크기는 "size = 2^(N+1)" 또는 영역크기 인코딩 값(표 13.4)을 참고        
????, N(크기)의 2배수 값이 base address가 되야한 다는 게 이해가 잘..안됨
- N : 크기 설정을 위해 지수 값 설정.(4KB~4GB를 의미하는 11~31의 정수값)


- ARM740T, ARM946E-S. ARM1026EJ-S는 8개의 영역을 갖고,

 CP15:c6:cX 안의 보조 레지스터에 값을 설정하여 한 영역의 크기와 위치를 결정


ex. 영역 3을 시작위치 : 0x300000, 크기 : 256KB 로 설정하기


MOV    r1, #0x300000           ;시작 위치 : 0x300000

ORR     r1, r1, #0x11<<1        ;크기 : 256KB

MCR    p15, 0, r1, r6, c3, 0    ; CP15 보조 레지스터 값 쓰기



- ARM940T는 8개의 데이터영역과 8개의 명령어 영역을 각각 가짐

명령어 영역과 데이터 영역을 선택하기 위해 추가로 "opcode2"를 가짐


ex. 데이터 영역 5, 명령어 영역 5의 크기와 위치 읽기(2개의 MRC명령어가 필요함)


MCR    p15, 0, r2, c6, c5, 0    ; r2 = base address / size, 데이터 영역 5   => r2에 데이터 영역 5의 크기와 시작주소 로드

MCR    p15, 0, r3, c6, c5, 1    ; r3 = base address / size, 명령어 영역 5   => r3에 명령어 영역 5의 크기와 시작주소 로드


> Example 13.1 <

: 영역의 시작주소, 크기, E bit를 설정하는 방법


* C 프로토 타입

void regionSet(unsigned region, unsigned address, unsigned sizeN, unsigned enable);

enable : 속성 변경 중에는 비활성화, 변경이 완료되면 활성화


- 명령어 영역과 데이터 영역을 위해 동일한 크기와 시작주소 정보를 설정하여 ARM940T 영역을 하나로 통합

=> ARM940T용과 다른 코어용의 두 부분으로 분리하여 매크로를 작성

=> SET_REGION 매크로 : 동일한 루틴으로 4개의 MPU 코어를 지원,

정의된 영역을 위해 CP15:c6 보조 레지스터에 값을 설정하여 시작주소, 크기, 활성상태를 설정 


- address, sizeN, enable의 영역 속성을 c6f라는 unsigned 정수에 통합

- SET_REGION매크로로 만들어진 8개의 regionSet 루틴 중 하나로 분기


# 13.2.2. Access Permission

- 접근권한 방식의 2가지 : 표준 설정 방식, 확장 설정 방식


> CP15 레지스터 6 접근권한 


ARM740T, ARM940T, ARM946E-S, ARM1026EJ-S : 표준 설정 방식 지원

- 최신의 ARM946E-S, ARM1026EJ-S : 확장 설정 방식도 지원하며 2가지 레벨의 권한도 지원

- 확장설정 비트 필드 AP : 12개의 추가 권한 값을 지원하며, 비트 중 2개만 현재 할당되어 사용

- 정의되지 않은 인코드 값의 사용은 예기치 못한 동작을 발생


> 레지스터에 접근권한 부여

: CP15:c5 안의 보조 레지스터에 값을 설정


- 표준 AP 설정 : CP15:c5:c0:0, CP15:c5:c0:1

- 확장 AP 설정 : CP15:c5:c0:2 or CP15:c5:c0:3


> AP 레지스터를 위한 레지스터의 권한 비트 할당과 CP15 레지스터 5 접근권한 레지스터 포맷


- 확장 권한을 지원하는 프로세서는 표준 권한을 위해 작성된 소프트웨어에서 실행이 가능

- AP 레지스터 마지막으로 쓰여진 것이 표준 AP 레지스터라면 코어는 확장 권한을 사용 ???????????????

=> 표준 AP 레지스터에 쓰이는 것은 확장 AP 영역 엔트리의 [2:3]비트가 0을 클리어 함을 의미. 

확장 AP 레지스터에도 업데이트 되기 때문 ??


# 표준 AP

- 레지스터 CP15:c5:c0:0, CP15:c5:c0:1 안의 두 비트를 사용


CP15:c5:c0:0 : 데이터를 위한 AP를 설정

CP15:c5:c0:1 : 명령어영역을 설정


- 명령어와 데이터메모리를 위한 표준 AP를 읽기 위해, 2개의 레지스터를 읽어야 하므로 두개의 MRC 명령어를 사용


MRC    p15, 0, r1, c5, c0, 0        ; 데이터 영역 표준 AP. r1에 데이터 영역 메모리를 위한 AP 정보를 저장

MRC    p15, 0, r2, c5, c0, 1        ; 명령어 영역 표준 AP. r2에 명령어 영역 메모리를 위한 AP 정보를 저장


# 확장 AP

레지스터 CP15:c5:c0:2, CP15:c5:c0:3 안의 4개의 비트 사용


하나의 레지스터 : 8개의 영역을 위한 명령어 정보를 저장

또 하나의 레지스터 : 데이터 정보를 저장


CP15:c5:c0:2 : 데이터 영역을 위한 AP 설정

CP15:c5:c0:3 : 명령어 영역을 위한 AP 설정


- 데이터 영역 및 명령어 영역 확장 AP를 얻기위해,  2개의 레지스터를 읽어야 하므로 두개의 MRC 명령어를 사용


MRC    p15, 0, r3, c5, c0, 2       ; 데이터 영역 표준 AP. r3에 데이터 영역 AP 저장

MRC    p15, 0, r4, c5, c0, 3       ; 명령어 영역 표준 AP. r4에 명령어 영역 AP 저장


> Example 13.2 & 13.3 <

: 접근 권한을 사용하는 예


표준 AP 비트를 설정하기 위한 2가지 표준 AP 루틴


void regionSetISAP(unsigned region, unsigned ap);

void regionSetDSAP(unsigned region, unsigned ap);


region : 영역 번호

ap : 영역에 의해 제어되는 명령어나 데이터 메모리를 위한 표준 AP


> Example 13.2 <

: 접근 권한을 사용하는 예(표준 AP)


void regionSetISAP(unsigned region, unsigned ap)

{

unsigned c5f, shift;


shift = 2 * region;                                    /*  영역의 큭를 권한 비트필드 안에 저장되어있는 비트 수의 배수로 정의  */

__asm{ MRC    p15, 0, c5f, c5, c0, 1 }    /*  표준 I AP 로드  */

c5f = c5f &~ (0x3 << shift);                    /*  이전 AP 비트 클리어  */

c5f = c5f | (ap << shift);                          /*  새로운 AP 비트 설정  */

__asm{ MCR   p15, 0, c5f, c5, c0, 1 }    /*  표준 I AP 저장  */

}


void regionSetISAP(unsigned region, unsigned ap)

{

unsigned c5f, shift;


shift = 2 * region;                                    /*  영역의 크기를 권한 비트필드 안에 저장되어있는 비트 수의 배수로 정의  */

__asm{ MRC    p15, 0, c5f, c5, c0, 0 }    /*  표준 D AP 로드  */

c5f = c5f &~ (0x3 << shift);                    /*  이전 AP 비트 클리어  */

c5f = c5f | (ap << shift);                          /*  새로운 AP 비트 설정  */

__asm{ MCR   p15, 0, c5f, c5, c0, 0 }    /*  표준 DI AP 저장  */

}


> Example 13.3 <

: 접근 권한을 사용하는 예(확장 AP)


void regionSetIEAP(unsigned region, unsigned ap);

void regionSetDEAP(unsigned region, unsigned ap);


region : 영역 번호

ap : 영역에 의해 제어되는 명령어나 데이터 메모리를 위한 표준 AP


void regionSetIEAP(unsigned region, unsigned ap)

{

unsigned c5f, shift;


shift = 4 * region;                                    /*  영역의 크기를 권한 비트필드 안에 저장되어있는 비트 수의 배수로 정의  */

__asm{ MRC    p15, 0, c5f, c5, c0, 3 }    /*  확장 D AP 로드  */

c5f = c5f &~ (0x3 << shift);                    /*  이전 AP 비트 클리어  */

c5f = c5f | (ap << shift);                          /*  새로운 AP 비트 설정  */

__asm{ MCR   p15, 0, c5f, c5, c0, 3 }    /*  확장 D AP 저장  */

}


void regionSetIEAP(unsigned region, unsigned ap)

{

unsigned c5f, shift;


shift = 4 * region;                                    /*  영역의 큭를 권한 비트필드 안에 저장되어있는 비트 수의 배수로 정의  */

__asm{ MRC    p15, 0, c5f, c5, c0, 2 }    /*  확장 I AP 로드  */

c5f = c5f &~ (0x3 << shift);                    /*  이전 AP 비트 클리어  */

c5f = c5f | (ap << shift);                          /*  새로운 AP 비트 설정  */

__asm{ MCR   p15, 0, c5f, c5, c0, 2 }    /*  확장 I AP 저장  */

}



## 13.2.3. Setting Region Cache and Write Buffer Attributes


- CP15:c2:c0:0, CP15:c2:c0:1 : D캐시와 I캐시의 영역 속성값을 저장

- CP15:c3:c0:0 : 영역 쓰기 버퍼 속성을 저장, 메모리 데이터 영역에 제공


> CP15:c2 캐시와 CP15:c3 write buffer 영역 레지스터


> CP15:c2 및 CP15:c3 레지스터를 위한 비트필드 할당


CP15:c2:c0:1 : 8개의 명령어 영역을 위한 캐시 설정 데이터를 포함

CP15:c2:c0:0 : 8개의 데이터 영역을 포함

=> 둘 다  동일한 비트필드 인코딩 사용


> cache-bit : 캐시가 영역 내에 주어진 주소를 위해 활성화할지의 여부를 결정

-  ARM740T, ARM940T는 cache-bit에 상관없이 항상 캐시가 사용되므로

캐시의 정책이 cached->noncached로 변경되는 영역에서는 캐시를 flush(무조건), clean(가능하면) 해주는 것이 좋음

=> MPU 시스템은 캐시 정책이 write-through 방식에서 noncached 방식으로 변경될 때 항상 캐시를 flush 해야 함

=> write-back 방식에서는 캐시 flush와 clean을 모두 해야 함

- ARM946E-S 에서 cache-bit이 0이면 캐시안에 물리적 정보는 캐시로 복원되지 않고 외부 메모리 액세스가 수행됨

=> 캐시가 비활성화 되어 있을 때는 캐시를 flush하는데 필요한 요구사항을 줄여주지만, 오래된 영역에 대한 clean은 계속 적용 됨


CP15:c3:c0:0 : 8개의 영역 write buffer는 각 영역에 대한 write buffer의 활성화/비활성화를 조작


> 데이터 영역 설정 시 영역의 정책 결정

: write buffer bit, cache bit

 write buffer bit

 - 영역을 쓰기 위한 write buffer 활성화/비활성화 설정

 - 영역의 cache write policy를 설정

 cache bit

 - write buffer bit의 용도를 설정


 cache bit

  write buffer bit

 

 0

 0

 write buffer 비활성화 

 0

 1

 write buffer 활성화 

 1   

 0  

 write-through policy 적용

 1 1

 write-back policy 적용

(* cache와 write buffer 모두 활성화되고 write buffer bit은 캐시의 쓰기 정책을 판단)



> Example 13.4 <

: cache와 write buffer 활성화/비활성화 방법


- 인라인 어셈블러 사용

- cache와 write-buffer의 제어를 하나의 루틴 호출로 통합

- 캐시 쓰기 정책을 결정하기 위해서는 데이터 cache와 write buffer bit들을 모두 참조

- 명령어 cache bit은 단독 사용

* cache와 write-buffer의 상태를 각 영역을 위한 하나의 값으로 통합하면 영역 정보를 RCB로 모으는 것을 보다 쉽게 처리

(RCB : Region Control Block, 13.3.3절)


void regionSetCB(unsigned region, unsigned CB);

(region : 영역의 번호, CB : cache 속성 + write buffer 속성)



## 13.2.4. Enabling Regions and the MPU


# 초기화 과정

- 영역의 시작주소, 크기, E bit를 설정

- 접근권한 설정

- cache와 write buffer 활성화/비활성화

- 활성 영역을 enable : regionSet 루틴을 이용

- MPU, caches, write buffer를 enable : CP15:c1:c0:0안의 비트값을 수정

(CP15:c1:c0 안에 있는 MPU, caches, write buffer의 위치는 ARM940T, ARM946E-S, ARM1026EJ-S과 동일)


> Enable-bit의 위치


> CP15 컨트롤 레지스터 1에서의 보호 장치 활성 비트

> Example 13.5 < 

: MPU, caches를 enable하기 위해 "changeControl" 루틴을 사용

(but, changeControl 루틴은 CP15:c1:c0:0 레지스터 안에 있는 값들을 변경할 수 있음)???? 


void controlSet(unsigned value, unsigend mask);

(value : 변경할 비트를 포함하는 unsigned 정수 값, 

mask : 변경하기를 원하는 비트들을 선택하는데 사용. 

"value"와는 상관없이 1은 컨트롤 레지스터 안에 있는 비트를 변경, 0은 비트값이 변경되지 않고 그래도 유지되도록 함)


ex. MPU와 I캐시를 enabling, D캐시는 disabling        ????

=> [12]bit : 1,    [2]bit : 0,    [0]bit : 1

value : 0x00001001

mask : 0x00001005




### 13.3. Demonstration of an MPU System

: 고정된 메모리 맵을 사용하여 간단한 보호 시스템을 초기화하고 제어하기

(간단한 보호 멀티태스킹 시스템 안에서 동작하는 3개의 태스크를 enable)



## 13.3.1. 시스템 요구사항

- MPU를 가지는 ARM 코어

- 0x0에서 시작하고 0x40000으로 끝나는 256KB의 물리 메모리

- 0x10000000 ~ 0x12000000의 몇 MB 이상을 차지하는 메모리 매핑 된 몇가지 주변장치


* 모든 메모리 매핑된 주변장치는 보호를 필요로하는 하나의 메모리 영역으로 가정


- 시스템 소프트웨어는 크기가 64KB 이내

exception을 지원하기 위한 vector table, exception handler, data cache를 포함

- 시스템 소프트웨어는 user mode로 액세스 할 수 없음. system level의 권한을 갖음

=> user mode는 이 영역 안에 있는 코드나 데이터를 액세스 하기 위해 시스템 콜을 사용해야 함

- 크기가 64KB 이내인 공유 소프트웨어가 존재. 전체 시스템에 의해 액세스가 가능

user task 사이에 메시지를 보내기 위해 공통으로 사용되는 라이브러리와 데이터공간을 포함

- 시스템에서 독립적인 기능을 제어하는 3개의 user task가 존재. 

32KB 이내의 크기를 가짐. 실행될때는 각각 다른 2개의 task에 의한 액세스로부터 보호되어야 함

- 소프트웨어는 할당되어 있는 영역 내에서 소프트웨어 컴포넌트를 놓아두도록 연결


> 소프트웨어 메모리 맵


* 마지막 열에보면 영역은 4개임을 알 수 있음


> 영역 레이아웃을 나타내는 메모리 맵



## 13.3.2. 메모리맵을 사용하여 영역 할당하기


- Region 1 : 전체 메모리 공간을 사용할 수 있는 background 영역. 특권영역(어떤 user mode access라도 불가능)

명령어 캐시는 enabled, 데이터캐시는 write-back 방식으로 동작(??? why?)

가장 낮은 우선순위를 가짐

<기능> 

1. 0x0 ~ 0x10000사이의 64KB 공간을 제한적으로 액세스 하도록 함

2. 배경역역으로 동작하여 non-active한 user task를 위한 보호영역으로 동작

3. 배경 영역으로서는 디폴트로 전체 메모리 공간이 시스템 레벨의 액세스로 할당 되게 함

=> active한 user task에 인해 다른 user task가 액세스 되는 것을 보호


- Region 2 : 공유 시스템 자원을 액세스 하는 것을 제어

0x10000을 시작주소로 64KB의 크기를 가짐

공유 메모리 영역에 직접 매핑

보호된 영역 1의 일부분의 꼭대기에 위치하며 영역1보다 높은 우선순위를 가짐

user system 레빌의 메모리 액세스를 허용


- Region 3 : active한 task의 메모리 영역과 속성을 제어

context switching이 발생하는 동안 처럼,
     한 task에서 다른 task로 제어권이 넘어가면 OS는 영역 3이 실행중인 task의 메모리 영역과 overlap되도록 재정의를 수행함

새로운 task에 대한 위치가 다시 정해질 때, 이전 task는 영역 1의 일부가 되고 실행하는 task는 새롭게 영역 3이 됨

실행중인 task는 이전 task에 액세스 할 수 없음. (영역 1의 속성으로 보호되기 때문)


- Region 4 : 메모리 매핑된 주변장치의 공간

목적 : 해당 영역을 캐시와 버퍼를 사용하지 않는 영역으로 설정하는 것

이유? 캐시에 의해 발생되는 잘못된 데이터 문제와 write buffer를 사용할 대 포함 될 수 있는 시간이나 순서적 문제 때문에 

입력이나 출력 컨트롤 레지스터가 영향을 받지 않게 하기 위함



## 13.3.3. MPU의 초기화


# Region data type : 초기화 과정을 조직화 하기위해 만들어진 구조체

시스템 동작중에 사용되는 영역의 속성값들을 포함

MPU를 사용할 때에는 필요하지 않고 단지 예시 소프트웨어를 지원하기 위해 만들어낸, 설계상 편의를 목적으로 함

RCB(Region Control Block)


- 초기화 소프트웨어는 MPU안에 영역을 설정하기 위해 RCB 안에 저장된 정보를 이용

- RCB안에 정의되어 있는 Region 구조체는 물리적 영역보다 많이 있을 수 있음

ex. 영역 3은 task를 위해서만 사용되지만, 각 user task를 위해 영역 3을 사용하는 Region 구조체에는 3개가 있어야 함


typedef struct {

unsigned int number;            // Region에 할당되어 있는 MPU 영역 번호

unsigned int type;                  // 사용되는 접근 권한의 유형 (STANDARD, EXTENDED)

unsigned int baseaddress;     // 영역의 시작주소

unsigned int size;                   // 영역의 크기

unsigned int IAP;                    // 접근권한

unsigned int DAP;                  // 접근권한

unsigned int CB;                     // cache, write buffer 설정

} region;


- RCB 안에 저장되어있는 6개의 Region


> RCB 안에 있는 엔트리들에 대해 만든 매크로


- 4개의 문자 조합을 이용해 데이터와 명령어 메모리로의 접근권한을 입력

처음 2개 : system access permission, 나머지 2개 : user access permission

(RW / RO/ NA(no access))


- cache와 write buffer의 정보 : 명령어 캐시와 데이터 캐시 정책을 위한 속성으로 매핑

처음 문자 : C or c. 영역을 위한 명령어 캐시 활성화/비활성화

다음 2개 문자 : 데이터캐시 정책과 write buffer의 컨트롤 결정. 

WT : write-through, WB : write-back, 

Cb : =WT, CB : =WB, cB : 캐시를 사용하지 않고 버퍼만 사용, cb : 캐시와 버퍼 모두 사용하지 않음



## 13.3.4. 영역 설정 및 초기화


- "configRegion" 루틴(초기화 다음 단계에 위치)  

: 영역을 설명하는 데이터를 가지고 CP15레지스터를 조작하기 위해 RCB에서 하나의 Region 구조체 엔트리를 얻어 옴


void configRegion(region *region);

(*region : 영역의 RCB를 가리키는 포인터 값으로 루틴내에서 Region의 멤버들을 초기화 하는 과정에서 데이터 입력값으로 사용)


> MPU, cache, write buffer 초기화


void configRegion(Region *region) 

 /* Step 1 - Define the size and location of the instruction */

 /* and data regions using CP15:c6 */

regionSet(region->number, region->baseaddress, region->size, R_DISABLE);


/* Step 2 - Set access permission for each region using CP15:c5 */

if (region->type == STANDARD) { 

regionSetISAP(region->number, region->IAP); 

regionSetDSAP(region->number, region->DAP); 

else if (region->type == EXTENDED) 

{

regionSetIEAP(region->number, region->IAP); 

regionSetDEAP(region->number, region->DAP); 


/* Step 3 - Set the cache and write buffer attributes */ 

/* for each region using CP15:c2 for cache */ 

/* and CP15:c3 for the write buffer. */ 

regionSetCB(region->number, region->CB); 


/* Step 4 - Enable the caches, write buffer and the MPU */ 

/* using CP15:c6 and CP15:c1 */ 

regionSet(region->number, region->baseaddress, region->size, region->enable); 

}



## 13.3.5. MPU 초기화


- 모든 영역을 설명하는 데이터를 저장하기 위해 RCB를 사용

- MPU를 초기화 하기위해 "initActiveRegions"라는 상위레벨의 루틴을 사용

: 시스템이 시작될 때 활성화된 각각의 영역을 위해 한번씩만 호출

- MPU를 enable 시킴으로써 마무리


void initActiveRegions();        // 입력 파라미터 없음


- 시스템이 시작할 때 활성화 되어있는 영역인 

kernelRegion, shareRegion, peripheralRegion, task1Region을 위해 configRegion을 한번 씩 호출


#define ENABLEMPU (0x1) 

#define ENABLEDCACHE (0x1 << 2) 

#define ENABLEICACHE (0x1 << 12) 

#define MASKMPU (0x1) 

#define MASKDCACHE (0x1 << 2) 

#define MASKICACHE (0x1 << 12) 


void initActiveRegions() 

unsigned value,mask; 

configRegion(&kernelRegion); 

configRegion(&sharedRegion); 

configRegion(&peripheralRegion);

 configRegion(&task1Region); 


value = ENABLEMPU | ENABLEDCACHE | ENABLEICACHE; 

mask = MASKMPU | MASKDCACHE | MASKICACHE; 

controlSet(value, mask); 

}


=> 여기까지 시스템 초기화 완료!!!, 제어 시스템은 첫번재 태스크를 실행!!



## 13.3.6. 보호된 문맥전환

- 제어 시스템은 시스템 초기화가 완료 된 후 첫번재 태스트를 실행하며, 다른 태스크를 실행하기 위해 context switching을 수행

- RCB는 현재 task의 영역 문맥 정보를 포함하므로 CP15 레지스터로부터 영역 데이터를 저장할 필요가 없음


- (그림 13.7)에서 task 2로 변환하기 위해 OS는 region 3을 task 2의 메모리 영역으로 변경

- 현재 task와 다음 task 사이의 context switching을 수행하는 코드를 실행하기 전, 

초기화의 일부로 이 함수를 수행하기 위해 configRegion 루틴을 다시 사용 

- configRegion으로의 입력 값 : taask2Region


STMFD sp!, {r0-r3,r12,lr} 

BL configRegion 

LDMFD sp!, {r0-r3,r12,pc}     ; return


- C 함수


configRegion(&task2Region);



## 13.3.7. mpuSLOS

: SLOS(11장) 메모리 보호 장치를 추가한 제어시스템


> 기존 SLOS와의 차이점

mpuSLOS는 MPU를 완전히 사용

- applications는 커널과 분리되어 컴파일 디고 빌드된 다음 하나의 바이너리 파일에 통합

각 application은 다른 메모리 영역에서 실행되도록 링크 됨

- 3개의 applications은 각각 Static Application Loader 라는 루틴에 의해 32KB 크기의 분리된 고정 영역으로 로딩

이 주소는 Application의 시작 주소임

각 영역은 32KB의 크기를 가지므로 스택 포인터는 32KB의 상위값으로 설정

- applications는 device driver call에의해서만 하드웨어를 액세스

만약 application이 직접 하드웨어를 액세스 하려고 한다면 data abort가 발생 

(SLOS와 다른점. device가 application으로부터 직접 액세스 될 때는 data abort가 발생하지 않음)

- applications으로 분기하는 것은 spsr을 설정한 다음, 

MOVS 명령어를 사용하여 pc가 task1을 가리키는 엔트리포인터의 값으로 변경하는 작업을 포함

- 스케줄러가 호출될 경우에는 언제나 활성화된 영역2는 새로 실행되는 application을 반영하도록 변경 됨




### 13.4. Summary


# 메모리 protection

1.  unprotected : 태스크 상호 작용을 위한 규칙들을 관리하기 위해 소프트웨어적인 제어 루틴을 사용

2. protected : 태스크 상호작용을 관리하기 위해 하드웨어와 소프트웨어를 둘 다 사용.

=> 보호 시스템에서 접근권한이 침범을 받은 경우 하드웨어적으로 abort를 발생하여 메모리 영역을 보호함

소프트웨어는 발생한 abort 루틴을 처리하고 메모리 기반의 자원을 제어하도록 반응


# Region : ARM MPU가 시스템 보호를 위한 기본적으로 사용하는 struct

메모리 영역과 관련되어 있는 속성값들의 모임을 말함

# Backgroud Region : 영역은 overlap 될 수 있으므로,

현재 실행중인 태스크에 의한 원치않은 액세스로 부터 non-active한 상태의 task의 메모리를 보호하기위해 사용


# MPU를 초기화하는 단계

1. CP15:c5을 사용하여 명령어 및 데이터 영역의 크기와 위치를 설정

2. CP15:c5를 사용하여 각 영역에 대한 접근 권한을 설정

3. 각 영역을 위한 cache와 write buffer 속성을 지정

CP15:c2 : 캐시 설정

CP15:c3 : write buffer 설정

4. CP15:c6를 사용하여 활성화 영역을 Enabled

5. CP15:c1을 사용하여 cache, write buffer, MPU를 enabled


# 간단한 멀티태스킹 환경에서의 보호에 대한 예제

1. 보호 시스템 정의

2. 초기화

3. 초기화 후 보호시스템을 실행하는 데 필요한 태스크 변환 및 태스크로 영역할당 받기


# mpuSLOS






'System > Embedded' 카테고리의 다른 글

[ARM] 캐시 2  (0) 2015.11.12
[ARM] 캐시  (0) 2015.11.12
[ARM] 펌웨어  (0) 2015.11.12
[ARM] 익셉션과 인터럽트 처리 2  (0) 2015.11.10
[ARM] 익셉션과 인터럽트 처리  (0) 2015.11.10

- Open Firmware

- FDT


- FPGA 참고



The Flattened Device Tree is...

The Flattened Device Tree (FDT) is a data structure. Nothing more.

It describes a machine hardware configuration. It is derived from the device tree format used by Open Firmware. The format is expressive and able to describe most board design aspects including:

  • the number and type of CPUs,
  • base addresses and size of RAM,
  • busses and bridges,
  • peripheral device connections, and
  • interrupt controllers and IRQ line connections.

Just like initrd images, an FDT image can either be statically linked into the kernel or passed to the kernel at boot time.


(출처. http://elinux.org/Device_Tree)


참고. http://blog.dasomoli.org/491


'System > Etc.' 카테고리의 다른 글

git  (0) 2016.01.17
[OS 기초] File System 2 - Disk Scheduling  (0) 2015.11.06
[OS 기초] File System  (0) 2015.11.05
[OS 기초] I/O Device와 Device Driver  (0) 2015.11.05
[OS 기초] Demand paging 3 - Trashing, Working Set  (0) 2015.11.04

+ Recent posts