Linux 用户态与内核态的交互netlink

Linux 用户态与内核态的交互netlink
Linux 用户态与内核态的交互netlink

这是一篇学习笔记,主要是对《Linux 系统内核空间与用户空间通信的实现与分析》中的源码imp2的分析。其中的源码,可以到以下URL下载:

https://www.360docs.net/doc/8217119583.html,/developerworks/cn/linux/l-netlink/imp2.tar.gz

参考文档

《Linux 系统内核空间与用户空间通信的实现与分析》陈鑫

https://www.360docs.net/doc/8217119583.html,/developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux

《在 Linux 下用户空间与内核空间数据交换的方式》杨燚

https://www.360docs.net/doc/8217119583.html,/developerworks/cn/linux/l-kerns-usrs/

理论篇

在 Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交互就全部使用了netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的主要方法之一。它的通信依据是一个对应于进程的标识,一般定为该进程的 ID。当通信的一端处于中断过程时,该标识为 0。当使用 netlink 套接字进行通信,通信的双方都是用户态进程,则使用方法类似于消息队列。但通信双方有一端是中断过程,使用方法则不同。netlink 套接字的最大特点是对中断过程的支持,它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线程,而是通过另一个软中断调用用户事先指定的接收函数。工作原理如图:

如图所示,这里使用了软中断而不是内核线程来接收数据,这样就可以保证数据接收的实时性。

当 netlink 套接字用于内核空间与用户空间的通信时,在用户空间的创建方法和一般套接字使用类似,但内核空间的创建方法则不同,下图是 netlink 套接字实现此类通信时创建的过程:

用户空间

用户态应用使用标准的socket与内核通讯,标准的socket API 的函数, socket(), bind(), sendmsg(), recvmsg() 和 close()很容易地应用到 netlink socket。

为了创建一个 netlink socket,用户需要使用如下参数调用 socket():

1.socket(AF_NETLINK, SOCK_RAW, netlink_type)

复制代码

netlink对应的协议簇是 AF_NETLINK,第二个参数必须是SOCK_RAW或SOCK_DGRAM,第三个参数指定netlink协议类型,它可以是一个自定义的类型,也可以使用内核预定义的类型:

1.#define NETLINK_ROUTE 0 /* Routing/device hook */

2.#define NETLINK_W1 1 /* 1-wire subsystem */

3.#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */

4.#define NETLINK_FIREWALL 3 /* Firewalling hook */

5.#define NETLINK_INET_DIAG 4 /* INET socket monitoring */

6.#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */

7.#define NETLINK_XFRM 6 /* ipsec */

8.#define NETLINK_SELINUX 7 /* SELinux event notifications */

9.#define NETLINK_ISCSI 8 /* Open-iSCSI */

10.#define NETLINK_AUDIT 9 /* auditing */

11.#define NETLINK_FIB_LOOKUP 10

12.#define NETLINK_CONNECTOR 11

13.#define NETLINK_NETFILTER 12 /* netfilter subsystem */

14.#define NETLINK_IP6_FW 13

15.#define NETLINK_DNRTMSG 14 /* DECnet routing messages */

16.#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */

复制代码

#define NETLINK_GENERIC 16

同样地,socket函数返回的套接字,可以交给bing等函数调用:

1.static int skfd;

2.skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);

3.if(skfd < 0)

4.{

5.printf("can not create a netlink socket\n");

6.exit(0);

7.}

复制代码

bind函数需要绑定协议地址,netlink的socket地址使用struct sockaddr_nl结构描述:

1.struct sockaddr_nl

2.{

3.sa_family_t nl_family;

4.unsigned short nl_pad;

5.__u32 nl_pid;

6.__u32 nl_groups;

7.};

复制代码

成员 nl_family为协议簇 AF_NETLINK,成员 nl_pad 当前没有使用,因此要总是设置为0,成员 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。成员 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组:

1.struct sockaddr_nl local;

2.

3.memset(&local, 0, sizeof(local));

4.local.nl_family = AF_NETLINK;

5.local.nl_pid = getpid(); /*设置pid为自己的pid值*/

6.local.nl_groups = 0;

7./*绑定套接字*/

8.if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)

9.{

10.printf("bind() error\n");

11.return -1;

12.}

复制代码

用户空间可以调用send函数簇向内核发送消息,如sendto、sendmsg等,同样地,也可以使用struct sockaddr_nl来描述一个对端地址,以待send函数来调用,与本地地址稍不同的是,因为对端为内核,所以nl_pid成员需要设置为0:

1.struct sockaddr_nl kpeer;

2.memset(&kpeer, 0, sizeof(kpeer));

3.kpeer.nl_family = AF_NETLINK;

4.kpeer.nl_pid = 0;

5.kpeer.nl_groups = 0;

复制代码

另一个问题就是发内核发送的消息的组成,使用我们发送一个IP网络数据包的话,则数据包结构为“IP包头+IP数据”,同样地,netlink的消息结构是“netlink消息头部+数据”。Netlink消息头部使用struct nlmsghdr结构来描述:

1.struct nlmsghdr

2.{

3.__u32 nlmsg_len; /* Length of message */

4.__u16 nlmsg_type; /* Message type*/

5.__u16 nlmsg_flags; /* Additional flags */

6.__u32 nlmsg_seq; /* Sequence number */

7.__u32 nlmsg_pid; /* Sending process PID */

8.};

复制代码

字段 nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小,一般地,我们使用netlink提供的宏NLMSG_LENGTH来计算这个长度,仅需向

NLMSG_LENGTH宏提供要发送的数据的长度,它会自动计算对齐后的总长度:

1./*计算包含报头的数据报长度*/

2.#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))

3./*字节对齐*/

4.#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )

复制代码

后面还可以看到很多netlink提供的宏,这些宏可以为我们编写netlink宏提供很大的方便。

字段 nlmsg_type 用于应用内部定义消息的类型,它对 netlink 内核实现是透明的,因此大部分情况下设置为 0,字段 nlmsg_flags 用于设置消息标志,对于一般的使用,用户把它设置为 0 就可以,只是一些高级应用(如 netfilter 和路由 daemon 需要它进行一些复杂的操作),字段 nlmsg_seq 和 nlmsg_pid 用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID。

1.struct msg_to_kernel /*自定义消息首部,它仅包含了netlink的消息首部*/

2.{

3.struct nlmsghdr hdr;

4.};

5.

6.struct msg_to_kernel message;

7.memset(&message, 0, sizeof(message));

8.message.hdr.nlmsg_len = NLMSG_LENGTH(0); /*计算消息,因为这里只是发送一

个请求消息,没有多余的数据,所以,数据长度为0*/

9.message.hdr.nlmsg_flags = 0;

10.message.hdr.nlmsg_type = IMP2_U_PID; /*设置自定义消息类型*/

11.message.hdr.nlmsg_pid = local.nl_pid; /*设置发送者的PID*/

12.

13.这样,有了本地地址、对端地址和发送的数据,就可以调用发送函数将消息发送给

内核了:

14./*发送一个请求*/

15.sendto(skfd, &message, message.hdr.nlmsg_len, 0,

16.(struct sockaddr*)&kpeer, sizeof(kpeer));

复制代码

当发送完请求后,就可以调用recv函数簇从内核接收数据了,接收到的数据包含了netlink消息首部和要传输的数据:

1./*接收的数据包含了netlink消息首部和自定义数据结构*/

2.struct u_packet_info

3.{

4.struct nlmsghdr hdr;

5.struct packet_info icmp_info;

7.struct u_packet_info info;

8.while(1)

9.{

10.kpeerlen = sizeof(struct sockaddr_nl);

11./*接收内核空间返回的数据*/

12.rcvlen = recvfrom(skfd, &info, sizeof(struct u_packet_info),

13.0, (struct sockaddr*)&kpeer, &kpeerlen);

14.

15./*处理接收到的数据*/

16.……

17.}

复制代码

同样地,函数close用于关闭打开的netlink socket。程序中,因为程序一直循环接收处理内核的消息,需要收到用户的关闭信号才会退出,所以关闭套接字的工作放在了自定义的信号函数sig_int中处理:

1./*这个信号函数,处理一些程序退出时的动作*/

2.static void sig_int(int signo)

3.{

4.struct sockaddr_nl kpeer;

5.struct msg_to_kernel message;

6.

7.memset(&kpeer, 0, sizeof(kpeer));

8.kpeer.nl_family = AF_NETLINK;

9.kpeer.nl_pid = 0;

10.kpeer.nl_groups = 0;

11.

12.memset(&message, 0, sizeof(message));

13.message.hdr.nlmsg_len = NLMSG_LENGTH(0);

14.message.hdr.nlmsg_flags = 0;

15.message.hdr.nlmsg_type = IMP2_CLOSE;

16.message.hdr.nlmsg_pid = getpid();

18./*向内核发送一个消息,由nlmsg_type表明,应用程序将关闭*/

19.sendto(skfd, &message, message.hdr.nlmsg_len, 0, (struct sockaddr

*)(&kpeer), sizeof(kpeer));

20.

21.close(skfd);

22.exit(0);

23.}

复制代码

这个结束函数中,向内核发送一个“我已经退出了”的消息,然后调用close函数关闭netlink套接字,退出程序。

内核空间

与应用程序内核,内核空间也主要完成三件工作:

n 创建netlink套接字

n 接收处理用户空间发送的数据

n 发送数据至用户空间

API函数netlink_kernel_create用于创建一个netlink socket,同时,注册一个回调函数,用于接收处理用户空间的消息:

1.struct sock *

https://www.360docs.net/doc/8217119583.html,link_kernel_create(int unit, void (*input)(struct sock *sk, int len));复制代码

参数unit表示netlink协议类型,如NL_IMP2,参数input则为内核模块定义的netlink

消息处理函数,当有消息到达这个netlink socket时,该input函数指针就会被引用。函数指针input的参数sk实际上就是函数netlink_kernel_create返回的struct sock指针,sock实际是socket的一个内核表示数据结构,用户态应用创建的socket在内核中也会有

一个struct sock结构来表示。

1.static int __init init(void)

2.{

3.rwlock_init(&user_proc.lock); /*初始化读写锁*/

4.

5./*创建一个netlink socket,协议类型是自定义的ML_IMP2,kernel_reveive为

接受处理函数*/

6.nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);

7.if(!nlfd) /*创建失败*/

8.{

9.printk("can not create a netlink socket\n");

10.return -1;

11.}

12.

13./*注册一个Netfilter 钩子*/

14.return nf_register_hook(&imp2_ops);

15.}

16.

17.

18.module_init(init);

复制代码

用户空间向内核发送了两种自定义消息类型:IMP2_U_PID和IMP2_CLOSE,分别是请求和关闭。kernel_receive 函数分别处理这两种消息:

1.DECLARE_MUTEX(receive_sem); /*初始化信号量*/

2.static void kernel_receive(struct sock *sk, int len)

3.{

4.do

5.{

6.struct sk_buff *skb;

7.if(down_trylock(&receive_sem)) /*获取信号量*/

8.return;

9./*从接收队列中取得skb,然后进行一些基本的长度的合法性校验*/

10.while((skb = skb_dequeue(&sk->receive_queue)) != NULL)

11.{

12.{

13.struct nlmsghdr *nlh = NULL;

14.

15.if(skb->len >= sizeof(struct nlmsghdr))

16.{

17./*获取数据中的nlmsghdr 结构的报头*/

18.nlh = (struct nlmsghdr *)skb->data;

19.if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))

20.&& (skb->len >= nlh->nlmsg_len))

21.{

22./*长度的全法性校验完成后,处理应用程序自定义消息类型,主要是对用户PID的

保存,即为内核保存“把消息发送给谁”*/

23.if(nlh->nlmsg_type == IMP2_U_PID) /*请求*/

24.{

25.write_lock_bh(&user_proc.pid);

https://www.360docs.net/doc/8217119583.html,er_proc.pid = nlh->nlmsg_pid;

27.write_unlock_bh(&user_proc.pid);

28.}

29.else if(nlh->nlmsg_type == IMP2_CLOSE) /*应用程序关闭*/

30.{

31.write_lock_bh(&user_proc.pid);

32.if(nlh->nlmsg_pid == user_proc.pid)

https://www.360docs.net/doc/8217119583.html,er_proc.pid = 0;

34.write_unlock_bh(&user_proc.pid);

35.}

36.}

37.}

38.}

39.kfree_skb(skb);

40.}

41.up(&receive_sem); /*返回信号量*/

42.}while(nlfd && nlfd->receive_queue.qlen);

43.}

复制代码

因为内核模块可能同时被多个进程同时调用,所以函数中使用了信号量和锁来进行互斥。skb = skb_dequeue(&sk->receive_queue)用于取得socket sk的接收队列上的消息,返回为一个struct sk_buff的结构,skb->data指向实际的netlink消息。

程序中注册了一个Netfilter钩子,钩子函数是get_icmp,它截获ICMP数据包,然后调

用send_to_user函数将数据发送给应用空间进程。发送的数据是info结构变量,它是struct packet_info结构,这个结构包含了来源/目的地址两个成员。Netfilter Hook不

是本文描述的重点,略过。

send_to_user 用于将数据发送给用户空间进程,发送调用的是API函数netlink_unicast 完成的:

1.int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int

nonblock);

复制代码

参数sk为函数netlink_kernel_create()返回的套接字,参数skb存放待发送的消息,它

的data字段指向要发送的netlink消息结构,而skb的控制块保存了消息的地址信息,

参数pid为接收消息进程的pid,参数nonblock表示该函数是否为非阻塞,如果为1,该

函数将在没有接收缓存可利用时立即返回,而如果为0,该函数在没有接收缓存可利用时

睡眠。

向用户空间进程发送的消息包含三个部份:netlink 消息头部、数据部份和控制字段,控

制字段包含了内核发送netlink消息时,需要设置的目标地址与源地址,内核中消息是通

过sk_buff来管理的, linux/netlink.h中定义了NETLINK_CB宏来方便消息的地址设置:

1.#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))

复制代码

例如:

https://www.360docs.net/doc/8217119583.html,LINK_CB(skb).pid = 0;

https://www.360docs.net/doc/8217119583.html,LINK_CB(skb).dst_pid = 0;

https://www.360docs.net/doc/8217119583.html,LINK_CB(skb).dst_group = 1;

复制代码

字段pid表示消息发送者进程ID,也即源地址,对于内核,它为 0, dst_pid 表示消息接收者进程 ID,也即目标地址,如果目标为组或内核,它设置为 0,否则 dst_group 表示目标组地址,如果它目标为某一进程或内核,dst_group 应当设置为 0。

1.static int send_to_user(struct packet_info *info)

2.{

3.int ret;

4.int size;

5.unsigned char *old_tail;

6.struct sk_buff *skb;

7.struct nlmsghdr *nlh;

8.struct packet_info *packet;

9.

10./*计算消息总长:消息首部加上数据加度*/

11.size = NLMSG_SPACE(sizeof(*info));

12.

13./*分配一个新的套接字缓存*/

14.skb = alloc_skb(size, GFP_ATOMIC);

15.old_tail = skb->tail;

16.

17./*初始化一个netlink消息首部*/

18.nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh));

19./*跳过消息首部,指向数据区*/

20.packet = NLMSG_DATA(nlh);

21./*初始化数据区*/

22.memset(packet, 0, sizeof(struct packet_info));

23./*填充待发送的数据*/

24.packet->src = info->src;

25.packet->dest = info->dest;

26.

27./*计算skb两次长度之差,即netlink的长度总和*/

28.nlh->nlmsg_len = skb->tail - old_tail;

29./*设置控制字段*/

https://www.360docs.net/doc/8217119583.html,LINK_CB(skb).dst_groups = 0;

31.

32./*发送数据*/

33.read_lock_bh(&user_proc.lock);

34.ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT);

35.read_unlock_bh(&user_proc.lock);

36.

37.

38.}

复制代码

函数初始化netlink 消息首部,填充数据区,然后设置控制字段,这三部份都包含在

skb_buff中,最后调用netlink_unicast函数把数据发送出去。

函数中调用了netlink的一个重要的宏NLMSG_PUT,它用于初始化netlink 消息首部:

1.#define NLMSG_PUT(skb, pid, seq, type, len) \

2.({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \

3.__nlmsg_put(skb, pid, seq, type, len); })

4.static __inline__ struct nlmsghdr *

5.__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)

6.{

7.struct nlmsghdr *nlh;

8.int size = NLMSG_LENGTH(len);

9.

10.nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));

11.nlh->nlmsg_type = type;

12.nlh->nlmsg_len = size;

13.nlh->nlmsg_flags = 0;

14.nlh->nlmsg_pid = pid;

15.nlh->nlmsg_seq = seq;

16.return nlh;

17.}

复制代码

这个宏一个需要注意的地方是调用了nlmsg_failure标签,所以在程序中应该定义这个标签。

在内核中使用函数sock_release来释放函数netlink_kernel_create()创建的netlink socket:

1.void sock_release(struct socket * sock);

复制代码

程序在退出模块中释放netlink sockets和netfilter hook:

1.static void __exit fini(void)

2.{

3.if(nlfd)

4.{

5.sock_release(nlfd->socket); /*释放netlink socket*/

6.}

7.nf_unregister_hook(&imp2_ops); /*撤锁netfilter 钩子*/

8.}

复制代码

操作系统复习题

复习题一 一、选择题 1、下列选项中,不可能在用户态发生的事件是() A.系统调用 B.外部中断 C.进程切换 D.缺页 2、中断处理和子程序调用都需要压栈以保护现场,中断处理一定会保存而子程序调用不需要保存其内容的是() A.程序计数器 B.程序状态字寄存器 C.通用数据寄存器 D.通用地址寄存器 3、下列关于虚拟存储器的叙述中,正确的是() A.虚拟存储只能基于连续分配技术 B.虚拟存储只能基于非连续分配技术 C.虚拟存储容量只受外存容量的限制 D.虚拟存储容量只受内存容量的限制 4、假设5个进程P0、P1、P2、P3、P4共享三类资源R1、R2、R3,这些资源总数分别为18、6、22。T0时刻的资源分配情况如下表所示,此时存在的一个安全序列是() A. P0,P2,P4,P1,P3 B. P1,P0,P3,P4,P2 C. P2,P1,P0,P3,P4 D. P3,P4,P2,P1,P0 5、操作系统的I/O软件通常由四个层次组成,每一层明确定义了与邻近层次的接口,其合理的层次组织排列顺序是() A.用户级I/O软件、设备无关软件、设备驱动程序、中断处理程序 B.用户级I/O软件、设备无关软件、中断处理程序、设备驱动程序 C.用户级I/O软件、设备驱动程序、设备无关软件、中断处理程序 D.用户级I/O软件、中断处理程序、设备无关软件、设备驱动程序 6、一个多道批处理系统中仅有P1和P2两个作业,P2比P1晚5ms到达,它的计算和I/O操作顺序如下: P1:计算60ms,I/O 80ms,计算20ms P2:计算120ms,I/O 40ms,计算40ms 若不考虑调度和切换时间,则完成两个作业需要的时间最少是()

基于32位ARM920T内核的微处理器的嵌入式Linux系统构建详解

基于32位ARM920T内核的微处理器的嵌入式Linux系统构建详解目前,在嵌入式系统中基于ARM微核的嵌入式处理器已经成为市场主流。随着ARM技术的广泛应用,建立面向ARM构架的嵌入式操作系统成为当前研究的热点问题。 已经涌现出许多嵌入式操作系统,如VxWork,windows-CE,PalmOS,Linux等。在众多的嵌入式操作系统中,Linux以其开源代码及免费使用倍受开发人员的喜爱。本文选用的微处理器S3C2410是基于32位ARM920T内核的微处理器,基于此处理器构造一Linux 嵌入式操作系统,将其移植到基于32位的ARM920T内核的系统中,在此基础上进行应用程序开发。 l、开发环境介绍 1.1、基于S3C2410ARM920T的硬件平台 该系统的硬件平台为深圳旋极公司提供,硬件的核心部件为三星$3C2410ARM920T芯片,外围还包括:64MNANDFLASH和RAM外围存储芯片;串口、网口和USB外围接口;CSTNLCD和触摸屏外围显示设备;UDAl34lTS的外围音频设备。S3C2410处理器和外围设备共同构成了基于ARM920T的开发板。 1.2、嵌入式Limlx软件系统 该嵌入式Linux的软件系统包括以下4个部分:引导加载程序vivi;Linux2.6.14内核;YAFFS2文件系统以及用户程序。他们的可执行映像依次存放在系统存储设备上. 与通常的嵌入式系统布局有所不同,本系统在引导加载程序和内核映像之间还增加了一个启动参数区,在这个区里存放着系统启动参数。引导加载程序通过调用这些参数来决定启动模式、启动等待时间等,这些启动参数的增加加强了系统的灵活性。本系统采用64MNANDFLASH的存储设备。 2、嵌入式Linux系统设计与实现 2.1、引导加载程序vivi

探究linux内核,超详细解析子系统

探究linux内核,超详细解析子系统 Perface 前面已经写过一篇《嵌入式linux内核的五个子系统》,概括性比较强,也比较简略,现在对其进行补充说明。 仅留此笔记,待日后查看及补充!Linux内核的子系统 内核是操作系统的核心。Linux内核提供很多基本功能,如虚拟内存、多任务、共享库、需求加载、共享写时拷贝(Copy-On-Write)以及网络功能等。增加各种不同功能导致内核代码不断增加。 Linux内核把不同功能分成不同的子系统的方法,通过一种整体的结构把各种功能集合在一起,提高了工作效率。同时还提供动态加载模块的方式,为动态修改内核功能提供了灵活性。系统调用接口用户程序通过软件中断后,调用系统内核提供的功能,这个在用户空间和内核提供的服务之间的接口称为系统调用。系统调用是Linux内核提供的,用户空间无法直接使用系统调用。在用户进程使用系统调用必须跨越应用程序和内核的界限。Linux内核向用户提供了统一的系统调用接口,但是在不同处理器上系统调用的方法

各不相同。Linux内核提供了大量的系统调用,现在从系统 调用的基本原理出发探究Linux系统调用的方法。这是在一个用户进程中通过GNU C库进行的系统调用示意图,系 统调用通过同一个入口点传入内核。以i386体系结构为例,约定使用EAX寄存器标记系统调用。 当加载了系统C库调用的索引和参数时,就会调用0x80软件中断,它将执行system_call函数,这个函数按照EAX 寄存器内容的标示处理所有的系统调用。经过几个单元测试,会使用EAX寄存器的内容的索引查system_call_table表得到系统调用的入口,然后执行系统调用。从系统调用返回后,最终执行system_exit,并调用resume_userspace函数返回用户空间。 linux内核系统调用的核心是系统多路分解表。最终通过EAX寄存器的系统调用标识和索引值从对应的系统调用表 中查出对应系统调用的入口地址,然后执行系统调用。 linux系统调用并不单层的调用关系,有的系统调用会由

用户态至内核态的通讯

Proc fs /proc目录是系统模拟出来的一个文件系统,本身并不存在于磁盘上,其中的文件都表示内核 参数的信息 /proc 在linux系统中非常多地应用. 很多现代 Linux 发布中的工具, 例如 ps, top, 以及 uptime, 从 /proc 中获取它们的信息. 一些设备驱动也通过 /proc 输出信息. Netlink Netlink相对于其他的通信机制具有以下优点: 1.使用Netlink通过自定义一种新的协议并加入协议族即可通过socket API使用 Netlink协议完成数据交换,而ioctl和proc文件系统均需要通过程序加入相应的设 备或文件。 https://www.360docs.net/doc/8217119583.html,link使用socket缓存队列,是一种异步通信机制,而ioctl是同步通信机制,如 果传输的数据量较大,会影响系统性能。 https://www.360docs.net/doc/8217119583.html,link支持多播,属于一个Netlink组的模块和进程都能获得该多播消息。 https://www.360docs.net/doc/8217119583.html,link允许内核发起会话,而ioctl和系统调用只能由用户空间进程发起。 Syscall syscall的范围就广了,通过注册字符设备可以使用mmap和ioctl等来进行操作,要注意 的是在内核态ioctl已经被废弃,现在应该使用unlocked_ioctl,需要自己来加锁。 用户态通过系统暴露出来的系统调用来进行操作,如mmap,ioctl,open,close,read,write,内核态通过建立共享内存remap_pfn_range或者copy_to_user, copy_from_user 来进行操作。 IOCTL 内核和用户空间进行通信,大概有如下几种方式可以考虑: 采用内存映射的方式,将内核地址映射到用户态。这种方式最直接,可以适用大量的 数据传输机制。这种方式的缺点是很难进行“业务控制”,没有一种可靠的机制保障 内核和用户态的调动同步,比如信号量等都不能跨内核、用户层使用。因此内存映射 机制一般需要配合一种“消息机制”来控制数据的读取,比如采用“消息”类型的短 数据通道来完成一个可靠的数据读取功能。 ioctl机制,ioctl机制可以在驱动中扩展特定的ioctl消息,用于将一些状态从内核反应到用户态。Ioctl有很好的数据同步保护机制,不要担心内核和用户层的数据访问冲突,但是ioctl不适合传输大量的数据,通过和内存映射结合可以很好的完成大量数据交换 过程。但是,ioctl的发起方一定是在用户态,因此如果需要内核态主动发起一个通知 消息给用户层,则非常的麻烦。可能需要用户态程序采用轮询机制不停的ioctl。

嵌入式Linux内核移植详解(顶嵌)

内核移植阶段 内核是操作系统最基本的部分。它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件操作多长时间。直接对硬件操作是非常复杂的,所以内核通常提供一种硬件抽象的方法来完成这些操作。硬件抽象隐藏了复杂性,为应用软件和硬件提供了一套简洁,统一的接口,使程序设计更为简单。 内核和用户界面共同为用户提供了操作计算机的方便方式。也就是我们在windows下看到的操作系统了。由于内核的源码提供了非常广泛的硬件支持,通用性很好,所以移植起来就方便了许多,我们需要做的就是针对我们要移植的对象,对内核源码进行相应的配置,如果出现内核源码中不支持的硬件这时就需要我们自己添加相应的驱动程序了。 一.移植准备 1. 目标板 我们还是选用之前bootloader移植选用的开发板参数请参考上文的地址: https://www.360docs.net/doc/8217119583.html,/thread-80832-5-1.html。bootloader移植准备。 2. 内核源码 这里我们选用比较新的内核源码版本linux-2.6.25.8,他的下载地址是 ftp://https://www.360docs.net/doc/8217119583.html,/pub/linux/kernel/v2.6/linux-2.6.25.8.tar.bz2。 3. 烧写工具 我们选用网口进行烧写这就需要内核在才裁剪的时候要对网卡进行支持 4. 知识储备 要进行内核裁剪不可缺少的是要对内核源码的目录结构有一定的了解这里进 行简单介绍。 (1)arch/: arch子目录包括了所有和体系结构相关的核心代码。它的每一个子 目录都代表一种支持的体系结构,例如i386就是关于intel cpu及与之相兼容体 系结构的子目录。PC机一般都基于此目录。 (2)block/:部分块设备驱动程序。 (3)crypto:常用加密和散列算法(如AES、SHA等),还有一些压缩和CRC校验 算法。 (4) documentation/:文档目录,没有内核代码,只是一套有用的文档。 (5) drivers/:放置系统所有的设备驱动程序;每种驱动程序又各占用一个子目 录:如,/block 下为块设备驱动程序,比如ide(ide.c)。 (6)fs/:所有的文件系统代码和各种类型的文件操作代码,它的每一个子目录支持 一个文件系统, 例如fat和ext2。

linux内核IMQ源码实现分析

本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。 E-mail: wwwlkk@https://www.360docs.net/doc/8217119583.html, 来源: https://www.360docs.net/doc/8217119583.html,/?business&aid=6&un=wwwlkk#7 linux2.6.35内核IMQ源码实现分析 (1)数据包截留并重新注入协议栈技术 (1) (2)及时处理数据包技术 (2) (3)IMQ设备数据包重新注入协议栈流程 (4) (4)IMQ截留数据包流程 (4) (5)IMQ在软中断中及时将数据包重新注入协议栈 (7) (6)结束语 (9) 前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。 首先揭示IMQ的核心技术: 1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。 2.如何做到及时的将数据包重新注入协议栈。 实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。下面先介绍这2个技术。 (1)数据包截留并重新注入协议栈技术

(2)及时处理数据包技术 QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数

激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的 证了数据包会被及时的发送。 这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。

Linux内核结构详解教程

Linux内核结构详解教程 ─────Linux内核教程 linux内核就像人的心脏,灵魂,指挥中心。 内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等. 严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux. 一个Linux内核很少1.2M左右,一张软盘就能放下. 内容基础,语言简短简洁 红联Linux论坛是致力于Linux技术讨论的站点,目前网站收录的文章及教程基本能满足不同水平的朋友学习。 红联Linux门户: https://www.360docs.net/doc/8217119583.html, 红联Linux论坛: https://www.360docs.net/doc/8217119583.html,/bbs 红联Linux 论坛大全,所有致力点都体现在这 https://www.360docs.net/doc/8217119583.html,/bbs/rf/linux/07.htm

目录 Linux内核结构详解 Linux内核主要五个子系统详解 各个子系统之间的依赖关系 系统数据结构 Linux的具体结构 Linux内核源代码 Linux 内核源代码的结构 从何处开始阅读源代码 海量Linux技术文章

Linux内核结构详解 发布时间:2006-11-16 19:05:29 Linux内核主要由五个子系统组成:进程调度,内存管理,虚拟文件系统,网络接口,进程间通信。

Linux内核主要五个子系统详解 发布时间:2006-11-16 19:05:54 1.进程调度(SCHED):控制进程对CPU的访问。当需要选择下一个进程运行时,由调度程序选择最值得运行的进程。可运行进程实际上是仅等待CPU资源的进程,如果某个进程在等待其它资源,则该进程是不可运行进程。Linux使用了比较简单的基于优先级的进程调度算法选择新的进程。 2.内存管理(MM)允许多个进程安全的共享主内存区域。Linux的内存管理支持虚拟内存,即在计算机中运行的程序,其代码,数据,堆栈的总量可以超过实际内存的大小,操作系统只是把当前使用的程序块保留在内存中,其余的程序块则保留在磁盘中。必要时,操作系统负责在磁盘和内存间交换程序块。内存管理从逻辑上分为硬件无关部分和硬件有关部分。硬件无关部分提供了进程的映射和逻辑内存的对换;硬件相关的部分为内存管理硬件提供了虚拟接口。 3.虚拟文件系统(VirtualFileSystem,VFS)隐藏了各种硬件的具体细节,为所有的设备提供了统一的接口,VFS提供了多达数十种不同的文件系统。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。 4.网络接口(NET)提供了对各种网络标准的存取和各种网络硬件的支持。网络接口可分为网络协议和网络驱动程序。网络协议部分负责实现每一种可能的网络传输协议。网络设备驱动程序负责与硬件设备通讯,每一种可能的硬件设备都有相应的设备驱动程序。 5.进程间通讯(IPC) 支持进程间各种通信机制。 处于中心位置的进程调度,所有其它的子系统都依赖它,因为每个子系统都需要挂起或恢复进程。一般情况下,当一个进程等待硬件操作完成时,它被挂起;当操作真正完成时,进程被恢复执行。例如,当一个进程通过网络发送一条消息时,网络接口需要挂起发送进程,直到硬件成功地完成消息的发送,当消息被成功的发送出去以后,网络接口给进程返回一个代码,表示操作的成功或失败。其他子系统以相似的理由依赖于进程调度。

操作系统题库

《操作系统》题库 【注】本题库按照讲课内容的顺序进行组织,仅供15软件《操作系统》课程期 末复习使用。复习时可先理解每一讲PPT的内容以及教材相应的章节,然后通 过做题巩固所学知识。期末考试涉及的知识点大部分已覆盖,但并不意味着考 题一定会从此题库中出,出题的形式肯定会有变化。 1. 概述 (1)操作系统属于____。 A. 硬件 B. 系统软件 C. 通用库 D. 应用软件【注】操作系统是管理计算机硬件与软件资源的计算机程序,例如Windows,Linux,Android,iOS等。应用软件一般是基于操作系统提供的接口,为针对使用者的某种应用目的所撰写的软件,例如Office Word,浏览器,手机游戏等。而通用库,一般是指为了便于程序开发,对常用的程序功能封装后被调用的程序。 (2)以下哪个不能用于描述操作系统? A. 使计算机方便使用 B. 可以管理计算机硬件 C. 可以控制应用软件的执行 D. 负责生成应用软件 【注】操作系统负责管理计算机的硬件资源,使得用户不需要关心硬件的工作过程,极大地方便了计算机的使用。我们日常使用计算机,往往已经在使用了特定的操作系统,例如Windows,而在操作系统上,会同时运行多个应用软件,例如浏览器,音乐播放器等,为了让一个或者多个软件能够正常使用有限的硬件资源,操作系统需要管理应用程序的执行过程。一般来说,像浏览器,音乐播放器,和其他应用软件,都是由特定的个人和团队开发的,操作系统不负责生成应用软件。 (3)以下不属于操作系统的功能是____。 A. 进程调度 B. 内存管理 C. 视频编辑 D. 设备驱动【注】视频编辑是一个特定的功能,不是系统范围内的共性需求,具体完成这个功能的是视频编辑应用软件。 (4)操作系统中的多道程序设计方式用于提高____。 A. 稳定性 B. 效率 C. 兼容性 D. 可靠性

简析linux内核的内核执行流程图

简析linux核的执行流程 ----从bootsect.s到main.c(核版本0.11)Linux启动的第一阶段(从开机到main.c) 3个任务: A、启动BIOS,准备实模式下的中断向量表和中断服务程序。 B、从启动盘加载操作系统程序到存。 C、为执行32的main函数做过渡准备。 存变化如下: ①、0xFE000到0xFFFFF是BIOS启动块,其中上电后第一条指令在0xFFFF0。 ②、而后0x00000到0x003FF总共1KB存放中断向量表,而接下去的地址到0x004FF共256B存放BIOS数据,从0x0E05B 开始的约8KB的存中存放中断服务程序。 ③、利用BIOS中断0x19h把硬盘的第一扇区bootsect.s的代码加载到存中,即0x07c00处,后转到该处执行。 ④、将bootsect.s的代码复制到0x90000处。 ⑤、利用中断0x13h将setup.s程序加载到存0x90200处。 ⑥、再将剩余的约240个扇区的容加载到0x10000~0x2EFFF 处。 ⑦、开始转到setup.s处执行,第一件事就利用BIOS提供的中断服务程序从设备上获取核运行的所需系统数据并存在0x90000的地址处,这时将原来bootsect.s的代码覆盖得只剩2Byte的空间。

⑧、关中断并将系统代码复制到0x00000处,将原来放在这里的中断向量表与BIOS数据区覆盖掉,地址围是 0x00000~0x1EFFF。同时制作两表与两寄存器。 ⑨开地址线A20,寻址空间达到4GB,后对8259重新编程,改变中断号。 ⑩、转到head.s(大小是25K+184B)执行,执行该程序完后是这样的: 0x00000~0x04FFF:页目录与4个页表,每一项是4KB,共20KB;0x05000~0x05400:共1KB的空间是软盘缓冲区; 0x05401~0x054b8:共184B没用; 0x054b9~0x05cb8:共2KB的空间存中断描述符表; 0x05cb9~0x064b8:共2KB的空间存全局描述符表; 之后就是main函数的代码了! 第二阶段、从main.c函数到系统准备完毕阶段。 第一步:创建进程0,并让进程0具备在32位保护模式下载主机中的运算能力。流程是: 复制根设备和硬盘参数表(main.c中的102、110、111行) 物理存规划格局(main.c的112行~126行,其中有 rd_init函数定义在kernel/ramdisk.c中,此函数用于虚拟盘初始化;而mem_init函数是用于存管理结构初始化,定义在mem/memory.c中,该函数页面使用

计算机操作系统实验_运行用户态程序

西北工业大学操作系统实验实验报告 一、实验目的 掌握在GeekOS系统用户态模式下加载并运行可执行程序的方法。 二、实验要求 1. 按照实验讲义P127页中的设计要求,实现在用户态模式下加载并运行可执行程序的代码,给出关键函数的代码以及实验结果。 三、实验过程及结果 答:核心函数代码如下: ================== user.c =============== //产生一个进程(用户态) int Spawn(const char *program, const char *command, struct Kernel_Thread **pThread) { //TODO("Spawn a process by reading an executable from a filesystem"); int rc; char *exeFileData = 0; ulong_t exeFileLength; struct User_Context *userContext = 0; struct Kernel_Thread *process = 0; struct Exe_Format exeFormat; if ((rc = Read_Fully(program, (void**) &exeFileData, &exeFileLength)) != 0 ) { Print("Failed to Read File %s!\n", program); goto fail; } if((rc = Parse_ELF_Executable(exeFileData, exeFileLength, &exeFormat)) != 0 ) { Print("Failed to Parse ELF File!\n"); goto fail; } if((rc = Load_User_Program(exeFileData, exeFileLength, &exeFormat, command, &userContext)) != 0) { Print("Failed to Load User Program!\n"); goto fail; } //在堆分配方式下释放内存并再次初始化exeFileData Free(exeFileData); exeFileData = 0;

Linux内核与跟文件系统的关系

Linux内核与根文件系统的关系 开篇题外话:对于Linux初学者来说,这是一个很纠结的问题,但这也是一个很关键的问题!一语破天机:“尽管内核是Linux 的核心,但文件却是用户与操作系统交互所采用的主要工具。这对Linux 来说尤其如此,这是因为在UNIX 传统中,它使用文件I/O 机制管理硬件 设备和数据文件。” 一.什么是文件系统 文件系统指文件存在的物理空间,linux系统中每个分区都是一个文件系统,都有自己的目 录层次结构。 Linux文件系统中的文件是数据的集合,文件系统不仅包含着文件中的数据而且还有文件系统的结构,所有Linux 用户和程序看到的文件、目录、软连接及文件保护信息等都存储在其 中。这种机制有利于用户和操作系统的交互。 每个实际文件系统从操作系统和系统服务中分离出来,它们之间通过一个接口层:虚拟文件系统或VFS来通讯。VFS使得Linux可以支持多个不同的文件系统,每个表示一个VFS 的通用接口。由于软件将Linux 文件系统的所有细节进行了转换,所以Linux核心的其它部分及系统中运行的程序将看到统一的文件系统。Linux 的虚拟文件系统允许用户同时能透明地安装 许多不同的文件系统。 在Linux文件系统中,EXT2文件系统、虚拟文件系统、/proc文件系统是三个具有代表性的 文件系统。 二.什么是根文件系统 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所挂载(mount)的第一个文件系统,内核代码的映像文件保存在根文件系统中,系统引导启动程序会在根文件系统挂载之后从中把一些初始化脚本(如rcS,inittab)和服务加载到内存中去运行。我们要明白文件系统和内核是完全独立的两个部分。在嵌入式中移植的内核下载到开发板上,是没有办法真正的启动Linux操作系统的,会出现无法加载文件系统的错误。 那么根文件系统在系统启动中到底是什么时候挂载的呢?先将/dev/ram0挂载,而后执行/linuxrc.等其执行完后。切换根目录,再挂载具体的根文件系统.根文件系统执行完之后,也就是到了Start_kernel()函数的最后,执行init的进程,也就第一个用户进程。对系统进行各 种初始化的操作。 根文件系统之所以在前面加一个”根“,说明它是加载其它文件系统的”根“,既然是根的话,那么如果没有这个根,其它的文件系统也就没有办法进行加载的。它包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在Linux挂载分区时Linux 一定会找/etc/fstab这个挂载文件等,根文件系统中还包括了许多的应用程序bin目录等,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。成功之后可以自动或手动挂载其他的文件系统。因此,一个系统中可以同时存在不同的文件系统。在Linux 中将一个文件系统与一个存储设备关联起来的过程称为挂载(mount)。使用mount 命令将一个文件系统附着到当前文件系统层次结构中(根)。在执行挂装时,要提供文件系统类型、文件系统和一个挂装点。根文件系统被挂载到根目录下“/”上后,在根目录下就有根文件系统的各个目录,文件:/bin /sbin /mnt等,再将其他分区挂接到/mnt 目录上,/mnt目录下就有这个分区的各个目录,文件。

linux内核启动 Android系统启动过程详解

linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)

……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader

Linux内核分析-网络[五]:网桥

看完了路由表,重新回到netif_receive_skb ()函数,在提交给上层协议处理前,会执行下面一句,这就是网桥的相关操作,也是这篇要讲解的容。 view plaincopy to clipboardprint? 1. s kb = handle_bridge(skb, &pt_prev, &ret, orig_dev); 网桥可以简单理解为交换机,以下图为例,一台linux机器可以看作网桥和路由的结合,网桥将物理上的两个局域网LAN1、LAN2当作一个局域网处理,路由连接了两个子网1.0和2.0。从eth0和eth1网卡收到的报文在Bridge模块中会被处理成是由Bridge收到的,因此Bridge也相当于一个虚拟网卡。 STP五种状态 DISABLED BLOCKING LISTENING LEARNING FORWARDING 创建新的网桥br_add_bridge [net\bridge\br_if.c] 当使用SIOCBRADDBR调用ioctl时,会创建新的网桥br_add_bridge。 首先是创建新的网桥: view plaincopy to clipboardprint?

1. d ev = new_bridge_dev(net, name); 然后设置dev->dev.type为br_type,而br_type是个全局变量,只初始化了一个名字变量 view plaincopy to clipboardprint? 1. S ET_NETDEV_DEVTYPE(dev, &br_type); 2. s tatic struct device_type br_type = { 3. .name = "bridge", 4. }; 然后注册新创建的设备dev,网桥就相当一个虚拟网卡设备,注册过的设备用ifconfig 就可查看到: view plaincopy to clipboardprint? 1. r et = register_netdevice(dev); 最后在sysfs文件系统中也创建相应项,便于查看和管理: view plaincopy to clipboardprint? 1. r et = br_sysfs_addbr(dev); 将端口加入网桥br_add_if() [net\bridge\br_if.c] 当使用SIOCBRADDIF调用ioctl时,会向网卡加入新的端口br_add_if。 创建新的net_bridge_port p,会从br->port_list中分配一个未用的port_no,p->br会指向br,p->state设为BR_STATE_DISABLED。这里的p实际代表的就是网卡设备。 view plaincopy to clipboardprint? 1. p = new_nbp(br, dev); 将新创建的p加入CAM表中,CAM表是用来记录mac地址与物理端口的对应关系;而刚刚创建了p,因此也要加入CAM表中,并且该表项应是local的[关系如下图],可以看到,CAM表在实现中作为net_bridge的hash表,以addr作为hash值,链入 net_bridge_fdb_entry,再由它的dst指向net_bridge_port。

操作系统复习题(部分)(1)

一、选择题 1、在下列文件的外存分配方式中,不利于文件长度动态增长的文件物理结构是( A )。 A.连续分配 B.链接分配 C.索引分配 D.以上都不对 2、若文件的外存分配方式采用连续分配,则文件控制块FCB中有关文件的物理位置的信息应包括( B )。 (Ⅰ)起始块号(Ⅱ)文件长度(Ⅲ)索引表地址 A.全部 B.(Ⅰ)和(Ⅱ) C.(Ⅰ)和(Ⅲ) D.(Ⅱ)和(Ⅲ) 3、文件系统中可命名的最小数据单位是(C)。 A.字符串 B.记录 C.数据项 D.文件 4、文件系统最基本的目标之一是实现“按名存取”,它主要是通过( B )功能实现的。 A.存储空间管理 B.目录管理 C. 文件读写管理 D. 文件安全性管理 5、一个文件的绝对路径名是从( B )开始,逐步沿着每一级子目录向下追溯,最后到指定文件的通路上所有子目录名及“/”(或“\”)组成的字符串。 A. 当前目录 B. 根目录 C. 多级目录 D. 二级目录 6、假定盘块的大小为1KB,对于1.2M的硬盘,对于FAT,需占用( C )的存储空间。 A. 1KB B. 1.5KB C. 1.8KB D. 2.4KB 7、对文件存储空间的管理,在MS-DOS操作系统中是采用( B ),在Unix中采用( D )。 A. 空闲表 B. 文件分配表 C. 位示图 D. 成组链接法 8、在文件系统中通常是利用( D )来组织大量文件的。 A. 文件控制表 B. 索引结点 C. 符号名表 D. 目录 1、操作系统是一种____B____。 A.通用软件 B.系统软件 C.应用软件 D.软件包 2、操作系统是对 C 进行管理的软件。 A.软件 B.硬件 C.计算机资源 D.应用程序 3、操作系统中采用多道程序设计技术提高CPU与外部设备的 A 。 A.利用率 B.可靠性 C.稳定性 D.兼容性

史上最全linux内核配置详解

对于每一个配置选项,用户可以回答"y"、"m"或"n"。其中"y"表示将相应特性的支持或设备驱动程序编译进内核;"m"表示将相应特性的支持或设备驱动程序编译成可加载模块,在需要时,可由系统或用户自行加入到内核中去;"n"表示内核不提供相应特性或驱动程序的支持。只有<>才能选择M 1. General setup(通用选项) [*]Prompt for development and/or incomplete code/drivers,设置界面中显示还在开发或者还没有完成的代码与驱动,最好选上,许多设备都需要它才能配置。 [ ]Cross-compiler tool prefix,交叉编译工具前缀,如果你要使用交叉编译工具的话输入相关前缀。默认不使用。嵌入式linux更不需要。 [ ]Local version - append to kernel release,自定义版本,也就是uname -r可以看到的版本,可以自行修改,没多大意义。 [ ]Automatically append version information to the version string,自动生成版本信息。这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。这需要Perl的支持。由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。 Kernel compression mode (LZMA),选择压缩方式。 [ ]Support for paging of anonymous memory (swap),交换分区支持,也就是虚拟内存支持,嵌入式不需要。 [*]System V IPC,为进程提供通信机制,这将使系统中各进程间有交换信息与保持同步的能力。有些程序只有在选Y的情况下才能运行,所以不用考虑,这里一定要选。 [*]POSIX Message Queues,这是POSIX的消息队列,它同样是一种IPC(进程间通讯)。建议你最好将它选上。 [*]BSD Process Accounting,允许进程访问内核,将账户信息写入文件中,主要包括进程的创建时间/创建者/内存占用等信息。可以选上,无所谓。 [*]BSD Process Accounting version 3 file format,选用的话统计信息将会以新的格式(V3)写入,注意这个格式和以前的v0/v1/v2 格式不兼容,选不选无所谓。 [ ]Export task/process statistics through netlink (EXPERIMENTAL),通过通用的网络输出工作/进程的相应数据,和BSD不同的是,这些数据在进程运行的时候就可以通过相关命令访问。和BSD类似,数据将在进程结束时送入用户空间。如果不清楚,选N(实验阶段功能,下同)。 [ ]Auditing support,审计功能,某些内核模块需要它(SELINUX),如果不知道,不用选。 [ ]RCU Subsystem,一个高性能的锁机制RCU 子系统,不懂不了解,按默认就行。 [ ]Kernel .config support,将.config配置信息保存在内核中,选上它及它的子项使得其它用户能从/proc/ config.gz中得到内核的配置,选上,重新配置内核时可以利用已有配置Enable access to .config through /proc/config.gz,上一项的子项,可以通过/proc/ config.gz访问.config配置,上一个选的话,建议选上。 (16)Kernel log buffer size (16 => 64KB, 17 => 128KB) ,内核日志缓存的大小,使用默认值即可。12 => 4 KB,13 => 8 KB,14 => 16 KB单处理器,15 => 32 KB多处理器,16 => 64 KB,17 => 128 KB。 [ ]Control Group support(有子项),使用默认即可,不清楚可以不选。 Example debug cgroup subsystem,cgroup子系统调试例子 Namespace cgroup subsystem,cgroup子系统命名空间 Device controller for cgroups,cgroups设备控制器

linux用户态和内核态的转换

linux用户态和内核态的转换 原文链接:https://www.360docs.net/doc/8217119583.html,/question/363231653.html 当一个任务(进程)执行系统调用而执行内核代码时,称进程处于内核内核态,此时处理器处于特权级最高的(0级)内核代码中执行,当进程处于内核态时,执行的内核代码会使用当前进程的内核栈,每个进程都有自己的内核栈。当进程执行用户代码时,称其处于用户态,此时处理器在特权级最低的(3级)用户代码中运行。 当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态,因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。内核态与用户态是操作系统的两种运行级别,跟intel cpu没有必然的联系,intel cpu提供Ring0-Ring3三种级别的运行模式,Ring0级别最高,Ring3最低。 Linux使用了Ring3级别运行用户态,Ring0作为内核态,没有使用Ring1和Ring2。Ring3状态不能访问Ring0的地址空间,包括代码和数据。Linux进程的4GB地址空间,3G-4G部分大家是共享的,是内核态的地址空间,这里存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。用户运行一个程序,该程序所创建的进程开始是运行在用户态的,如果要执行文件操作,网络数据发送等操作,必须通过write,send等系统调用,这些系统调用会调用内核中的代码来完成操作,这时,必须切换到Ring0,然后进入3GB-4GB中的内核地址空间去执行这些代码完成操作,完成后,切换回Ring3,回到用户态。这样,用户态的程序就不能随意操作内核地址空间,具有一定的安全保护作用。 保护模式,通过内存页表操作等机制,保证进程间的地址空间不会互相冲突,一个进程的操作不会修改另一个进程的地址空间中的数据。在内核态下,CPU可执行任何指令,在用户态下CPU只能执行非特权指令。当CPU处于内核态,可以随意进入用户态;而当CPU处于用户态,只能通过中断的方式进入内核态。一般程序一开始都是运行于用户态,当程序需要使用系统资源时,就必须通过调用软中断进入内核态. 使用nm查看用户态程序的符号表内容 使用System.map(内核符号表)查看内核符号表内容 1. 测试程序中打印用户态函数地址,并调用系统调用(在内核中打印系统调用函数地址),用"用户态符号表"和"内核态符号表"示例说明内核态和用户态地址空间的差异 2. 说明内核态地址映射ioremap();用户态地址映射mmap()

基于ARM的嵌入式linux内核的裁剪与移植.

基于ARM的嵌入式linux内核的裁剪与 移植 0引言微处理器的产生为价格低廉、结构小巧的CPU和外设的连接提供了稳定可靠的硬件架构,这样,限制嵌入式系统发展的瓶颈就突出表现在了软件方面。尽管从八十年代末开始,已经陆续出现了一些嵌入式操作系统(比较著名的有Vxwork、pSOS、Neculeus和WindowsCE)。但这些专用操作系统都是商业化产品,其高昂的价格使许多低端产品的小公司望而却步;而且,源代码封闭性也大大限制了开发者的积极性。而Linux的开放性,使得许多人都认为Linu 0 引言 微处理器的产生为价格低廉、结构小巧的CPU和外设的连接提供了稳定可靠的硬件架构,这样,限制嵌入式系统发展的瓶颈就突出表现在了软件方面。尽管从八十年代末开始,已经陆续出现了一些嵌入式操作系统(比较著名的有Vxwork、pSOS、Nec uleus和Windows CE)。但这些专用操作系统都是商业化产品,其高昂的价格使许多低端产品的小公司望而却步;而且,源代码封闭性也大大限制了开发者的积极性。而Linux的开放性,使得许多人都认为Linux 非常适合多数Intemet设备。Linux操作系统可以支持不同的设备和不同的配置。Linux对厂商不偏不倚,而且成本极低,因而很快成为用于各种设备的操作系统。嵌入式linux是大势所趋,其巨大的市场潜力与酝酿的无限商机必然会吸引众多的厂商进入这一领域。 1 嵌入式linux操作系统 Linux为嵌入操作系统提供了一个极有吸引力的选择,它是个和Unix 相似、以核心为基础、全内存保护、多任务、多进程的操作系统。可以支持广泛的计算机硬件,包括X86、Alpha、Sparc、MIPS、PPC、ARM、NEC、MOTOROLA 等现有的大部分芯片。Linux的程序源码全部公开,任何人都可以根据自己的需要裁剪内核,以适应自己的系统。文章以将linux移植到ARM920T内核的 s3c2410处理器芯片为例,介绍了嵌入式linux内核的裁剪以及移植过程,文中介绍的基本原理与方法技巧也可用于其它芯片。 2 内核移植过程 2.1 建立交叉编译环境 交叉编译的任务主要是在一个平台上生成可以在另一个平台上执行的程序代码。不同的CPU需要有不同的编译器,交叉编译如同翻译一样,它可以把相同的程序代码翻译成不同的CPU对应语言。 交叉编译器完整的安装涉及到多个软件安装,最重要的有binutils、gcc、glibc三个。其中,binutils主要用于生成一些辅助工具;gcc则用来生成交叉编译器,主要生成arm—linux—gcc交叉编译工具;glibc主要是提供用户程序所使用的一些基本的函数库。 自行搭建交叉编译环境通常比较复杂,而且很容易出错。本文使用的是

相关文档
最新文档