🗿 Embedded/🐧 OS for ARM
[ARM/OS 만들기] 11. Event flag 를 통해 이벤트를 발생 시켜 보자.
11.1 이벤트 플래그 이벤트는 개발자가 정한 어떤 값으로 전달된다. 여기서는 비트맵으로 처리하도록 한다. 비트맵으로 만들면 각각의 이벤트를 명확하게 구분할 수 있고, 이벤트를 구분하는 코드를 간단하게 구현할 수 있기 때문이다. 각각의 이벤트 값ㅇ르 겹치지 않는 비트 위치에 할당한다. 특정 비트 위치에 독립된 이벤트를 할당해서 이벤트가 있다 없다를 표시하는 방식이다. kernel/event.h 와 event.c 파일 두개를 만들도록 한다. #ifndef KERNEL_EVENT_H_ #define KERNEL_EVENT_H_ typedef enum KernelEventFlag_t { KernelEventFlag_UartIn = 0x00000001, KernelEventFlag_CmdIn = 0x000000..
[ARM/OS 만들기] 10. 컨텍스트 스위칭
컨텍스트 스위칭 동작하는 프로그램을 바꾼다는 의미이다. 나빌로스의 컨텍스트 스위칭은 아래의 순서대로 진행된다. 현재 동작하고 있는 태스크의 컨텍스트를 현재 스택에 저장한다. 다음에 동작할 태스크 컨트롤 블록을 스케줄러에서 받는다. 2에서 받은 태스크 컨트롤 블록에서 스택 포인터를 읽는다. 3에서 읽은 태스크의 스택에서 컨텍스트를 읽어서 ARM코어에 복구한다. 다음에 동작할 태스크의 직전 프로그램 실행 위치로 이동한다. 그러면 이제 현재 동작하고 있는 태스크가 된다. 아래는 위의 절차를 코드로 옮긴 것이다. kernel/task.c 파일에 수정해 주도록 한다. static KernelTcb_t* Scheduler_round_robin_algorithm(void) { sCurrent_tcb_index++; ..
[ARM/OS 만들기] 9. 스케줄러 만들기
9.1 스케줄러 먼저 간단한 스케줄러를 만들어 보자. 스케줄러는 현재 실행하는 태스크 다음에 실행할 테스크를 선택하는 방법을 결정한다. 여기서는 라운드 로빈 방식을 택해 스케줄러를 작성하도록 한다. kernel/task.c 에 파일ㅇ르 수정해 라운드 로빈을 작성하도록 한다. static KernelTcb_t* Scheduler_round_robin_algorithm(void) { sCurrent_tcb_index++; sCurrent_tcb_index %=sAllocated_tcb_index; return &sTask_list[sCurrent_tcb_index]; } sCurrent_tcb_index 라는 변수를 만들어 현재 실행중인 태스크의 블록 인덱스를 저장한다. 나머지 연산을 이용해 최대 인덱스를 ..
[ARM/OS 만들기] 8. Task 컨트롤
8.1 태스크 컨트롤 블록 태스크 컨트롤 블록이란 개별 태스크 자체를 추상화하는 자료구조를 말한다. 태스크는 운영체재에서 동작하는 프로그램 그 자체이다. 프로그램은 현재 상태를 기록하고 그 기록에 따라 태스크간 전환이 이루어 지는데 그 상태를 기록한 것을 컨택스트 라고 한다. 태스크를 관리하는 데 필요한 정보들을 컨트롤 블록에 넣어서 관리한다. 이제 이 컨트롤 블록을 구현해 RTOS 커널을 만드는 첫번째 작업에 들어가 보자. kernel 이라는 디렉토리를 만들고, task.c 와 task.h 파일을 만든다. kernel/task.h 에 태스크 컨트롤 블록을 정의한다. #ifndef KERNEL_TASK_H_ #define KERNEL_TASK_H_ #include "MemoryMap.h" #define ..
![[ARM/OS 만들기] 7. 타이머(timer) 초기화, 동작 개발](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2FcfoJzz%2FbtrCHpWXxq5%2FAAAAAAAAAAAAAAAAAAAAAPRqZjK09hmMaMTQGaA1EY61-bc2x7ZxUEoGTqvpYNIM%2Fimg.jpg%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3D%252Bpzid%252B%252BQ%252Bx67AgUkqLfw0TdJQjs%253D)
[ARM/OS 만들기] 7. 타이머(timer) 초기화, 동작 개발
7. 타이머 RealViewPB는 SP804라는 타이머를 사용한다. 이 타이머는 측정 카운터가 감소하는 형식이다. 이번 장에는 delay()를 구현해 보도록 하자. 7.1 타이머 하드웨어 초기화 하드웨어 레지스터를 구조체로 추상화하여 hal에 추가한다. SP805의 스펙은 아래의 링크에 나와있다. https://developer.arm.com/documentation/ddi0271/d/programmer-s-model/summary-of-registers?lang=en hal/rvpb/Timer.h에 레지스터 코드를 작성하고 나면 총 7개의 레지스터를 정의하는 것을 알 수 있다. timerxload는 카운터의 목표 값을 지정하는 레지스터이다. timerxvalue는 감소하는 레지스터 이다. 따라서 타이머..
![[ARM/OS 만들기] 6. OS의 인터럽트 (interrupt)](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2Fb96qwK%2FbtrCvKUJHb3%2FAAAAAAAAAAAAAAAAAAAAALSDy8SowN8hLDt7BRm28PVHgOiTduFfg-AZw9v62EMd%2Fimg.png%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3DWdXCNWiKLgmrfZGaLi6ehoeOgrU%253D)
[ARM/OS 만들기] 6. OS의 인터럽트 (interrupt)
6. Interrupt 인터럽트는 임베디드 시스템을 표함한 모든 컴퓨팅 시스템의 꽃이다. 컴퓨팅 시스템은 외부와의 상호작용으로 인터럽트를 이용한다. 인터럽트는 처리하기 위해 인터럽트 컨트롤러를 사용하는 법을 알고, 인터럽트 컨트롤러를 초기화하고 사용하는 코드를 작성해야 한다. 익셉션 핸들러에서 적절한 인터럽트 핸들러를 호출하면 인터럽트 처리가 완료된다. 우선 main 함수의 맨 끝에 무한루프를 삽입해 OS를 멈춰놓고, 인터럽트를 테스트해 보자. 6.1 인터럽트 컨트롤러 RealViewPB에는 Generic Interrupt Contoller라는 이름의 인터럽트 컨트롤러 하드웨어가 달려있다. 먼저 GIC의 레지스터 구조체를 만든다. hal/rvpb/Interrupt.h 파일에 작성한다. GIC에 관한 내용..
[ARM/OS 만들기] 5. Uart 모듈 개발.
5. Uart 이제 UART 코딩을 시작해 보자. RealView Board에 있는 UART는 PL011을 사용한다. 그럼 먼저 PL011 DataSheet에 있는 Uart Register를 코드로 옮겨보자. 레지스터를 코드로 구현하는 부분은 다음과 같이 나타낼 수 있다. #define UART_BASE_ADDR 0x10009000 #define UARTDR_OFFSET (0X00) #define UARTDR_OFFSET (0) . ... 위의 경우로 코딩된 부분을 에러 비트 검사를 한다고 할 경우 아래와 같이 나타낼 수 있다. uint32_r *uartdr = (uint32_t*)(UART_BASE_ADDR + UARTDR_OFFSET); *uartdr = (data) > UARTDR_FE) & 0x1..
![[ARM/OS 만들기] 4. 부팅하기!](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2Fc9vawI%2FbtrBrLs3gdr%2FAAAAAAAAAAAAAAAAAAAAANt1SDcUQfXaQM6TrjKl9JmwySGfaO8vJlbKUtp13cqM%2Fimg.jpg%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3DtwxpQBDXWRWGCS0KgcNl%252FxuZ0t8%253D)
[ARM/OS 만들기] 4. 부팅하기!
4. 부팅하기 부팅이란 정의하기 나름이지만, 여기서는 시스템에 전원이 들어가고 ARM 코어가 리셋 익셉션 핸들러를 모두 처리한 다음에 본격적으로 C언어 코드로 넘어가기 직전 까지를 말한다. 4.1 메모리의 설계 메로리의 영역은 아래의 세가지로 나뉘어져 있다. text 영역 코드가 있는 공간, 코드이므로 임의로 변경하면 안된다. data 영역 초기화한 전역 변수가 있는 공간, 전역 변수를 선언할 때 초기 값을 할당해서 선언하면 해당 전역 변수가 점유하는 공간은 여기에 할당됨. bss 영역 초기화하지 않은 전역 변수가 있는 공간. 초기화하지 않은 전역 변수이므로 빌드 완료되어 생성된 바이너리 파일에는 심벌과 크기만 들어있음. 위의 영역을 배치할 때, 각각의 특성들을 고려해서 해당 영역을 빠르고 적은 메모리에..
![[ARM/OS 만들기] 3. 시작하기.](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2FcmERyo%2FbtrBrszk9ly%2FAAAAAAAAAAAAAAAAAAAAAIRnERFk37-C_W20ujjoqwX59VmICBSH8VI2JkWwPkul%2Fimg.jpg%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3DUx8yKN44axxrK0g2OHB62izLhCw%253D)
[ARM/OS 만들기] 3. 시작하기.
3.1 리셋 벡터 리셋 벡터는 전원이 들어오면 가장 먼저 실행되는 명령어를 저장함. 메모리 주소 0x00000000 를 가짐 아래는 Enyry.S .text .code 32 .global vector_start .global vector_end vector_start: MOV R0, R1 vector_end: .space 1024, 0 .end code 3.1 code32 명령어의 크기가 32비트, 즉 4바이트 .global C언어에서의 extern과 같은 역할 MOV R0, R1 의미없는 코드 .space 1024, 0 해당 위치부터 1024 바이트를 0으로 채움. 컴파일 및 바이너리 확인. 3.2 실행파일 만들기 링커란 여러 오브젝트 파일을 linking해 하나의 실행 파일로 만드는 프로그램 이 링커..
![[ARM/OS 만들기] 2. 나만의 OS 만들기 개발환경 구성](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdna%2Fdip3Oj%2FbtrBqfA0JEL%2FAAAAAAAAAAAAAAAAAAAAAKf3LbEInMBcIfQeBzLgm2zVnaETtabtji6kh7HAfV9I%2Fimg.jpg%3Fcredential%3DyqXZFxpELC7KVnFOS48ylbz2pIh7yKj8%26expires%3D1753973999%26allow_ip%3D%26allow_referer%3D%26signature%3DtRhwVUKaShKbb8mMxZDdH7324lU%253D)
[ARM/OS 만들기] 2. 나만의 OS 만들기 개발환경 구성
개발환경 구성 1. 컴파일러 설치 크로스 컴파일러로 GCC 사용. ARM용 GCC 사용 그 중 gcc-arm-none-eabi를 사용하기로 함. sudo apt install gcc-arm-none-eabi 터미널에 arm-none-eabi-gcc -v 를 입력해 제대로 설치가 되었는지 확인. 2. QEMU 설치 QEMU는 가상머신 에뮬러이터를 지원하는 어플리케이션. VM과 같은 역할을 함. qemu-system-arm 을 설치하도록 함. sudo apt install qemu-system-arm qemu-system-arm --version을 입력해 제대로 설치가 되었는지 확인.