linux的启动配置文件(grub)

时间:2021-01-25 04:39:00

linux的启动配置文件(grub):

GRUB:系统引导管理器。GRUB启动时会在 /boot/grub 中寻找一个名字为grub.conf的设置文件,如果找不到此设置文件则不进入菜单模式而直接进入命令行模式。
    grub.conf是一个纯文字文件,您可以用任何一个文字编辑器来打开它。每一行代表一个设置命令,如果一行的第一个字符为井号#,则这一行为注释,您可以简单地用增加或减少注释行来改变设置。

用vi打开grub.conf,内容如下:
default=0
timeout=10
splashimage=(hd0,6)/grub/splash.xpm.gz
title Red Hat Linux (2.4.20-8)
        root (hd0,0)
        kernel /vmlinuz-2.4.20-8 ro root=LABEL=/
        initrd /initrd-2.4.20-8.img

timeout second
设置在second秒之后引导默认的操作系统。
Linux 默认是timeout 10,也就是说10秒之内如果没有其他命令就启动系统。如果设成 -1,则 GRUB 会一直等待直到用户选择一个选项为止。
default num
默认启动第 num +1行选项,也就说default=0,则默认启动菜单第1行的操作系统,default=1,则启动第2行的系统,如此类推。
splashimage指定了开机画面文件splash.xpm.gz的位置.

title: 定义启动菜单项的名称
root: 设置 Grub 的根设备 (root)为 Linux 内核所在分区
hd0是指第一个硬盘(主硬盘),(hd0,0)是指第一个硬盘的第一个分区。
kernel: 后跟 Linux 内核文件为参数, 加载 Linux 内核文件
kernel /vmlinuz是指出Linux内核的路径在/vmlinuz中。
initrd: 加载镜像文件

如果自己重新编译了内核,可把这个内核加载到grub,开机时可以选择运行哪个内核。(把这段加在原有内容的后面,想启动几个就加几个)
如:title Linux (2.4.18)
        root (hd0,0)
        kernel /bzImage ro root=/dev/hda2
        initrd /initrd-2.4.20-8.img
改一下启动菜单的名称,把编译好的内核bImage挂载到/dev/hda2
如果硬盘用的是scsi的,挂载到/dev/sda2,在make menuconfig时,以下选项必选:
Device Drivers  --->SCSI device support  ---><*>   SCSI disk support
Device Drivers  --->SCSI device support  --->SCSI low-level drivers  ---> <*> BusLogic SCSI support

Open()
头文件: #include<fcntl.h>
定义函数 int open( const char * pathname, int flags);
int open( const char * pathname,int flags, mode_t mode);
Open()和 C 中的fopen相似,定义int fd;fd=open(“filename”,打开方式);
返回值:此函数调用成功后(所有欲核查的权限都通过了检查)将返回所打开的文件的文件描述符(int类型),表示成功,如果调用失败,或只要有一个权限被禁止则返回-1。
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以可读写方式打开文件。上述三种是互斥的,也就是不可同时使用,但可与下列的利用OR(|)运算符组合。
O_CREAT 若欲打开的文件不存在则自动建立该文件。
O_EXCL 如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败。
O_NOCTTY 如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机。
O_TRUNC 若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失。
O_APPEND 当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面。
O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
O_NDELAY 同O_NONBLOCK。
O_SYNC 以同步的方式打开文件。
O_NOFOLLOW 如果参数pathname 所指的文件为一符号连接,则会令打开文件失败。
O_DIRECTORY 如果参数pathname 所指的文件并非为一目录,则会令打开文件失败。

Read()
头文件: #include<unistd.h>
定义函数 ssize_t read(int fd,void * buf ,size_t count);
函数说明 read()会把参数fd 所指的文件传送count个字节到buf指针所指的内存中。若参数count为0,则read()不会有作用并返回0。返回值为实际读取到的字节数,如果返回0,表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动。

附加说明 如果顺利read()会返回实际读到的字节数,最好能将返回值与参数count 作比较,若返回的字节数比要求读取的字节数少,则有可能读到了文件尾、从管道(pipe)或终端机读取,或者是read()被信号中断了读取动作。当有错误发生时则返回-1,错误代码存入errno中,而文件读写位置则无法预期。

文件描述符:
     任何打开的文件都将被分配一个唯一标识该打开文件夹的文件描述符(也称文件句柄),为一个大于等于0的整数。系统启动后,默认打开的文件流有标准输入设备(STDIN)、标准输出设备(STDOUT)和标准错误输出设备(STDERR),其文件描述符分别为0、1、2。以后打开的文件的文件描述符分配依次增加。
     内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。


系统调用:
在Linux中,为了更好地保护内核,把程序运行空间分为内核空间和用户空间,它们分别运行在不同的级别上,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数。但是在有些情况下,用户空间的进程需要获得一定的系统服务,这时,就必须通过系统调用。
系统调用是指操作系统提供给用户程序调用的一组“特殊”接口,用户程序可以通过这组接口获得操作系统内核提供的服务。从逻辑上来说,系统调用可被看成是一个内核与用户空间程序交互的接口——它好比一个中间人,把用户进程的请求传达给内核,待内核把请求处理完毕后再将处理结果送回给用户空间。

系统调用、用户编程接口(API)、系统命令、和内核函数的关系
系统调用并非直接和程序员或系统管理员打交道,它仅仅是一个通过软中断机制向内核提交请求,获取内核服务的接口。而在实际使用中程序员调用的多是用户编程接口——API,而管理员使用的则多是系统命令。
用户编程接口其实是一个函数定义,说明了如何获得一个给定的服务,比如read()、malloc()、free()、abs()等。这些系统调用编程接口主要是通过C库(libc)实现的。
系统命令相对编程接口更高了一层,它是内部引用API的可执行程序,比如我们常用的系统命令ls等。
内核函数和系统调用的关系,内核函数不要想像的过于复杂,其实它们和普通函数很像,只不过在内核实现,因此要满足一些内核编程的要求。系统调用是一层用户进入内核的接口,它本身并非内核函数,进入内核后,不同的系统调用会找到对应到各自的内核函数——换个专业说法就叫:系统调用服务服务例程。实际对请求服务的是内核函数而非调用接口。
总而言之,从用户角度向内核看,依次是系统命令、编程接口、系统调用和内核函数。
系统调用通常通过函数进行调用,通常,用一个负的返回值来表明错误,返回一个0值表明成功.

系统调用号:
在Linux中,每个系统调用被赋予一个全局唯一的系统调用号.用户空间进程执行一个系统调用的时候,这个系统调用号就被用来指明到底要执行哪个系统调用;进程不会提及系统调用的名称.
系统调用号相当关键,一旦分配就不能再有任何变更,否则编译好的应用程序就会崩溃.此外,如果一个系统调用被删除,它所占用的系统调用号也不允许被回收利用.
应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,希望系统切换到内核态,这样内核就可以代表应用程序来执行该系统调用了.
文件include/asm/unisted.h为每个系统调用规定了唯一的编号。假设用name表示系统调用的名称,那么系统调用号与系统调用响应函数的关系是:以系统调用号_NR_name作为下标,可找出系统调用表sys_call_table(见arch/i386/kernel/entry.S)中对应表项的内容,它正好 是该系统调用的响应函数sys_name的入口地址。系统调 用表sys_call_table记录了各sys_name函数在表中的位 置。有了这张表,就很容易根据特定系统调用 在表中的偏移量,找到对应的系统调用响应函数的入口地址。系统调用表共2XX项,余下的项是可供用户自己添加的系统调用空间。

1.编写一个系统调用函数,把它加到内核中,函数名以 sys_ 开头,后跟该系统调用名。如新加系统调用为foo(),在/linux/kernel/sys.c中添加源代码:
asmlinkage int sys_foo(int x)
{
        printk(“%d\n”,x);  //注意这是在内核下的,用printk
}
2. 连接新的系统调用
1).inculde/asm/unistd.h在这个文件中加入
#define_NR_foo 238   (因为原列表结尾是237,所以在后面加)

2).are/i386/kernel/entry.S这个文件用来对指针数组初始化,在这个文件中增加一行:
.long SYMBOL_NAME(_sys_foo)
3.重新编译内核
    为了使新的系统调用生效,需要重建Linux内核,以root身份在linux文件夹下编译内核:
    make menuconfig  //配置内核,在File system下选中ext3文件系统支持
    make clean       //清除以前编译的中间文件
    make dep         //读取配置文件,创建依赖关系树
    make bzImage     //编译内核
4.装载内核,将/linux/arch/i386/boot/bzImage复制到/boot下
  修改grub.conf(请看linux启动配置文件)
  重启系统,在启动介面上,可以选择刚才编译的那个内核进入。
5.编写测试程序
#include <stdio.h>
#include "/home/xgc/linux/include/asm-i386/unistd.h"
int errno;
_syscall1(char *, foo, int, ret)
int main()
{
        int i;
        i = 100;
        printf("This is the result of new kernel\n");
        foo(i);
        return 0;
}
在字符介面运行可得到结果:100
宏定义_syscallN()见include/asm/unisted.h)用于系统调用的格式转换和参数的传递。N取0~5之间的整数。 参数个数为N的系统调用由_syscallN()负责格式转换和参数传递。在这里使用了_syscall1()宏指令,宏指令本身在程序中将扩展成名为syscall()的函数,它在main()函数内部加以调用。