导航:首页 > 软件知识 > 程序如何在内核态运行

程序如何在内核态运行

发布时间:2022-12-31 14:55:46

㈠ 内核启动流程

内核的初始化过程由start_kernel函数开始,至第一个用户进程init结束,调用了一系列的初始化函数对所有的内核组件进行初始化。其中,start_kernel、rest_init、kernel_init、init_post等4个函数构成了整个初始化过程的主线。

从start_kernel函数开始,内核即进入了C语言部分,它完成了内核的大部分初始化工作。实际上,可以将start_kernel函数看做内核的main函数。

在start_kernel函数的最后调用了rest_init函数进行后续的初始化。

(1)rest_init中调用kernel_thread函数启动了2个内核线程,分别是:kernel_init和kthreadd

(2)调用schele函数开启了内核的调度系统,从此linux系统开始转起来了。

rest_init最终调用cpu_idle函数结束了整个内核的启动。

kernel_init函数将完成设备驱动程序的初始化,并调用init_post函数启动用户空间的init进程。

到init_post函数为止,内核的初始化已经进入尾声,第一个用户空间进程init将姗姗来迟

如果内核命令行中给出了到init进程的直接路径(或者别的可替代的程序),这里就试图执行init。

init:开始是内核态,后来转变为用户态】

init进程完成了从内核态向用户态的转变
init进程在内核态下面时,通过一个函数kernel_execve来执行一个用户空间编译连接的应用程序就跳跃到用户态了。

在init/main.c中最后会通过kernel_execve()来调用用户空间的init进程(如/sbin/init, /etc/init, /bin/init等

uboot通过传参来告诉内核这些信息。
uboot传参中的root=/dev/mmcblk0p2 rw 这一句就是告诉内核根文件系统在哪里
uboot传参中的rootfstype=ext3这一句就是告诉内核rootfs的类型。

㈡ 内核态和用户态

内核态和用户态是操作系统的两种运行级别,内核态权限高,用户态权限低。

用户程序从用户态切换到内核态:系统调用(软中断),异常,中断。

系统调用是系统开放给用户程序的接口。

库函数是对系统调用的封装。

shell也对系统调用进行了封装。

系统调用,库函数,shell是用户程序主动访问内核程序的三种方式。

参考: Linux | 为什么用户态和内核态的切换耗费时间? - JH_Zhai的博客 - CSDN博客

㈢ 用户态与内核态

在计算机的指令中,引入了指令级别的概念,Window下分为0~3级,Linux下分为0、3两级;
分级主要是为了区分不同的程序有不同的指令执行权限;

在搞清楚用户态与内核态之前,首先需要搞清楚,用户态和内核态是针对谁描述的?

也看了网上不少资源,很多博客会直接对用户态与内核态的区别直接上手做分析,但实际上了解这两者是针对谁而言,对之后的学习也非常有效果。

这里用户态与内核态是针对CPU而言的,是CPU的两种运行状态,也就是说再任意时刻CPU要么处于内核态要么处于用户态。

这里的原因主要处于操作系统的安全性考虑;

设想一下,如果CPU没有内核态与用户态的概念,完全是一视同仁,所有用户编写的程序可以访问一切硬件资源包括内存。这种情况下写个病毒程序就太容易了,只要运行起来之后把内存的数据随便迁移,这样的场景对于整个系统安全性来说绝对是极其糟糕的。

因此来说,计算机所有硬件资源的使用权应该仅仅收回给操作系统,用户态的程序无权进行访问,如果用户态的程序需要调用硬件资源如读取网卡的数据,必须通过操作系统层面进行操作。

内核态程序执行完毕

我们都知道程序在执行的过程中是离不开栈的数据结构,操作系统在创建程序进程的同时会创建与该程序对应的两个栈结构,分别用于用户态程序执行与内核态程序执行。

当用户态与内核态相互切换的时候,CPU要切换到不同的栈去执行程序,至于为什么不能共用一个栈结构,多半也是为了安全考虑,分为两个栈也就是两片内存区域天然就有了隔离性,自然也就安全了。

本文大体描述了内核态与用户态之间的联系,但创作背景是在没有完全看完权威的操作系统相关书籍情况下编写。上述知识大多数来源于网络上的博客或B站视频,可能其中存在不严谨的语句甚至错误,还请大家勘误。

㈣ Linux用户进程内核态执行,内核线程的关系问题

1、几乎所有的程序都要切换到内核态运行再返回用户态,用中断完成的,因为在内核下封装了一些东西,用户态下只是传入某些参数后调用内核态下的函数罢了,
2、进程有三态(执行态,就绪态,阻塞态),cpu任何时刻都只有一个进程在执行,so从用户态切换到内核态时,用户态下的进程就处于阻塞或就绪态了,至于从用户态切换到内核态执行哪个函数那就看你在用户态下执行的是什么函数了,比如在用户态下的lseek在内核下就是llseek了,不一样的。
3、这问题就是linux的内存管理了,这里就得提到三种地址(逻辑地址、线性地址、物理地址),这里我们提到的4G地址是逻辑地址,不是我们实际的物理地址,linux中一个进程用户占0-3G对应的内核占3G-4G部分
说得不是很清楚,这是比较复杂的内容,需要从头看起,单就这几个问题是不能搞懂linux的,最好还是系统的学习,不断的重复

㈤ windows怎么实现内核态和用户态

为使用户进程无法访问甚至修改关键的操作系统数据,windows使用了两种处理器访问模式:用户态和内核态。用户应用代码运行在用户态,而系统代码(如系统服务和设备驱动)运行在内核态。内核态指处理器中授权访问所有系统内存并使用所有CPU指令的执行状态。通过为操作系统软件定义比用户应用更高的特权,处理器的这种机制使操作系统设计者能够保证行为无法捉摸的用户应用程序不会破坏系统的稳定性。

虽然每个windows进程都有自己的私有地址空间,内核态的操作系统代码和设备驱动代码共享同一个虚拟地址空间。每个虚拟内存页都设定了读写该页所需要的处理器执行状态。操作系统空间中的页只有在内核态时才能访问,所有用户地址空间的页都可以从用户态访问。只读页(通常存放的静态数据)不管处理器处于什么态都无法更改。另外,在支持不执行内存保护的处理器上,windows将包含数据的页标记为不可执行,从而阻止无意触发的对数据页的代码执行。

32位windows对在内核态运行的组件使用私有的系统内存不提供任何保护,也就是说一旦处于内核态,操作系统和设备驱动代码对系统内存有完全的访问权限,并且能够绕过window安全机制访问对象。因为windows操作系统代码运行在内核态,所以运行在内核态的组件需要精心设计并仔细测试以保证它们不会破坏系统安全从而引起系统不稳定。

缺少保护意味着在加载第三方驱动时需要十分小心,因为内核态的软件对所有操作系统数据有完全的访问权限。windows的这一脆弱性也是其驱动签名机制产生的重要原因,这一机制在系统添加未授权的驱动程序的时候会向用户发出警告。同样,一项称为驱动验证器(Driver
Verifier)的技术能够帮助驱动程序编写者查找bug(比如缓冲区溢出或者内存泄漏),以免引起安全或可靠性问题。

另外,64位windows中,内核模式代码标记策略(KMCS)规定64位设备驱动必须使用从某一权威代码认证机构获取加密的key对驱动加以签名。不像32位版本的windows,用户不能公然强制安装一个未授权的驱动,既使是管理员用户(除非在启动时按F8并选择高级启动选项关闭强制驱动签名)

用户应用作出系统调用时会从用户态进入内核态。比如windows的ReadFile函数最终需要调用处理文件读取的内核例程。这个例程由于访问了内核系统数据结构必须运行的内核态下。从用户态到内核态的转换由一条特殊的将处理器转换到内核态的处理器指令完成。操作系统捕获这条指令,意识到有对系统服务的请求,验证传递给系统函数的参数,然后执行内核函数。在将控制权交给用户线程之前处理器返回用户态。通过这种方式,系统保护自身数据以免被用户进程读取甚至修改。

因此,用户线程部分时间在用户态,部分时间在内核态。实际上,由于图形和窗口系统代码也运行在内核态,图形密集型的应用在内核的时间会多于其在用户态运行的时间。可使用性能工具监测图形密集型应用的内核态和用户态时间比例来测试。

可以使用windows自带的性能监测器观察系统在不同运行状态下时间的比例。

步骤如下:

1 打开工具

2 点击工具栏的 “+”

3 选择处理器性能对象后,点击%
Privileged Time计数器,然后按ctrl, 点 % User Time计数器

4 点击 add
,然后点击close

5 不断在移动鼠标,发现与上面分析一样,%
Privileged Time迅速上升

㈥ 中断服务程序都是运行在内核态吗

最近复习操作系统和组成原理也遇到了这个问题,经过多方资料查询,得到如下解释:在中断发生时,往往会先由中断隐指令保存程序断点,也就是pc(或pc+psw)里的内容(x86机器中psw的内容依然由隐指令即硬件保存,因为中断服务程序可能会改变它的内容,MIPS中无psw,故只保存pc),这完全是由硬件实现的,然后需要调用中断服务程序保存通用寄存器和中断屏蔽字的内容,它由操作系统负责完成,运行在管态。

㈦ 系统调用是通过什么方式陷入内核态的

第一步,在系统中添加一个不用传递参数的系统调用;执行这个系统调用,使用户的uid等于0。显然,这不是一个有实际意义的系统调用。我们的目的并不是实用不实用,而是通过最简单的例子,帮助熟悉对系统调用的添加过程,为下面我们添加更加复杂的系统调用打好基础。
第二步,用kernel mole机制,实现系统调用gettimeofday的简化版,返回调用时刻的日期和时间。

实验指导
1.一个简单的例子
在我们开始学习系统调用这一章之前,让我们先来看一个简单的例子。就好像哪个经典的编程书上都会使用到的例子一样:

1: int main(){
2: printf(“Hello World!\n”);
3: }

我们也准备了一个例子给你:

1: #include <linux/unistd.h> /* all system calls need this header */
2: int main(){
3: int i = getuid();
4: printf(“Hello World! This is my uid: %d\n”, i);
5: }

这就是一个最简单的系统调用的例子。与上面那个传统的例子相比,在这个例子中多了2行,他们的作用分别是:
第一行:包括unistd.h这个头文件。所有用到系统调用的程序都需要包括它,因为系统调用中需要的参数(例如,本例中的“__NR_getuid”,以及_syscall0()函数)包括在unistd.h中;根据C语言的规定,include <linux/unistd.h>意味着/usr/include/linux目录下整个unistd.h都属于Hello World源程序了。
第三行:进行getuid()系统调用,并将返回值赋给变量i。
好了,这就是最简单的一个使用了系统调用的程序,现在你可以在你的机器上试一试它。然后我们一起进入到系统调用的神秘世界中去。

㈧ 如何让linux的一段程序代码进入内核态运行

Linux内核的最初部分代码是用汇编语言写的(文件是boot/bootsect.s)。(我的汇编水平有限,暂且不看),它首先把自身这部分代码移到绝对地址0x90000,把下面的2K代码从引导设备加载到地址0x90200上,内核的其余部分加载到地址0x10000处。在加载系统时显示“loading...”. 然后,程序控制权交给另一个实模式汇编程序(boot/Setup.S)。

接下来,此程序把整个系统从地址0x10000移到地址0x1000,进入保护模式。程序控制转给系统的其余部分即地址0x1000。

下一个步骤是系统内核的解压过程,这部分代码在地址0x1000(文件/Boot/head.S),该段程序初始化寄存器,然后执行decompress_kernel(),这个函数源于zBoot/inflate.c、zBoot/unzip.c和zBoot/misc.c三个文件

Loading....[bootsect.S]
uncompress.....[decompress_kernel()]
main.c--->start_kernel()开始.
开始printk(banner);
Linuxversion2.2.6(root@lance)(gccversion2.7.2.3)(检查一下GCC的版本号,在/init/main.c中如果gcc的版本号不够,时不允许编译内核的)
#40SunApr1817:44:20CST1999
调用init_time()打印出以下内容:
Detected199908264Hzprocessor.
然后运行console_init()-->drivers/char/tty_io.c*/
Console:colourVGA+80x25
运行一个循环,测量一下MIPS–据说是要用一个确定的机器指令周期来实现实时的延迟.
Calibratingdelayloop...199.48BogoMIPS
初始化内存/*init_mem*/
Memory:63396k/65536kavailable(848kkernelcode,408kreserved,856kdata
,28k
/**dquote_init()**/
VFS:Diskquotasversiondquot_6.4.0initialized
察看cpu的类型(在2.2.14以后听说增加了对多种cpu的支持,以后我可得用心看看,ifIcanfindabugofintelthen……)
CPU:IntelPentiumProstepping09
初始或处理器与协处理器,对于比较老的处理器,linux会用软件模拟协处理器?
Checking386/387coupling...OK,.
检查治理的合法性
Checking'hlt'instruction...OK.

此后调用linux_thread(init,..,..,)(arch/i386/kernel/process.c)
创建一个运行init的进程.
进入了第二阶段用户模式(user_mode)Endofstart_kerne最后进入cpu_idle(arch/i386/kernel/process.c)
第二部分设备的初始化
对设备的初始化调用.init()--->do_basic_init()--+
pci_init()对pci设备的初始化(在main.c文件中有这样一段ifdefPCI…..需要看一下)下面打印出结果:
PCI:PCIBIOSrevision2.10entryat0xfd8d1
PCI:Usingconfigurationtype1
PCI:ProbingPCIhardware
对Socket的初始化,socket_init()(这里也许就是linux的网络秘密所在吧,以后我的注意)-LinuxNET4.0forLinux2.2
.039
NET4:Unixdomainsockets1.0forLinuxNET4.0.
NET4:LinuxTCP/IP1.0forNET4.0
IPProtocols:ICMP,UDP,TCP
Startingkswapdv1.5kswapd_setup()
调用device_setup()
DetectedPS/2MousePort.
初始化声卡
Soundinitializationstarted
Soundinitializationcomplete
初始化软驱
Floppydrive(s):fd0is1.44M

SCSI设备的初始化
(scsi0)foundatPCI13/0
(scsi0)WideChannel,SCSIID=7,16/255SCBs
(scsi0)Downloadingsequencercode...419instructionsdownloaded
scsi0:AdaptecAHA274x/284x/294x(EISA/VLB/PCI-FastSCSI)5.1.10/3.2.4
scsi:1host.
Vendor:SEAGATEModel:ST32155WRev:0596
ype:Direct-AccessANSISCSIrevision:02
Detectedscsidisksdaatscsi0,channel0,id0,lun0
Vendor:SEAGATEModel:ST32155WRev:0596
Type:Direct-AccessANSISCSIrevision:02
Detectedscsidisksdbatscsi0,channel0,id1,lun0
scsi:detected2SCSIdiskstotal.
(scsi0:0:0:0)Synchronousat40.0Mbyte/sec,offset8.
SCSIdevicesda:hdwrsector=512bytes.Sectors=4197405[2049MB][2.0GB](scsi0:0:1:0)Synchronousat40.0Mbyte/sec,offset8.
SCSIdevicesdb:hdwrsector=512bytes.Sectors=4197405[2049MB][2.0GB]Partitioncheck:sda:sda1|
sdb:sdb1sdb2|
安装文件系统filesystem_setup()
安装设备驱动程序mount_root()
VFS:Mountedroot(ext2filesystem)readonly.
Freeingunusedkernelmemory:28kfreed
AddingSwap:66540kswap-space(priority-1)
(C)byHannuSavolainen1993-1996
SB3.01detectedOK(220)
at0x220irq5dma1
YM3812andOPL-3driverCopyright(C)byHannuSavolainen,RobHooft1993-1
996at0x388
NET4:AppleTalk0.18forLinuxNET4.0
eth0:IntelEtherExpressPro10/100at0xf800,00:A0:C9:49:2F:FF,IRQ9.
Boardassembly645520-034,Physicalconnectorspresent:RJ45
#1.
DP83840specificsetup,settingregister23to8462.
Generalself-test:passed.
Serialsub-systemself-test:passed.
Internalregistersself-test:passed.
ROMchecksumself-test:passed(0x49caa8d6).
Receiverlock-upworkaroundactivated.
NET4:AppleTalk0.18forLinuxNET4.0
结束do_basic_setup()
open("/dev/console",O_RDWR,0)
开始执行/sbin/init(execv(...))
内核就此启动完毕...

㈨ 内核态与用户态

当程序运行在内核空间时为内核态,当程序运行在用户空间时为用户态。用户态只能访问用户空间下的地址,而内核态可以访问所有地址。

为防止用户程序对系统造成破坏,所以限制用户态程序访问其他内存。

内核态程序执行完成后返回发起调用的用户空间。

所有程序的用户空间是独立的,内核空间确是共享的,通过共享的内核空间实现程序间的数据交互。例如:MMAP。

状态切换需要上下文切换(切换进程),消耗较大。

2022-03-27

㈩ 如何从应用程序进入linux内核

需要让linux的一段程序代码进入内核态运行产生的方式有二: 被动式 主动式 所谓被动式就是产生中断或者代码产出异常,代码不得不从用户态进入内核态进行中断操作或者是异常处理; 而主动式则是系统响应了程序对系统的一次调用过程,并且系统允许该运行级别的提升;

阅读全文

与程序如何在内核态运行相关的资料

热点内容
附近人如何群发信息 浏览:653
福建玉器市场什么地方 浏览:202
如何强行停止某程序 浏览:752
9针数据线接口是什么 浏览:950
枣庄技术员证书怎么考有用吗 浏览:634
有正负的波动数据用什么分析 浏览:309
湛江有哪些水产品种 浏览:384
数学十几减九的数学信息是什么 浏览:874
产品销售分享会怎么开头 浏览:380
错版币怎么鉴定拍卖交易 浏览:699
信息化建设是一个什么样的工作 浏览:666
怎么看塑料产品能不能降解 浏览:49
如何整合金融资产交易所 浏览:972
物联网发展核心技术是什么 浏览:492
什么是电网企业代理购电 浏览:302
玉石交易大厅系统开发需要多少钱 浏览:685
医疗信息交换标准是什么意思 浏览:938
如何提高叉车技术 浏览:97
欠钱最少多少可以走法律程序 浏览:585
哪个行业小程序比较多 浏览:18