이것은 실제 운영 시스템이 아닙니다. 교육 목적으로 만들어진 간단한 운영 시스템 일뿐입니다.
제가 추적하는 주요 목표는 OS가 처음부터 어떻게 작동하는지 배우는 것입니다. 자체 부츠 부문, 하드웨어 및 소프트웨어 인터럽트, 자체 드라이버에서 시작합니다.
REPOTION은 GCC로 접미사되어 있습니다. 그래서 Ghaiklor-os-GCC 와 Ghaiklor-os-Rustc 가 있기를 바랍니다.
| 안녕하세요, 세상 |
|---|
Ghaiklor-OS-GCC는 RAW 바이너리 형식의 두 파일 인 Boot.bin 및 Kernel.bin 으로 구성됩니다. 컴파일 후 Boot/Boot.bin 및 Kernel/Kernel.bin 에 있습니다.
Boot.bin은 NASM 을 통해 편집됩니다. makefile은 boot/boot.asm을 가져 와서 nasm boot/boot.asm -f bin -o boot/boot.bin 호출합니다. NASM 핸들에는 하위 폴더 자체가 포함되므로 모든 어셈블리 파일이 바이너리로 컴파일됩니다. 다른 것은 없습니다.
kernel.bin 은 크로스 컴필라 GCC 및 LD 를 통해 컴파일되어 설치해야합니다. 개발 환경 섹션을 살펴보십시오. 크로스 컴파일러가 설치된 후 CPU 의 소스, 드라이버 , 커널 및 LIBC 폴더 를 재귀 적으로 가져갈 수 있습니다. 모든 .C 파일은 gcc 를 통해 컴파일됩니다. 컴파일 된 객체 파일은 kernel.bin을 컴파일하는 데 사용됩니다. 그런 다음 ld ld -o kernel/kernel.bin -Ttext 0x1000 <OBJ_FILES> --oformat binary 통해 사용됩니다.
os-Image.bin is 편집 boot.bin 및 kernel.bin 의 연결. cat boot/boot.bin kernel/kernel.bin > os-image.bin 으로 쉽게 달성 할 수 있습니다.
나는 당신이 실행할 수있는 bootstrap.sh 스크립트를 썼습니다. 호스트 컴퓨터에 필요한 모든 종속성을 설치합니다.
bash bootstrap.sh컴퓨터가 켜지거나 재설정되면 Post-Power-on-Self-Test라는 일련의 진단을 통해 실행됩니다. 이 서열은 플로피, CDROM 또는 하드 디스크와 같은 부팅 가능한 장치를 찾는 데 정점적입니다.
BYTES 511 및 512의 BYTE 시퀀스 0x55 , 0xAA 있는 부팅 섹터를 보유하면 장치가 부팅 가능합니다. BIOS가 그러한 부팅 섹터를 찾으면 0x0000:0x7C00 에서 메모리에로드됩니다.
부팅 가능한 장치의 간단한 구현 :
jmp $
times 510 - ($ - $$) db 0
dw 0xAA55 $ - $$ 는 CURRENT_POINTER - START_POINTER 에서 결과를 얻습니다. 그렇게하면 부트 레코드가 얼마나 오래 걸리는지 계산하고 있습니다. 그 후, 우리는 그것으로부터 510을 침전시키고 0을 채우고 부팅 섹터 서명으로 512 바이트 부팅 레코드를 얻습니다.
예를 들어, 우리는 100과 같은 $ - $$ 가 있습니다. 따라서 510 - 100 = 410 무료 바이트가 있습니다. 우리는이 410 바이트를 0으로 채우고 있습니다. 그리고 마지막 두 바이트 511과 512는 dw 0xAA55 로 채우는 부팅 가능한 서명입니다.
완료! 우리는 부팅 가능한 장치를 가지고 있으며 jmp $ 원하는 코드로 바꿀 수 있습니다.
부팅 섹터 구현
처음에는 코드가 실제 모드로 실행됩니다.
실제 모드는 모든 X86 프로세서에 존재하는 단순한 16 비트 모드입니다. 실제 모드는 최초의 X86 모드 설계였으며 많은 초기 운영 체제에서 사용되었습니다. 호환성을 위해 모든 X86 프로세서는 실제 모드에서 실행을 시작합니다.
실제 모드에서 나쁘고 좋은 것은 무엇입니까?
단점
프로
실제 모드가 가지고있는 많은 제한 사항과 문제로 인해 보호 모드로 전환해야합니다.
보호 모드는 80286 이후 현대 인텔 프로세서의 주요 작동 모드입니다. 여러 가상 주소 공간으로 작업 할 수 있으며 각각 최대 4GB의 주소 메모리가 있습니다.
BIOS가 실제 모드로 시작하여 CPU가 초기화되었으므로 보호 모드로 전환하면 대부분의 BIOS 인터럽트를 사용하지 않습니다. 보호 모드로 전환하기 전에 NMI를 포함한 인터럽트를 비활성화하고 A20 라인을 활성화하고 글로벌 디스크립터 테이블을로드해야합니다.
보호 모드로 전환하기위한 알고리즘 :
cli
lgdt [ gdt_descriptor ]
mov eax , cr0
or eax , 0x1
mov cr0 , eax
jmp CODE_SEG:init_pmPM으로 전환하기위한 구현
글로벌 디스크립터 테이블
그러나 우리는 더 나아갈 수 있습니다 ...
Long Mode 란 무엇이며 왜 설정합니까?
X86-64 프로세서가 도입 된 이후 새로운 모드도 소개되었으며, 이는 Long Mode라고합니다. Long Mode는 기본적으로 실제 64 비트 모드와 호환성 모드 (32 비트) 인 두 개의 하위 모드로 구성됩니다.
우리가 관심있는 것은이 모드가 다음과 같은 많은 새로운 기능을 제공하기 때문에 단순히 64 비트 모드입니다.
긴 모드로 전환하기 전에 CPU 가이 모드를 지원하는지 확인 해야합니다 . CPU가 긴 모드를 지원하지 않으면 보호 모드로의 폴백이 필요합니다.
긴 모드가 지원되는지 감지하십시오
그렇다면 긴 모드로 전환하십시오
이 모든 모드는 훌륭하지만 512 바이트로 운영 체제를 작성할 수는 없습니다. 따라서 부팅 섹터는 하드 디스크에서 컴파일 된 커널을로드하는 방법을 알아야 합니다 .
실제 모드에있을 때는 디스크에서 읽기 위해 BIOS 인터럽트를 사용할 수 있습니다. 우리의 경우 INT 13,2 - Read Disk Sectors 입니다.
그것을 사용하는 방법?
;; al = number of sectors to read (1 - 128)
;; ch = track/cylinder number
;; cl = sector number
;; dh = head number
;; dl = drive number
;; bx = pointer to buffer
mov ah , 0x02
mov al , 15
mov ch , 0x00
mov cl , 0x02
mov dh , 0x00
mov dl , 0
mov bx , KERNEL_OFFSET_IN_MEMORY
int 0x13 이 코드는 하드 디스크에서 KERNEL_OFFSET_IN_MEMORY 주소로 읽습니다. 두 번째 섹터에서 시작하여 15 개의 섹터를 읽고 주소 KERNEL_OFFSET_IN_MEMORY 에 의해 저장됩니다.
우리의 컴파일 된 OS 이미지는 부팅 섹터와 커널을 연결하기 때문에 부팅 섹터가 512 바이트라는 것을 알고 있기 때문에 커널이 두 번째 섹터에서 시작되는지 확인할 수 있습니다.
읽기가 성공적으로 완료되면 KERNEL_OFFSET_IN_MEMORY 에서 명령어를 호출하고 커널을 실행할 수 있습니다.
call KERNEL_OFFSET_IN_MEMORY
jmp $디스크 읽기 구현
우리는 여기에 부팅 섹터에 대한 선을 그릴 수 있습니다. 흐름은 간단합니다.
call 명령을 통해 커널을 실행하십시오.이 단계에서 부팅 부문은 작업을 마치고 커널 작업을 시작합니다.
부팅 소스를 탐색하고 작동 방식을 얻을 수 있습니다.
우리가 주소로 지시에 전화 할 때 몇 가지 문제가 발생할 수 있습니다. 주소 별 지침은 kernel_main() 입니다. 솔루션은 간단합니다.
커널 코드의 시작에 첨부 된 하위 경로를 쓸 수 있습니다. 이 하위 경로는 커널의 외부 기능 kernel_main() 을 호출합니다. 객체 파일이 함께 연결되면이 호출은 kernel_main() 의 호출로 변환됩니다.
global _start
[bits 32]
[extern kernel_main]
_start:
call kernel_main
jmp $커널 입력 구현
이 단계에는 kernel_main() 메소드에 대한 입력 포인트가 있습니다. 그리고 그것은 전체 커널의 진입 점입니다.
#include 어떻게 작동하고 kernel_main() 에서 어떻게되는지 설명하는 것이 지루하다고 생각합니다. 내가 호출하는 방법을 쉽게 따라갈 수 있습니다.
c
이것이 가장 간단한 부분입니다.
RAW 바이너리 형식으로 boot/boot.bin 이미지를 빌드해야합니다. 그렇게하기 위해, 우리는 특별한 깃발로 nasm 어셈블러를 부릅니다.
nasm boot/boot.asm -f bin -o boot/boot.binQEMU를 통해 실행할 수있는 원시 바이너리 형식으로 이어집니다.
이 단계에서는 컴파일 된 부팅 섹터를 사용했습니다.
boot 폴더를 제외한 모든 폴더에서 모든 폴더에서 모든 소스를 구축해야합니다.
모든 C 파일은 gcc 통해 객체 파일과 nasm 통해 조립 파일로 컴파일됩니다.
gcc -g -ffreestanding -Wall -Wextra -fno-exceptions -m32 -std=c11 -c < SOURCE > -o < OBJ_FILE >
nasm < SOURCE > -f elf -o < OBJ_FILE > 원시 바이너리 형식에 링크하기 위해 필요한 모든 객체 파일로 이어집니다. 남은 것은 ld 통해 서로 연결하는 것입니다.
ld -o kernel/kernel.bin -Ttext 0x1000 kernel/kernel_entry.o < OBJ_FILES > --oformat binary kernel_main() 호출하는 데 문제가 있기 때문에 kernel/kernel_entry.o . 이런 식으로, 우리는 boot/kernel_entry.asm 에서 첫 번째 명령이 호출 될 것을 보장합니다.
결국, 우리는 원시 바이너리 형식으로 커널 이미지를 컴파일했습니다.
우리의 부츠 섹터와 커널은 원시 바이너리 형식이므로 연결 만 할 수 있습니다.
cat boot/boot.bin kernel/kernel.bin > os-image.bin 이제 qemu-system-i386 통해 os-image.bin 실행할 수 있습니다. BIOS 부팅 가능한 섹터를 찾으려고, boot/boot.bin 찾아 서명을 본다. int 13,2를 통해 kernel/kernel.bin 메모리에로드하여 실행하는 boot/boot.bin 에서 어셈블리 코드를 실행하기 시작합니다.
그것이 모든 것이 함께 작동하는 방식입니다. 프로젝트를 탐색하십시오. 감사합니다.
MIT 라이센스 (MIT)
저작권 (C) 2016 Eugene Obrezkov
이에 따라이 소프트웨어 및 관련 문서 파일 ( "소프트웨어")의 사본을 얻는 사람에게는 허가가 부여됩니다. 소프트웨어의 사용, 복사, 수정, 합병, 배포, 배포, 숭고 및/또는 소프트웨어의 사본을 판매 할 권한을 포함하여 제한없이 소프트웨어를 처리 할 수 있도록 소프트웨어를 제공 할 권한이 없습니다.
위의 저작권 통지 및이 권한 통지는 소프트웨어의 모든 사본 또는 실질적인 부분에 포함되어야합니다.
이 소프트웨어는 상업성, 특정 목적에 대한 적합성 및 비 침해에 대한 보증을 포함하여 명시 적 또는 묵시적 보증없이 "그대로"제공됩니다. 어떠한 경우에도 저자 또는 저작권 보유자는 계약, 불법 행위 또는 기타, 소프트웨어 또는 소프트웨어의 사용 또는 기타 거래에서 발생하는 계약, 불법 행위 또는 기타의 행동에 관계없이 청구, 손해 또는 기타 책임에 대해 책임을지지 않습니다.