概述
Micernel的设计目的是为了了解操作系统技术,深入的去理解当今计算机领域发展所取得的各种技术突破与成就。同时以现代操作系统技术为基础,去探索在操作系统与AI更紧密结合相互发展的方式方法。
现代操作系统发展至今已经有了更多不同的思路与技术突破,同时很多人也没有一个很好的方法去深刻的理解其中的各种技术。本着知其然必知其所以然的原则,去重走一遍操作系统构建之路,在这其中希望能获得更多新的思路,萌生出别样的火花。
对于操作系统的研究不能不提现在很流行的开源操作系统linux,但随着linux的发展,其代码也是越来越多,学习难度也是越来越大,各个子模块或子系统之间的关系也是变得越来越复杂。所以这个项目也是想实现一个更易于理解,模块之间接口更清晰,同时能够囊括操作系统技术中大部分关键技术细节的操作系统。并且构思一种系统能够自行进化的解决途径,使系统能够随着时间,信息的增加而变得越来越智能,或者说是一种自学习的方案。
本文适合对操作系统有兴趣,对于C,汇编,计算机体系结构等相关知识有一定基础的同学阅读,因为主要是做项目跟踪与思路分享之用,许多基础性的东西都不会在这儿深入展开,而会把重心放在蓝图设计与编码实现上,也很欢迎有志学习的人能够加入到项目中来。
第一天设计目标
x86平台是现在个人电脑用户都能接触到的平台,各种虚拟机都能够做到对x86平台的模拟,所以我们从x86平台开始。第一天的任务很简单,了解x86平台,了解grub,了解引导协议,在前面都完成的基础上,我们需要能够使用grub2实现引导。
x86平台介绍,指令集介绍及系统开发手册:
https://software.intel.com/en-us/articles/intel-sdm
intel处理器及AMD处理器演变历史:
http://wiki.osdev.org/IA32_Architecture_Family
grub历史演变及特点:
https://en.wikipedia.org/wiki/GNU_GRUB
grub源码:
http://www.gnu.org/software/grub/grub-download.html
linux x86引导协议:
https://www.kernel.org/doc/Documentation/x86/boot.txt
《自己动手写操作系统》——于渊
《x86汇编语言:从实模式到保护模式》——李忠 王晓波
AT&T汇编入门简介:
http://blog.csdn.net/ztguang/article/details/51011771
AT&T汇编与Intel汇编区别:
http://blog.csdn.net/lnuyasha_hrb/article/details/6469621
汇编语言——王爽
汇编语言程序设计——Richard Blum
好了,以上介绍了在开始之前需要知道了解的一些东西,在之后对于一些不必要的细节将省略,重点放在设计思路上,这样可以帮助我们抓住主要的东西而不会迷失在细节的海洋里,更重要的是在之后在这更想将这儿用来记录思考的过程与一些无聊(^_^)。。的想法分享的地方和对项目进展进行与问题记录的地方。
过程记录
结合linux的源码和引导协议的文档制作grup引导所需要的setup,制作setup有一下几点需要注意的:
1.与linux内核镜像生成过程类似,需要将setup与内核合成一个文件,这是必须的,除非自己实现引导程序
2.setup的大小有限制,这取决与引导加载程序,grub中限制了setup最大不能超过64*512=32kb,如果在setup中没根据协议设置自身大小,grub默认setup大小为2kb
3.将setup与内核合成一个文件涉及对setup中引导协议关键字段的填充,需要一个工具完成这件事儿
设计思路:
|0|0x7c00|...|0x1000000
| |setup |...|micernel
目前grub2将setup(包含实模式代码和引导协议)放置在0x7c00起始的位置,内核代码加载到0x1000000开始的位置,这些都是历史原因造成的,为了保证我们能够使用grub2引导我们需要做到像linux那样的内核构建方式。
制作setup
这部分我们只需要包含引导协议即可,仿造linux的head.S代码构建
/*setup.S*/
.code16
.section ".bstext", "ax"
.global bootsect_start
bootsect_start:
# Normalize the start address
ljmp $0x7c0, $start2
start2:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
xorw %sp, %sp
sti
cld
movw $bugger_off_msg, %si
msg_loop:
lodsb
andb %al, %al
jz bs_die
movb $0xe, %ah
movw $7, %bx
int $0x10
jmp msg_loop
bs_die:
# Allow the user to press a key, then reboot
xorw %ax, %ax
int $0x16
int $0x19
# int 0x19 should never return. In case it does anyway,
# invoke the BIOS reset code...
ljmp $0xf000,$0xfff0
.section ".bsdata", "a"
bugger_off_msg:
.ascii "Use a boot loader.\r\n"
.ascii "\n"
.asciz "Remove disk and press any key to reboot...\r\n"
kernel_version:
.asciz "20170224"
.section ".header" , "a"
.global sentinel
sentinel: .byte 0xff,0xff
.global hdr
hdr:
setup_sects: .byte 0
root_flags: .word 1
syssize: .long 0
ram_size: .word 0
vid_mode: .word 0xfffd /* ask for it at bootup */
root_dev: .word 0
boot_flag: .word 0xaa55
.global _start
_start:
.byte 0xeb
.byte start_of_setup-1f
# Part 2 of the header, from the old setup.S
.ascii "HdrS" # header signature
.word 0x020d # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
.globl realmode_swtch
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word 0x1000 # obsolete and meaningless, but just
# in case something decided to "use" it
.word kernel_version # pointing to kernel version string
# above section of header is compatible
# with loadlin-1.5 (header v1.5). Don't
# change it.
type_of_loader: .byte 0 # 0 means ancient bootloader, newer
# bootloaders know to change this.
# See Documentation/x86/boot.txt for
# assigned ids
# flags, unused bits must be zero (RFU) bit within loadflags
loadflags:
.byte LOADED_HIGH # The kernel is to be loaded high
setup_move_size: .word 0x8000 # size to move, when setup is not
# loaded at 0x90000. We will move setup
# to 0x90000 then just before jumping
# into the kernel. However, only the
# loader knows how much data behind
# us also needs to be loaded.
code32_start: # here loaders can put a different
# start address for 32-bit code.
.long 0x100000 # 0x100000 = default for big kernel
ramdisk_image: .long 0 # address of loaded ramdisk image
# Here the loader puts the 32-bit
# address where it loaded the image.
# This only will be read by the kernel.
ramdisk_size: .long 0 # its size in bytes
bootsect_kludge:
.long 0 # obsolete
heap_end_ptr: .word _end+512-512
# (Header version 0x0201 or later)
# space from here (exclusive) down to
# end of setup code can be used by setup
# for local heap purposes.
ext_loader_ver:
.byte 0 # Extended boot loader version
ext_loader_type:
.byte 0 # Extended boot loader type
cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
# If nonzero, a 32-bit pointer
# to the kernel command line.
# The command line should be
# located between the start of
# setup and the end of low
# memory (0xa0000), or it may
# get overwritten before it
# gets read. If this field is
# used, there is no longer
# anything magical about the
# 0x90000 segment; the setup
# can be located anywhere in
# low memory 0x10000 or higher.
initrd_addr_max: .long 0x7fffffff
# (Header version 0x0203 or later)
# The highest safe address for
# the contents of an initrd
# The current kernel allows up to 4 GB,
# but leave it at 2 GB to avoid
# possible bootloader bugs.
kernel_alignment: .long 0x1000000 #physical addr alignment
#required for protected mode
#kernel
relocatable_kernel: .byte 1
min_alignment: .byte 21
#define X86_64 (1<<0)
#define CAN_BE_LOADED_ABOVE_4G (1<<1)
#define EFI_STUB 0
#define EFI_KEXEC 0
xloadflags:
.word X86_64 | CAN_BE_LOADED_ABOVE_4G | EFI_STUB | EFI_KEXEC
cmdline_size: .long 2048-1 #length of the command line,
#added with boot protocol
#version 2.06
hardware_subarch: .long 0 # subarchitecture, added with 2.07
# default to 0 for normal x86 PC
hardware_subarch_data: .quad 0
payload_offset: .long ZO_input_data
payload_length: .long ZO_z_input_len
setup_data: .quad 0 # 64-bit physical pointer to
# single linked list of
# struct setup_data
pref_address: .quad 0x1000000 # preferred load addr
init_size: .long 0 # kernel initialization size
handover_offset: .long 0 # Filled in by build.c
# End of setup header #####################################################
start_of_setup:
1:
hlt
jmp 1b
就像上面代码一样,启动协议这块完全按照linux来,因为目前不会用到efi,所以暂时舍弃efi的配置部分。这一块是比较死的东西,没有什么可以扩展或创新的地方,遵从协议保持兼容性是最好的做法。
剩下的是编译和生成部分,这块都是一些比较常规的做法,如果有兴趣可具体参考源代码。
项目地址和Commit说明
每次提交会尽量做到与博客记录的进度同步,可能会出现的情形是篇文章的内容对应几次提交,这中情况出现时会做特别说明,提交的描述和代码注释会尽可能的详细易懂。
项目地址:
因项目暂未上传git服务器,上传后更新地址