โ† Back

[์š”์•ฝ] ๐Ÿ–ฅ๏ธ์ž„๋ฒ ๋””๋“œ OS ํ”„๋กœ์ ํŠธ Ch.5

UART
์ธ๋„ค์ผ

์‹œ์ž‘ํ•˜๊ธฐ ์ „

์ „ ์‹œ๊ฐ„์—์„œ๋Š” ๋ ˆ์ง€์Šคํ„ฐ ๊ฐ’์„ ์–ด๋–ป๊ฒŒ ๋ฐ”๊พธ๋Š” ์ง€ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” UART ํ†ต์‹ ์œผ๋กœ ์ถœ๋ ฅ๊ณผ ์ž…๋ ฅ์„ ๋ฐฐ์›Œ ๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค (์ฝ”๋“œ ์–‘ ๋งŽ์Œ)

5.1 UART (from GPT)

UART(๋ฒ”์šฉ ๋น„๋™๊ธฐ ์†ก์ˆ˜์‹ ๊ธฐ)๋Š” ๋‘ ์žฅ์น˜ ๊ฐ„์— ํด๋Ÿญ ์‹ ํ˜ธ ์—†์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ง๋ ฌ๋กœ ์ „์†กํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. ์‹œ์ž‘ ๋น„ํŠธ์™€ ์ •์ง€ ๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์„ ๊ตฌ๋ถ„ํ•˜๋ฉฐ, ์˜ค๋ฅ˜ ๊ฒ€์ถœ์„ ์œ„ํ•œ ํŒจ๋ฆฌํ‹ฐ ๋น„ํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ ๋งˆ์ดํฌ๋กœ์ปจํŠธ๋กค๋Ÿฌ์™€ ์ปดํ“จํ„ฐ ๊ฐ„์˜ ํ†ต์‹ ์— ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค.

UART๋Š” ์ฃผ๋กœ ์ฝ˜์†” ์ž…์ถœ๋ ฅ์šฉ์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค. UART๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ UART ํ•˜๋“œ์›จ์–ด์˜ ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ์ฝ”๋“œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ๋ฐ”๋กœ UART๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜คํ”„์…‹์ด 0x00์ธ UARTDR์€ UART Data Register์˜ ์•ฝ์ž 0 ~ 7๋ฒˆ ๋น„ํŠธ๊นŒ์ง€ ์ž…์ถœ๋ ฅ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ํ•œ๋ฒˆ์— 1byte๋ฅผ ํ†ต์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค 8 ~ 11๋ฒˆ ๋น„ํŠธ๊นŒ์ง€๋Š” ์ข…๋ฅ˜๋ณ„๋กœ ์ •์˜๋œ ์—๋Ÿฌ์ด๋‹ค. ํ”„๋ ˆ์ž„์—๋Ÿฌ, ํŒจ๋ฆฌํ‹ฐ ์—๋Ÿฌ, ๋ธŒ๋ ˆ์ดํฌ ์—๋Ÿฌ, ์˜ค๋ฒ„๋Ÿฐ ์—๋Ÿฌ ๋“ฑ ์ด๋ฆ„์ด ๋ถ™์–ด์žˆ๋‹ค. ์„ค๋ช…์— ๋ถ€ํ•ฉํ•˜๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ•ด๋‹น ๋น„ํŠธ ๊ฐ’์ด 1์ด ๋œ๋‹ค.


5-2 ๊ทธ๋ฆผ

5-2 ๊ทธ๋ฆผ์„ ์ฝ”๋“œ๋กœ ์˜ฎ๊ธฐ๋Š” ๋ฐฉ๋ฒ•์€ 1. C์–ธ์–ด ๋งคํฌ๋กœ๋ฅผ ํ†ตํ•ด ์ •์˜๋ฅผ ํ•˜๊ฑฐ๋‚˜, 2. ๊ตฌ์กฐ์ฒด๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.` ์šฐ๋ฆฌ๋Š” ๊ตฌ์กฐ์ฒด๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ด๋‹ค.

๊ตฌ์กฐ์ฒด ์‚ฌ์šฉ ์ฝ”๋“œ ์˜ˆ์‹œ

/*
 * Uart.h
 *
 *  Created on: Sep 8, 2018
 *      Author: maanu
 */
#ifndef HAL_RVPB_UART_H_
#define HAL_RVPB_UART_H_
typedef union UARTDR_t
{
    uint32_t all;
    struct {
        uint32_t DATA:8;    // 7:0
        uint32_t FE:1;      // 8
        uint32_t PE:1;      // 9
        uint32_t BE:1;      // 10
        uint32_t OE:1;      // 11
        uint32_t reserved:20;
    } bits;
} UARTDR_t;
typedef union UARTRSR_t
{
    uint32_t all;
    struct {
        uint32_t FE:1;      // 0
        uint32_t PE:1;      // 1
        uint32_t BE:1;      // 2
        uint32_t OE:1;      // 3
        uint32_t reserved:28;
    } bits;
} UARTRSR_t;
typedef union UARTFR_t
{
    uint32_t all;
    struct {
        uint32_t CTS:1;     // 0
        uint32_t DSR:1;     // 1
        uint32_t DCD:1;     // 2
        uint32_t BUSY:1;    // 3
        uint32_t RXFE:1;    // 4
        uint32_t TXFF:1;    // 5
        uint32_t RXFF:1;    // 6
        uint32_t TXFE:1;    // 7
        uint32_t RI:1;      // 8
        uint32_t reserved:23;
    } bits;
} UARTFR_t;
typedef union UARTILPR_t
{
    uint32_t all;
    struct {
        uint32_t ILPDVSR:8; // 7:0
        uint32_t reserved:24;
    } bits;
} UARTILPR_t;
typedef union UARTIBRD_t
{
    uint32_t all;
    struct {
        uint32_t BAUDDIVINT:16; // 15:0
        uint32_t reserved:16;
    } bits;
} UARTIBRD_t;
typedef union UARTFBRD_t
{
    uint32_t all;
    struct {
        uint32_t BAUDDIVFRAC:6; // 5:0
        uint32_t reserved:26;
    } bits;
} UARTFBRD_t;
typedef union UARTLCR_H_t
{
    uint32_t all;
    struct {
        uint32_t BRK:1;     // 0
        uint32_t PEN:1;     // 1
        uint32_t EPS:1;     // 2
        uint32_t STP2:1;    // 3
        uint32_t FEN:1;     // 4
        uint32_t WLEN:2;    // 6:5
        uint32_t SPS:1;     // 7
        uint32_t reserved:24;
    } bits;
} UARTLCR_H_t;
typedef union UARTCR_t
{
    uint32_t all;
    struct {
        uint32_t UARTEN:1;      // 0
        uint32_t SIREN:1;       // 1
        uint32_t SIRLP:1;       // 2
        uint32_t Reserved1:4;   // 6:3
        uint32_t LBE:1;         // 7
        uint32_t TXE:1;         // 8
        uint32_t RXE:1;         // 9
        uint32_t DTR:1;         // 10
        uint32_t RTS:1;         // 11
        uint32_t Out1:1;        // 12
        uint32_t Out2:1;        // 13
        uint32_t RTSEn:1;       // 14
        uint32_t CTSEn:1;       // 15
        uint32_t reserved2:16;
    } bits;
} UARTCR_t;
typedef union UARTIFLS_t
{
    uint32_t all;
    struct {
        uint32_t TXIFLSEL:3;    // 2:0
        uint32_t RXIFLSEL:3;    // 5:3
        uint32_t reserved:26;
    } bits;
} UARTIFLS_t;
typedef union UARTIMSC_t
{
    uint32_t all;
    struct {
        uint32_t RIMIM:1;   // 0
        uint32_t CTSMIM:1;  // 1
        uint32_t DCDMIM:1;  // 2
        uint32_t DSRMIM:1;  // 3
        uint32_t RXIM:1;    // 4
        uint32_t TXIM:1;    // 5
        uint32_t RTIM:1;    // 6
        uint32_t FEIM:1;    // 7
        uint32_t PEIM:1;    // 8
        uint32_t BEIM:1;    // 9
        uint32_t OEIM:1;    // 10
        uint32_t reserved:21;
    } bits;
} UARTIMSC_t;
typedef union UARTRIS_t
{
    uint32_t all;
    struct {
        uint32_t RIRMIS:1;  // 0
        uint32_t CTSRMIS:1; // 1
        uint32_t DCDRMIS:1; // 2
        uint32_t DSRRMIS:1; // 3
        uint32_t RXRIS:1;   // 4
        uint32_t TXRIS:1;   // 5
        uint32_t RTRIS:1;   // 6
        uint32_t FERIS:1;   // 7
        uint32_t PERIS:1;   // 8
        uint32_t BERIS:1;   // 9
        uint32_t OERIS:1;   // 10
        uint32_t reserved:21;
    } bits;
} UARTRIS_t;
typedef union UARTMIS_t
{
    uint32_t all;
    struct {
        uint32_t RIMMIS:1;  // 0
        uint32_t CTSMMIS:1; // 1
        uint32_t DCDMMIS:1; // 2
        uint32_t DSRMMIS:1; // 3
        uint32_t RXMIS:1;   // 4
        uint32_t TXMIS:1;   // 5
        uint32_t RTMIS:1;   // 6
        uint32_t FEMIS:1;   // 7
        uint32_t PEMIS:1;   // 8
        uint32_t BEMIS:1;   // 9
        uint32_t OEMIS:1;   // 10
        uint32_t reserved:21;
    } bits;
} UARTMIS_t;
typedef union UARTICR_t
{
    uint32_t all;
    struct {
        uint32_t RIMIC:1;   // 0
        uint32_t CTSMIC:1;  // 1
        uint32_t DCDMIC:1;  // 2
        uint32_t DSRMIC:1;  // 3
        uint32_t RXIC:1;    // 4
        uint32_t TXIC:1;    // 5
        uint32_t RTIC:1;    // 6
        uint32_t FEIC:1;    // 7
        uint32_t PEIC:1;    // 8
        uint32_t BEIC:1;    // 9
        uint32_t OEIC:1;    // 10
        uint32_t reserved:21;
    } bits;
} UARTICR_t;
typedef union UARTDMACR_t
{
    uint32_t all;
    struct {
        uint32_t RXDMAE:1;  // 0
        uint32_t TXDMAE:1;  // 1
        uint32_t DMAONERR:1;// 2
        uint32_t reserved:29;
    } bits;
} UARTDMACR_t;
typedef struct PL011_t
{
    UARTDR_t    uartdr;         //0x000
    UARTRSR_t   uartrsr;        //0x004
    uint32_t    reserved0[4];   //0x008-0x014
    UARTFR_t    uartfr;         //0x018
    uint32_t    reserved1;      //0x01C
    UARTILPR_t  uartilpr;       //0x020
    UARTIBRD_t  uartibrd;       //0x024
    UARTFBRD_t  uartfbrd;       //0x028
    UARTLCR_H_t uartlcr_h;      //0x02C
    UARTCR_t    uartcr;         //0x030
    UARTIFLS_t  uartifls;       //0x034
    UARTIMSC_t  uartimsc;       //0x038
    UARTRIS_t   uartris;        //0x03C
    UARTMIS_t   uartmis;        //0x040
    UARTICR_t   uarticr;        //0x044
    UARTDMACR_t uartdmacr;      //0x048
} PL011_t;
#define UART_BASE_ADDRESS0       0x10009000
#define UART_INTERRUPT0          44
#endif /* HAL_RVPB_UART_H_ */

UART ํ•˜๋“œ์›จ์–ด๋ฅผ ์ œ์–ด ํ•  ์ˆ˜ ์žˆ๋Š” ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๊ธฐ ์œ„ํ•ด์„œ Regs.c ํŒŒ์ผ์„ ์ƒ์„ฑ

Regs.c

/*
 * Regs.c
 *
 *  Created on: Sep 8, 2018
 *      Author: maanu
 */
#include "stdint.h"
#include "Uart.h"
volatile PL011_t* Uart = (PL011_t*)UART_BASE_ADDRESS0;

PLUS HAL

HAL(Hardware Abstraction Layer)์€ ์šด์˜ ์ฒด์ œ์™€ ํ•˜๋“œ์›จ์–ด ๊ฐ„์˜ ์ค‘์žฌ ์—ญํ• ์„ ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ณ„์ธต์œผ๋กœ, ๋‹ค์–‘ํ•œ ํ•˜๋“œ์›จ์–ด๋ฅผ ์ถ”์ƒํ™”ํ•˜์—ฌ ์ผ๊ด€๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๋Š” ํ•˜๋“œ์›จ์–ด์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š๊ณ  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์‹œ์Šคํ…œ์˜ ์ด์‹์„ฑ๊ณผ ํ˜ธํ™˜์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. HAL์€ ํŠนํžˆ ๋“œ๋ผ์ด๋ฒ„ ๊ฐœ๋ฐœ๊ณผ ์‹œ์Šคํ…œ ์•ˆ์ •์„ฑ ์œ ์ง€์— ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

ํ˜„์žฌ ํŒŒ์ผ๊ตฌ์กฐ

--boot
|  |--Entry.S
|  |--Main.c
|
--hal
|  |--HalUart.h
|  |--rvpb
|      |--Uart.h
|
--include
|     |--ARMv7AR.h
|     |--MemoryMap.h
|     |--stdint.h
|
--Makefile
--navilos
--README.md

HARUART.h ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

HALUART.h ์ฝ”๋“œ

/*
 * HalUart.h
 *
 *  Created on: Sep 8, 2018
 *      Author: maanu
 */
#ifndef HAL_HALUART_H_
#define HAL_HALUART_H_
void    Hal_uart_init(void);
void    Hal_uart_put_char(uint8_t ch);
#endif /* HAL_HALUART_H_ */

UART ๊ณต์šฉ API๋ฅผ ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น API๋ฅผ ๋งŒ์กฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด Uart.c ํŒŒ์ผ์„ ์žฌ๊ตฌ์„ฑํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

Uart.c ์ฝ”๋“œ

/*
 * Uart.c
 *
 *  Created on: Sep 8, 2018
 *      Author: maanu
 */
#include "stdint.h"  // ํ‘œ์ค€ ์ •์ˆ˜ ํƒ€์ž… ์ •์˜๋ฅผ ํฌํ•จํ•˜๋Š” ํ—ค๋” ํŒŒ์ผ
#include "Uart.h"    // UART ๊ด€๋ จ ํ—ค๋” ํŒŒ์ผ
#include "HalUart.h" // HAL (Hardware Abstraction Layer) UART ๊ด€๋ จ ํ—ค๋” ํŒŒ์ผ
// ์™ธ๋ถ€์—์„œ ์„ ์–ธ๋œ volatile ํƒ€์ž…์˜ PL011_t ๊ตฌ์กฐ์ฒด ํฌ์ธํ„ฐ ๋ณ€์ˆ˜ Uart
extern volatile PL011_t* Uart;
/*
 * Hal_uart_init
 * UART๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•จ์ˆ˜
 */
void Hal_uart_init(void)
{
    // UART๋ฅผ ๋น„ํ™œ์„ฑํ™”
    Uart->uartcr.bits.UARTEN = 0;
    // ์†ก์‹ (TX)์„ ํ™œ์„ฑํ™”
    Uart->uartcr.bits.TXE = 1;
    // ์ˆ˜์‹ (RX)์„ ํ™œ์„ฑํ™”
    Uart->uartcr.bits.RXE = 1;
    // UART๋ฅผ ํ™œ์„ฑํ™”
    Uart->uartcr.bits.UARTEN = 1;
}

์ฝ”๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ž‘๋™๋œ๋‹ค๋ฉด ์‹คํ–‰๋˜๋Š” ์ˆœ๊ฐ„ UART๋ฅผ ํ†ตํ•ด์„œ๋ฐ์ดํ„ฐ๊ฐ€ ํ˜ธ์ŠคํŠธ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.

Main.c ์ฝ”๋“œ

#include "stdint.h"  // ํ‘œ์ค€ ์ •์ˆ˜ ํƒ€์ž… ์ •์˜๋ฅผ ํฌํ•จํ•˜๋Š” ํ—ค๋” ํŒŒ์ผ
#include "HalUart.h" // HAL (Hardware Abstraction Layer) UART ๊ด€๋ จ ํ—ค๋” ํŒŒ์ผ
#include "stdio.h"   // ํ‘œ์ค€ ์ž…์ถœ๋ ฅ ํ•จ์ˆ˜๋“ค์„ ํฌํ•จํ•˜๋Š” ํ—ค๋” ํŒŒ์ผ
static void Hw_init(void);     // ํ•˜๋“œ์›จ์–ด ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜์˜ ์ •์  ์„ ์–ธ
void main(void)  // ๋ฉ”์ธ ํ•จ์ˆ˜์˜ ์ •์˜
{
    Hw_init(); // ํ•˜๋“œ์›จ์–ด ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ ํ˜ธ์ถœ
    uint32_t i = 100; // ์นด์šดํ„ฐ ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™”
    while(i--)  // ์นด์šดํ„ฐ๊ฐ€ 0์ด ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต
    {
        Hal_uart_put_char('N'); // UART๋กœ ๋ฌธ์ž 'N'์„ ์ „์†ก
    }
}
static void Hw_init(void)  // ํ•˜๋“œ์›จ์–ด ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜์˜ ์ •์˜
{
    Hal_uart_init(); // UART ์ดˆ๊ธฐํ™” ํ•จ์ˆ˜ ํ˜ธ์ถœ
}

makefile์„ ๊ตฌ์„ฑ ํ•œ ๋‹ค์Œ์— ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ด…์‹œ๋‹ค.

Makefile

ARCH = armv7-a  # ์•„ํ‚คํ…์ฒ˜ ์„ค์ •
MCPU = cortex-a8  # CPU ์„ค์ •
CC = arm-none-eabi-gcc  # C ์ปดํŒŒ์ผ๋Ÿฌ ์„ค์ •
AS = arm-none-eabi-as  # ์–ด์…ˆ๋ธ”๋Ÿฌ ์„ค์ •
LD = arm-none-eabi-ld  # ๋ง์ปค ์„ค์ •
OC = arm-none-eabi-objcopy  # ์˜ค๋ธŒ์ ํŠธ ๋ณต์‚ฌ๊ธฐ ์„ค์ •
LINKER_SCRIPT = ./navilos.ld  # ๋ง์ปค ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ ๊ฒฝ๋กœ
MAP_FILE = build/navilos.map  # ๋งต ํŒŒ์ผ ๊ฒฝ๋กœ
ASM_SRCS = $(wildcard boot/*.S)  # ์–ด์…ˆ๋ธ”๋ฆฌ ์†Œ์Šค ํŒŒ์ผ ๋ชฉ๋ก
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))  # ์–ด์…ˆ๋ธ”๋ฆฌ ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ ๋ชฉ๋ก
C_SRCS = $(wildcard boot/*.c)  # C ์†Œ์Šค ํŒŒ์ผ ๋ชฉ๋ก
C_OBJS = $(patsubst boot/%.c, build/%.o, $(C_SRCS))  # C ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ ๋ชฉ๋ก
INC_DIRS  = -I include  # ํฌํ•จ ๋””๋ ‰ํ† ๋ฆฌ ์„ค์ •
navilos = build/navilos.axf  # ์ƒ์„ฑ๋  ์‹คํ–‰ ํŒŒ์ผ ๊ฒฝ๋กœ
navilos_bin = build/navilos.bin  # ์ƒ์„ฑ๋  ๋ฐ”์ด๋„ˆ๋ฆฌ ํŒŒ์ผ ๊ฒฝ๋กœ
.PHONY: all clean run debug gdb  # ๊ฐ€์ƒ ํƒ€๊ฒŸ ์„ค์ •
all: $(navilos)  # ๊ธฐ๋ณธ ํƒ€๊ฒŸ ์„ค์ •
clean:  # ๋นŒ๋“œ ๋””๋ ‰ํ† ๋ฆฌ ์ •๋ฆฌ ํƒ€๊ฒŸ
    @rm -fr build
run: $(navilos)  # ์‹คํ–‰ ํƒ€๊ฒŸ
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos)
debug: $(navilos)  # ๋””๋ฒ„๊ทธ ํƒ€๊ฒŸ
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
gdb:  # GDB ์‹คํ–‰ ํƒ€๊ฒŸ
    arm-none-eabi-gdb
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)  # ์‹คํ–‰ ํŒŒ์ผ ์ƒ์„ฑ ํƒ€๊ฒŸ
    $(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Map=$(MAP_FILE)
    $(OC) -O binary $(navilos) $(navilos_bin)
build/%.os: $(ASM_SRCS)  # ์–ด์…ˆ๋ธ”๋ฆฌ ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ ์ƒ์„ฑ ํƒ€๊ฒŸ
    mkdir -p $(shell dirname $@)
    $(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<
build/%.o: $(C_SRCS)  # C ์˜ค๋ธŒ์ ํŠธ ํŒŒ์ผ ์ƒ์„ฑ ํƒ€๊ฒŸ
    mkdir -p $(shell dirname $@)
    $(CC) -march=$(ARCH) -mcpu=$(MCPU) $(INC_DIRS) -c -g -o $@ $<

make run

N์ด 100๋ฒˆ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฆฌ๋ˆ…์Šค ํ„ฐ๋ฏธ๋„์˜ ์ž…๋ ฅ์ด QEMU์™€์—ฐ๊ฒฐ๋˜์–ด ์žˆ์–ด Ctrl + C๋กœ ์ข…๋ฃŒํ•  ์ˆ˜ ์—†๋‹ค. ๋ณ„๊ฐœ์˜ ํ„ฐ๋ฏธ๋„๋กœ kill ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด QEMU ๋ฅผ ์ข…๋ฃŒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

5.2 ์•ˆ๋…• ์„ธ์ƒ!

ํ‰์†Œ ์ฝ”๋”ฉ์„ ์‹œ์ž‘ํ•  ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ๋ณด์—ฌ์ฃผ๋Š” ์˜ˆ์ œ๋Š” printf("Hello world"); ์ž…๋‹ˆ๋‹ค. python, C๋ฅผ ๋ฐฐ์šธ๋•Œ๋Š” ๊ทธ๋ƒฅ ์จ๋„ ๋์—ˆ์ง€๋งŒ, ํŽŒ์›จ์–ด์—์„œ๋Š” printf()๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด์•ผํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ stdio.h, stdio.c ํŒŒ์ผ์„ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค.

stdio.h

/*
 * stdio.h
 *
 *  Created on: Sep 17, 2018
 *      Author: maanu
 */
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
uint32_t putstr(const char* s);
#endif /* LIB_STDIO_H_ */

stdio.c

/*
 * stdio.c
 *
 *  Created on: Sep 17, 2018
 *      Author: maanu
 */
#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
uint32_t putstr(const char* s)
{
    uint32_t c = 0;
    while(*s)
    {
        Hal_uart_put_char(*s++);
        c++;
    }
    return c;
}

์ด์ œ hello world๋ฅผ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก main.c ํŒŒ์ผ์— putchr ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด์ค์‹œ๋‹ค.

Main.c

#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
void main(void)
{
    Hw_init();
    uint32_t i = 100;
    while(i--)
    {
        Hal_uart_put_char('N');
    }
    Hal_uart_put_char('\n');
    putstr("Hello World!\n");
}
static void Hw_init(void)
{
    Hal_uart_init();
}

make run

Hello World! ๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

5.3 UART๋กœ ์ž…๋ ฅ๋ฐ›๊ธฐ

์ด์ œ UART๋กœ ์ถœ๋ ฅ์„ ํ•ด๋ณด์•˜์œผ๋‹ˆ ์ž…๋ ฅ ๋˜ํ•œ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ถœ๋ ฅ์„ ํ•  ๋•Œ์—๋Š”

  1. ๋ณด๋‚ด๊ธฐ ๋ฒ„ํผ๊ฐ€ ๋น„์—ˆ๋Š”์ง€, ๋น„์–ด์žˆ์œผ๋ฉด
  2. ๋ฐ์ดํ„ฐ ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ธฐ ๋ฒ„ํผ๋กœ ๋ณด๋‚ด๊ณ ,
  3. ํ•˜๋“œ์›จ์–ด๊ฐ€ ์•Œ์•„์„œ ๋‚˜๋จธ์ง€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๊ณ 
  4. ํ•˜๋“œ์›จ์–ด์™€ ์—ฐ๊ฒฐ๋œ ์ฝ˜์†”์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

์ž…๋ ฅ์€ ๊ทธ์™€ ๋ฐ˜๋Œ€๋กœ

  1. ๋ฐ›๊ธฐ ๋ฒ„ํผ๊ฐ€ ์ฑ„์›Œ์ ธ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ฑ„์›Œ์ ธ ์žˆ๋‹ค๋ฉด
  2. ๋ฐ์ดํ„ฐ ๋ ˆ์ง€์Šคํ„ฐ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ž…๋ ฅ๋ฐ›๋Š” ํ•จ์ˆ˜๋Š” ์ฝ”๋“œ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๋ฐ”๋กœ ์ตœ์ ํ™” ์ฝ”๋“œ๋กœ ๊ตฌ์„ฑํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Hal_uart_get_char() - [Uart.c]

uint8_t Hal_uart_get_char(void)
{
    uint32_t data;
    while(Uart->uartfr.bits.RXFE);
    data = Uart->uartdr.all;
    // Check for an error flag
    if (data & 0xFFFFFF00)
    {
        // Clear the error
        Uart->uartrsr.all = 0xFF;
        return 0;
    }
    return (uint8_t)(data & 0xFF);
}

์ตœ์ ํ™”๊ฐ€ ๋˜์ง€ ์•Š์€ ์ฝ”๋“œ๋Š” ์•ฝ 340๋ฐ”์ดํŠธ๊ฐ€ ์ƒ์„ฑ๋˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋Š” ์ด 200๋ฐ”์ดํŠธ์งœ๋ฆฌ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

๋งŒ๋“  ํ•จ์ˆ˜๋ฅผ Main.c์— ๋„ฃ์–ด๋ด…์‹œ๋‹ค

Main.c

#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
void main(void)
{
    Hw_init();
    uint32_t i = 100;
    while(i--)
    {
        Hal_uart_put_char('N');
    }
    Hal_uart_put_char('\n');
    putstr("Hello World!\n");
    i = 100;
    while(i--)
    {
        uint8_t ch = Hal_uart_get_char();
        Hal_uart_put_char(ch);
    }
}
static void Hw_init(void)
{
    Hal_uart_init();
}

์ž˜ ์ž…๋ ฅ๋˜๋Š” ๊ฑธ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5.4 printf ๋งŒ๋“ค๊ธฐ

์šฐ๋ฆฌ๊ฐ€ ์“ฐ๋˜ printf์™€ ์‹ค์ œ printf์˜ ์ฐจ์ด์ ์€ ํฌ๋งท์„ ์“ธ ์ˆ˜ ์žˆ๋‚˜, ์—†๋‚˜ ์ž…๋‹ˆ๋‹ค. ํฌ๋งท์€ %s, %d ๊ฐ™์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํ˜•์‹์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋“ค์ด ๋งŽ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” debug_printf()๋ฅผ ๋งŒ๋“ค ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

debug_printf() ์„ ์–ธ

uint32_t debug_printf(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    vsprintf(printf_buf, format, args);
    va_end(args);
    return putstr(printf_buf);
}

์ฝ”๋“œ๊ฐ€ ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ stdarg.h ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

stdarg.h

/*
 * stdarg.h
 *
 *  Created on: Sep 19, 2018
 *      Author: maanu
 */
#ifndef INCLUDE_STDARG_H_
#define INCLUDE_STDARG_H_
typedef __builtin_va_list va_list;
#define va_start(v,l)   __builtin_va_start(v,l)
#define va_end(v)       __builtin_va_end(v)
#define va_arg(v,l)     __builtin_va_arg(v,l)
#endif /* INCLUDE_STDARG_H_ */

GCC ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ธฐ์กด stdarg.h ํŒŒ์ผ์€ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋ณต์‚ฌํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

stdio.h ํŒŒ์ผ์—์„œ include๋งŒ ์‚ฌ์šฉํ•˜๋ฉด, va_list, va_start, va_end๋ฅผ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

stdio.h

/*
 * stdio.h
 *
 *  Created on: Sep 17, 2018
 *      Author: maanu
 */
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
#include "stdarg.h"
typedef enum utoa_t
{
    utoa_dec = 10,
    utoa_hex = 16,
} utoa_t;
uint32_t putstr(const char* s);
uint32_t debug_printf(const char* format, ...);
uint32_t vsprintf(char* buf, const char* format, va_list arg);
uint32_t utoa(char* buf, uint32_t val, utoa_t base);
#endif /* LIB_STDIO_H_ */

stdio.h์— stdarg.hํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค

vsprintf() ํ•จ์ˆ˜

uint32_t vsprintf(char* buf, const char* format, va_list arg)
{
    uint32_t c = 0;
    char     ch;
    char*    str;
    uint32_t uint;
    uint32_t hex;
    for (uint32_t i = 0 ; format[i] ; i++)
    {
        if (format[i] == '%')
        {
            i++;
            switch(format[i])
            {
            case 'c':
                ch = (char)va_arg(arg, int32_t);
                buf[c++] = ch;
                break;
            case 's':
                str = (char*)va_arg(arg, char*);
                if (str == NULL)
                {
                    str = "(null)";
                }
                while(*str)
                {
                    buf[c++] = (*str++);
                }
                break;
            case 'u':
                uint = (uint32_t)va_arg(arg, uint32_t);
                c += utoa(&buf[c], uint, utoa_dec);
                break;
            case 'x':
                hex = (uint32_t)va_arg(arg, uint32_t);
                c += utoa(&buf[c], hex, utoa_hex);
                break;
            }
        }
        else
        {
            buf[c++] = format[i];
        }
    }
    if (c >= PRINTF_BUF_LEN)
    {
        buf[0] = '\0';
        return 0;
    }
    buf[c] = '\0';
    return c;
}

์ตœ์†Œํ•œ์˜ ๊ธฐ๋Šฅ๋งŒ ๊ตฌํ˜„ํ•œ vsprintf() ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

stdio.h

/*
 * stdio.h
 *
 *  Created on: Sep 17, 2018
 *      Author: maanu
 */
#ifndef LIB_STDIO_H_
#define LIB_STDIO_H_
#include "stdarg.h"
typedef enum utoa_t
{
    utoa_dec = 10,
    utoa_hex = 16,
} utoa_t;
uint32_t putstr(const char* s);
uint32_t debug_printf(const char* format, ...);
uint32_t vsprintf(char* buf, const char* format, va_list arg);
uint32_t utoa(char* buf, uint32_t val, utoa_t base);
#endif /* LIB_STDIO_H_ */

utoa ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ฉ๋‹ˆ๋‹ค.

stdio.c

uint32_t utoa(char* buf, uint32_t val, utoa_t base)
{
    const char asciibase = 'a';
    uint32_t c = 0;
    int32_t idx = 0;
    char     tmp[11];   // It is enough for 32 bit int
    do {
        uint32_t t = val % (uint32_t)base;
        if (t >= 10)
        {
            t += asciibase - '0' - 10;
        }
        tmp[idx] = (t + '0');
        val /= base;
        idx++;
    } while(val);
    // reverse
    idx--;
    while (idx >= 0)
    {
        buf[c++] = tmp[idx];
        idx--;
    }
    return c;
}

utoa ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

main.c์— printf()ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค

Main.c

#include "stdint.h"
#include "HalUart.h"
#include "stdio.h"
static void Hw_init(void);
static void Printf_test(void);
void main(void)
{
    Hw_init();
    uint32_t i = 100;
    while(i--)
    {
        Hal_uart_put_char('N');
    }
    Hal_uart_put_char('\n');
    putstr("Hello World!\n");
    Printf_test();
    i = 100;
    while(i--)
    {
        uint8_t ch = Hal_uart_get_char();
        Hal_uart_put_char(ch);
    }
}
static void Hw_init(void)
{
    Hal_uart_init();
}
static void Printf_test(void)
{
    char* str = "printf pointer test";
    char* nullptr = 0;
    uint32_t i = 5;
    debug_printf("%s\n", "Hello printf");
    debug_printf("output string pointer: %s\n", str);
    debug_printf("%s is null pointer, %u number\n", nullptr, 10);
    debug_printf("%u = 5\n", i);
    debug_printf("dec=%u hex=%x\n", 0xff, 0xff);
}

์ดํ›„ make run์„ ๋™์ž‘์‹œํ‚ค๋ฉด ์—๋Ÿฌ๊ฐ€ ๋œฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒ๋ฉด utoa()์—์„œ๋Š” ๋‚˜๋จธ์ง€, ๋‚˜๋ˆ„๊ธฐ ์—ฐ์‚ฐ์ด ์“ฐ์ด์ง€๋งŒ ARM์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‚˜๋จธ์ง€, ๋‚˜๋ˆ„๊ธฐ ์—ฐ์‚ฐ์„ ์ง€์›ํ•˜๋Š” ํ•˜๋“œ์›จ์–ด๊ฐ€ ์—†๋‹ค๊ณ  ๊ฐ„์ฃผํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ GCC๊ฐ€ ์ด๋ฅผ ์†Œํ”„ํŠธ์›จ์–ด๋กœ ๊ตฌํ˜„ํ•ด๋†“์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜๋กœ ์ž๋™์œผ๋กœ ๋งํ‚นํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰ makefile์„ ์กฐ๊ธˆ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Makefile

ARCH = armv7-a
MCPU = cortex-a8
TARGET = rvpb
CC = arm-none-eabi-gcc
AS = arm-none-eabi-as
LD = arm-none-eabi-gcc
OC = arm-none-eabi-objcopy
LINKER_SCRIPT = ./navilos.ld
MAP_FILE = build/navilos.map
ASM_SRCS = $(wildcard boot/*.S)
ASM_OBJS = $(patsubst boot/%.S, build/%.os, $(ASM_SRCS))
VPATH = boot            \
        hal/$(TARGET)   \
        lib
C_SRCS  = $(notdir $(wildcard boot/*.c))
C_SRCS += $(notdir $(wildcard hal/$(TARGET)/*.c))
C_SRCS += $(notdir $(wildcard lib/*.c))
C_OBJS = $(patsubst %.c, build/%.o, $(C_SRCS))
INC_DIRS  = -I include          \
            -I hal              \
            -I hal/$(TARGET)    \
            -I lib
CFLAGS = -c -g -std=c11 -mthumb-interwork
LDFLAGS = -nostartfiles -nostdlib -nodefaultlibs -static -lgcc
navilos = build/navilos.axf
navilos_bin = build/navilos.bin
.PHONY: all clean run debug gdb
all: $(navilos)
clean:
    @rm -fr build
run: $(navilos)
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -nographic
debug: $(navilos)
    qemu-system-arm -M realview-pb-a8 -kernel $(navilos) -S -gdb tcp::1234,ipv4
gdb:
    arm-none-eabi-gdb
kill:
    kill -9 `ps aux | grep 'qemu' | awk 'NR==1{print $$2}'`
$(navilos): $(ASM_OBJS) $(C_OBJS) $(LINKER_SCRIPT)
    $(LD) -n -T $(LINKER_SCRIPT) -o $(navilos) $(ASM_OBJS) $(C_OBJS) -Wl,-Map=$(MAP_FILE) $(LDFLAGS)
    $(OC) -O binary $(navilos) $(navilos_bin)
build/%.os: %.S
    mkdir -p $(shell dirname $@)
    $(CC) -march=$(ARCH) -mcpu=$(MCPU) -marm $(INC_DIRS) $(CFLAGS) -o $@ $<
build/%.o: %.c
    mkdir -p $(shell dirname $@)
    $(CC) -march=$(ARCH) -mcpu=$(MCPU) -marm $(INC_DIRS) $(CFLAGS) -o $@ $<

make run

๊ตณ๊ตณ

์ง€๊ธˆ๊นŒ์ง€ ํŒŒ์ผ๊ตฌ์กฐ ์ž…๋‹ˆ๋‹ค

.
โ”œโ”€โ”€ ARMv7AR.h
โ”œโ”€โ”€ Makefile
โ”œโ”€โ”€ MemoryMap.h
โ”œโ”€โ”€ boot
โ”‚ย ย  โ”œโ”€โ”€ Entry.S
โ”‚ย ย  โ”œโ”€โ”€ Entry.bin
โ”‚ย ย  โ”œโ”€โ”€ Entry.o
โ”‚ย ย  โ””โ”€โ”€ Main.c
โ”œโ”€โ”€ build
โ”‚ย ย  โ”œโ”€โ”€ Entry.os
โ”‚ย ย  โ”œโ”€โ”€ Main.o
โ”‚ย ย  โ”œโ”€โ”€ Regs.o
โ”‚ย ย  โ”œโ”€โ”€ Uart.o
โ”‚ย ย  โ”œโ”€โ”€ navilos.axf
โ”‚ย ย  โ”œโ”€โ”€ navilos.bin
โ”‚ย ย  โ”œโ”€โ”€ navilos.map
โ”‚ย ย  โ””โ”€โ”€ stdio.o
โ”œโ”€โ”€ em.em
โ”œโ”€โ”€ hal
โ”‚ย ย  โ”œโ”€โ”€ HalUart.h
โ”‚ย ย  โ””โ”€โ”€ rvpb
โ”‚ย ย      โ”œโ”€โ”€ Regs.c
โ”‚ย ย      โ”œโ”€โ”€ Uart.c
โ”‚ย ย      โ”œโ”€โ”€ Uart.h
โ”‚ย ย      โ””โ”€โ”€ Uart.o
โ”œโ”€โ”€ hello.txt
โ”œโ”€โ”€ include
โ”‚ย ย  โ”œโ”€โ”€ ARMv7AR.h
โ”‚ย ย  โ”œโ”€โ”€ MemoryMap.h
โ”‚ย ย  โ”œโ”€โ”€ stdarg.h
โ”‚ย ย  โ””โ”€โ”€ stdint.h
โ”œโ”€โ”€ lib
โ”‚ย ย  โ”œโ”€โ”€ stdio.c
โ”‚ย ย  โ””โ”€โ”€ stdio.h
โ”œโ”€โ”€ navilos.axf
โ”œโ”€โ”€ navilos.ld
โ””โ”€โ”€ temp
    โ””โ”€โ”€ SYS_ID_analysis.py

โ†

[์š”์•ฝ] ๐Ÿ–ฅ๏ธ์ž„๋ฒ ๋””๋“œ OS ํ”„๋กœ์ ํŠธ Ch.4

๋ถ€ํŒ…ํ•˜๊ธฐ

โ†’

[ํ›„๊ธฐ] ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์บ์ด์…˜ ์„ค๊ณ„

์•„์ง ์š”์•ฝ์„ ํ•  ๋ ˆ๋ฒจ์ด ์•„๋‹Œ ๊ฑฐ ๊ฐ™๋‹ค