首先,建议你看书,你问的东西太多,即使给你回答了,你可能还是不明白,因为太多基础性的东西你不知道。这些书包括Intel的开发手册(intel 架构软件开发人员手册 第3卷:系统编程指南,有部分被翻译成中文)、以及自己编写操作系统的书(这些书有很多,大多数讲的都还可以)。
以x86架构为例,x86指令运行的权限是从Ring0到Ring3的,操作系统内核运行在R0,用户程序运行在R3。
有一些指令只能在R0执行,比如修改CR寄存器(mov cr0, eax),这种操作在用户态直接会报错。因为CPU会保存当前运行的代码的CPL(当前特权级别)和IOPL(IO权限),如果CPL/IOPL不符,CPU会抛出异常,丢给内核R0的代码去处理。这种错误,是执行到某条特定指令才会遇到的,不是加载的时候遇到的,是CPU行为,不是操作系统行为。
操作系统之所以不会被限制,是因为操作系统内核运行在R0上,对CPU有完整的控制权。
计算机刚启动时,属于实模式,从实模式切换到保护模式的过程中,默认是进入到R0里的,所以操作系统在启动的过程中,是自动获得了R0的权限的。而用户代码都是被操作系统启动的,此时操作系统能控制用户代码运行在什么级别上。
那么为什么操作系统的代码就可以切换特权级而用户的代码却不可以切换特权级?
实际上可以的。Windows可以加载用户驱动到内核(但受到一些限制),这就是把用户代码放到R0里执行的过程,Linux也有类似的东西存在。
没操作系统之前二进制代码 到 操作系统 的过程是什么?
引导扇区(实模式)-> bootloader(实模式->保护模式,R0)-> 操作系统(保护模式,R0)
有操作系统以后从二进制代码 到 shell 到 内核 到硬件 过程是什么?
操作系统先加载的是内核,内核处于R0,shell已经是在用户态了。