• tools/build.c


    /*
     *  linux/tools/build.c
     *
     *  Copyright (C) 1991, 1992  Linus Torvalds
     */

    /*
     * This file builds a disk-image from three different files:
     *
     * - bootsect: max 510 bytes of 8086 machine code, loads the rest
     * - setup: max 4 sectors of 8086 machine code, sets up system parm
     * - system: 80386 code for actual system
     *
     * It does some checking that all files are of the correct type, and
     * just writes the result to stdout, removing headers and padding to
     * the right amount. It also writes some system data to stderr.
     */

    /*
     * Changes by tytso to allow root device specification
     */

    #include <stdio.h>    /* fprintf */
    #include <string.h>
    #include <stdlib.h>    /* contains exit */
    #include <sys/types.h>    /* unistd.h needs this */
    #include <sys/stat.h>
    #include <sys/sysmacros.h>
    #include <unistd.h>    /* contains read/write */
    #include <fcntl.h>
    #include <linux/config.h>
    #include <linux/a.out.h>

    #define MINIX_HEADER 32
    #define GCC_HEADER 1024

    #define SYS_SIZE DEF_SYSSIZE

    #define DEFAULT_MAJOR_ROOT 0
    #define DEFAULT_MINOR_ROOT 0

    /* max nr of sectors of setup: don't change unless you also change
     * bootsect etc */
    #define SETUP_SECTS 4

    #define STRINGIFY(x) #x

    //联合
    typedef union {
        long l;
        short s[2];
        char b[4];
    } conv;

    //定义long数据类型
    long intel_long(long l)
    {
        conv t;

        t.b[0] = l & 0xff; l >>= 8;
        t.b[1] = l & 0xff; l >>= 8;
        t.b[2] = l & 0xff; l >>= 8;
        t.b[3] = l & 0xff; l >>= 8;
        return t.l;
    }

    //定义short类型
    short intel_short(short l)
    {
        conv t;

        t.b[0] = l & 0xff; l >>= 8;
        t.b[1] = l & 0xff; l >>= 8;
        return t.s[0];
    }

    //程序异常结束
    void die(char * str)
    {
        fprintf(stderr,"%s ",str);
        exit(1);
    }

    //用法,build程序将bootsect setup system三部分和根设备名生成映像文件
    void usage(void)
    {
        die("Usage: build bootsect setup system [rootdev] [> image]");
    }

    //主函数
    int main(int argc, char ** argv)
    {
        int i,c,id, sz;
        //系统长度
        unsigned long sys_size;
        //定义缓冲区长度
        char buf[1024];
        //定义可执行文件结构指针,将缓冲区转化为可执行结构
        struct exec *ex = (struct exec *)buf;
        //主从根设备
        char major_root, minor_root;
        //文件状态
        struct stat sb;

        //如果输入参数个数不是4或者5,则显示用法信息
        if ((argc < 4) || (argc > 5))
            usage();
        //如果参数个数是5个,即带有根设备文件名
        if (argc > 4) {
            //此时输入参数是5个,比较第五个参数是否为CURRENT
            if (!strcmp(argv[4], "CURRENT")) {
                if (stat("/", &sb)) {
                    perror("/");
                    die("Couldn't stat /");
                }
                major_root = major(sb.st_dev);
                minor_root = minor(sb.st_dev);
            } else if (strcmp(argv[4], "FLOPPY")) {//比较第五个参数是否为FLOPPY,即软盘
                if (stat(argv[4], &sb)) {
                    perror(argv[4]);
                    die("Couldn't stat root device.");
                }
                major_root = major(sb.st_rdev);
                minor_root = minor(sb.st_rdev);
            } else {
                major_root = 0;
                minor_root = 0;
            }
        } else {//输入参数是四个,即没有指定根设备,则此处使用默认的根设备
            major_root = DEFAULT_MAJOR_ROOT;
            minor_root = DEFAULT_MINOR_ROOT;
        }
        //输出主从根设备号
        fprintf(stderr, "Root device is (%d, %d) ", major_root, minor_root);
        //初始化buff
        for (i=0;i<sizeof buf; i++) buf[i]=0;
        //打开bootsect,如果出错,则中断程序
        if ((id=open(argv[1],O_RDONLY,0))<0)
            die("Unable to open 'boot'");
        //读取文件头,且该文件头应该是MINIX文件头,长度为32,如果出错,则中断程序
        if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
            die("Unable to read header of 'boot'");
        //前四个字节应该为0x04100301
        if (((long *) buf)[0]!=intel_long(0x04100301))
            die("Non-Minix header of 'boot'");
        //判断头部长度是否为32,四个字节中后面三个为0
        if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
            die("Non-Minix header of 'boot'");
        //数据段长度是否为0
        if (((long *) buf)[3] != 0)
            die("Illegal data segment in 'boot'");
        //bss段是否为0
        if (((long *) buf)[4] != 0)
            die("Illegal bss in 'boot'");
        //判断执行点处是否为0
        if (((long *) buf)[5] != 0)
            die("Non-Minix header of 'boot'");
        //判断符号表长度是否为0
        if (((long *) buf)[7] != 0)
            die("Illegal symbol table in 'boot'");
        //读取数据,返回的长度i应该为512
        i=read(id,buf,sizeof buf);
        //输出boot sector长度
        fprintf(stderr,"Boot sector %d bytes. ",i);
        //如果实际读取的长度不是512,则报错,退出
        if (i != 512)
            die("Boot block must be exactly 512 bytes");
        //最后两字节如果不是启动扇区标志0x55AA则报错,退出
        if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55))
            die("Boot block hasn't got boot flag (0xAA55)");
        //将主从设备号写入引导块
        buf[508] = (char) minor_root;
        buf[509] = (char) major_root;    
        //将所读取的512字节写入标准输出
        i=write(1,buf,512);
        //校验写入数据的长度
        if (i!=512)
            die("Write call failed");
        //关闭文件。完成bootsect文件的处理工作
        close (id);
        
        //打开第二个参数指定的文件setup,出错则退出
        if ((id=open(argv[2],O_RDONLY,0))<0)
            die("Unable to open 'setup'");
        //读取MINIX文件头,长度应为32
        if (read(id,buf,MINIX_HEADER) != MINIX_HEADER)
            die("Unable to read header of 'setup'");
        //校验文件头魔数
        if (((long *) buf)[0]!=intel_long(0x04100301))
            die("Non-Minix header of 'setup'");
        //校验文件头长度
        if (((long *) buf)[1]!=intel_long(MINIX_HEADER))
            die("Non-Minix header of 'setup'");
        //判断数据段的长度是否为0
        if (((long *) buf)[3] != 0)
            die("Illegal data segment in 'setup'");
        //判断bss段的长度是否为0
        if (((long *) buf)[4] != 0)
            die("Illegal bss in 'setup'");
        //判断执行点处是否为0
        if (((long *) buf)[5] != 0)
            die("Non-Minix header of 'setup'");
        //判断符号表的长度是否为0
        if (((long *) buf)[7] != 0)
            die("Illegal symbol table in 'setup'");
        //每次读取1024字节,并将读取的数据写入标准输出
        for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c )
            if (write(1,buf,c)!=c)
                die("Write call failed");
        //最后一次操作长度是否为0
        if (c != 0)
            die("read-error on 'setup'");
        //以上都没有问题,则关闭文件
        close (id);
        //校验setup程序的长度
        if (i > SETUP_SECTS*512)
            die("Setup exceeds " STRINGIFY(SETUP_SECTS)
                " sectors - rewrite build/boot/setup");
        //输出setup的长度
        fprintf(stderr,"Setup is %d bytes. ",i);
        //缓冲区清零
        for (c=0 ; c<sizeof(buf) ; c++)
            buf[c] = '';
        //如果setup程序长度小于SETUP_SECTS*512
        while (i<SETUP_SECTS*512) {
            //剩余空间填,补足SETUP_SECTS*512
            c = SETUP_SECTS*512-i;
            if (c > sizeof(buf))
                c = sizeof(buf);
            if (write(1,buf,c) != c)
                die("Write call failed");
            i += c;
        }
        
        //打开system文件
        if ((id=open(argv[3],O_RDONLY,0))<0)
            die("Unable to open 'system'");
        //读取文件头,该文件头为GCC_HEADER
        if (read(id,buf,GCC_HEADER) != GCC_HEADER)
            die("Unable to read header of 'system'");
        //此时ex指向该文件头,校验文件头魔数
        if (N_MAGIC(*ex) != ZMAGIC)
            die("Non-GCC header of 'system'");
        //输出所system文件长度、代码段长度、数据段长度和bss段长度
        fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss) ",
            (ex->a_text+ex->a_data+ex->a_bss)/1024,
            ex->a_text /1024,
            ex->a_data /1024,
            ex->a_bss  /1024);
        //
        sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
        sys_size = (sz + 15) / 16;
        //校验system的长度
        if (sys_size > SYS_SIZE)
            die("System is too big");
        //每次读取1024个字节长度,然后写入标准输出中
        //最后一次是实际长度
        while (sz > 0) {
            int l, n;

            l = sz;
            if (l > sizeof(buf))
                l = sizeof(buf);
            if ((n=read(id, buf, l)) != l) {
                if (n == -1)
                    perror(argv[1]);
                else
                    fprintf(stderr, "Unexpected EOF ");
                die("Can't read 'system'");
            }
            if (write(1, buf, l) != l)
                die("Write failed");
            sz -= l;
        }
        //关闭文件
        close(id);
        //从标准输出中从开始搜索偏移为500字节处
        if (lseek(1,500,0) == 500) {
            //如果可以搜索到
            //在buff[0]和buff[1]出写入system的长度
            buf[0] = (sys_size & 0xff);
            buf[1] = ((sys_size >> 8) & 0xff);
            if (write(1, buf, 2) != 2)
                die("Write failed");
        }
        return(0);
    }
    //本文件的主要功能是将编译产生的三个文件bootsect、setup和system是三个文件写入一个映像文件中
    //前面两个文件时MINIX文件,后面是一个GCC文件,写入标准输出时需要校验文件格式

  • 相关阅读:
    入门菜鸟
    FZU 1202
    XMU 1246
    Codeforces 294E Shaass the Great 树形dp
    Codeforces 773D Perishable Roads 最短路 (看题解)
    Codeforces 814E An unavoidable detour for home dp
    Codeforces 567E President and Roads 最短路 + tarjan求桥
    Codeforces 567F Mausoleum dp
    Codeforces 908G New Year and Original Order 数位dp
    Codeforces 813D Two Melodies dp
  • 原文地址:https://www.cnblogs.com/xiaofengwei/p/3753327.html
Copyright © 2020-2023  润新知