从零写自己的操作系统.
前提 来自youtube上一位腼腆的牛人推出的视频 .
目标 完成一个自己的系统的iso文件,在屏幕上打印一句话,效果如下:
技术栈
makefle
ASM汇编
链接
C++
代码 types.h: 声明数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 #ifndef __TYPES_H #define __TYPES_H typedef char int8_t ; typedef unsigned char uint8_t ; typedef short int16_t ; typedef unsigned short uint16_t ; typedef int int32_t ; typedef unsigned int uint32_t ; typedef long long int int64_t ; typedef unsigned long long int uint64_t ; #endif
kernel.cpp:打印逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include "types.h" void printf (char * str) { static uint16_t * VideoMemory = (uint16_t *)0xb8000 ; for (int i = 0 ; str[i] != '\0' ; ++i) VideoMemory[i] = (VideoMemory[i] & 0xFF00 ) | str[i]; } typedef void (*constructor) () ;extern "C" constructor start_ctors;extern "C" constructor end_ctors;extern "C" void callConstructors () { for (constructor* i = &start_ctors; i != &end_ctors; i++) (*i)(); } extern "C" void kernelMain (const void * multiboot_structure, uint32_t ) { printf ("Hello World! --- jimo - OS1" ); while (1 ); }
loader.s:从硬件启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 .set MAGIC, 0x1badb002 .set FLAGS, (1<<0 | 1<<1) .set CHECKSUM, -(MAGIC + FLAGS) .section .multiboot .long MAGIC .long FLAGS .long CHECKSUM .section .text .extern kernelMain #.extern callConstructors .global loader loader: mov $kernel_stack, %esp call callConstructors push %eax push %ebx call kernelMain _stop: cli hlt jmp _stop .section .bss .space 2*1024*1024; # 2 MiB kernel_stack:
linker.ld:用于链接,手写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ENTRY(loader) OUTPUT_FORMAT(elf32-i386) OUTPUT_ARCH(i386:i386) SECTIONS { . = 0x0100000; .text : { *(.multiboot) *(.text*) *(.rodata) } .data : { start_ctors = .; KEEP(*( .init_array )); KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); end_ctors = .; *(.data) } .bss : { *(.bss) } /DISCARD/ : { *(.fini_array*) *(.comment) } }
makefile:方便make
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 GCCPARAMS = -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore ASPARAMS = --32 LDPARAMS = -melf_i386 objects = loader.o kernel.o %.o: %.cpp gcc $(GCCPARAMS) -c -o $@ $< %.o: %.s as $(ASPARAMS) -o $@ $< mykernel.bin: linker.ld $(objects) ld $(LDPARAMS) -T $< -o $@ $(objects) install: mykernel.bin sudo cp $< /boot/mykernel.bin mykernel.iso: mykernel.bin rm -rf iso mkdir iso mkdir iso/boot mkdir iso/boot/grub cp mykernel.bin iso/boot/mykernel.bin echo 'set timeout=0' > iso/boot/grub/grub.cfg echo 'set default=0' >> iso/boot/grub/grub.cfg echo '' >> iso/boot/grub/grub.cfg echo 'menuentry "My Operating System" {' >> iso/boot/grub/grub.cfg echo ' multiboot /boot/mykernel.bin' >> iso/boot/grub/grub.cfg echo ' boot' >> iso/boot/grub/grub.cfg echo '}' >> iso/boot/grub/grub.cfg grub-mkrescue --output=mykernel.iso iso rm -rf iso run: mykernel.iso (killall VirtualBox && sleep 1) || true VirtualBox --startvm 'my-os' &
编译与链接 1.编译cpp
1 2 3 4 5 $ make kernel.o gcc -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -c -o kernel.o kernel.cpp kernel.cpp: 在函数‘void kernelMain(const void*, uint32_t)’中: kernel.cpp:26:41: 警告:ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] printf("Hello World! --- jimo - OS1");
2.编译loader
1 2 3 4 $ make loader.o as --32 -o loader.o loader.s loader.s: Assembler messages: loader.s: 警告:end of file not at end of a line; newline inserted
3.链接
1 2 3 4 5 6 7 $ make mykernel.bin gcc -m32 -fno-use-cxa-atexit -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fno-leading-underscore -c -o kernel.o kernel.cpp kernel.cpp: 在函数‘void kernelMain(const void*, unsigned int)’中: kernel.cpp:24:41: 警告:ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] printf("Hello World! --- jimo - OS1"); ^ ld -melf_i386 -T linker.ld -o mykernel.bin loader.o kernel.o
4.制作ISO文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 $ make mykernel.iso rm -rf iso mkdir iso mkdir iso/boot mkdir iso/boot/grub cp mykernel.bin iso/boot/mykernel.bin echo 'set timeout=0' > iso/boot/grub/grub.cfg echo 'set default=0' >> iso/boot/grub/grub.cfg echo '' >> iso/boot/grub/grub.cfg echo 'menuentry "My Operating System" {' >> iso/boot/grub/grub.cfg echo ' multiboot /boot/mykernel.bin' >> iso/boot/grub/grub.cfg echo ' boot' >> iso/boot/grub/grub.cfg echo '}' >> iso/boot/grub/grub.cfg grub-mkrescue --output=mykernel.iso iso xorriso 1.4.8 : RockRidge filesystem manipulator, libburnia project. Drive current: -outdev 'stdio:mykernel.iso' Media current: stdio file, overwriteable Media status : is blank Media summary: 0 sessions, 0 data blocks, 0 data, 25.7g free Added to ISO image: directory '/'='/tmp/grub.lWPSfY' xorriso : UPDATE : 633 files added in 1 seconds Added to ISO image: directory '/'='/home/jimo/workspace/temp/os/iso' xorriso : UPDATE : 637 files added in 1 seconds xorriso : NOTE : Copying to System Area: 512 bytes from file '/usr/lib/grub/i386-pc/boot_hybrid.img' ISO image produced: 8831 sectors Written to medium : 8831 sectors at LBA 0 Writing to 'stdio:mykernel.iso' completed successfully. rm -rf iso
如果这一步出现错误,比如没有xorriso,那么请安装libisoburn
1 2 grub-mkrescue --output=mykernel.iso iso grub-mkrescue:错误: xorriso not found.
这时当前目录下有iso文件了:
5.导入虚拟机新建就ok了.