/*
 *  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\n",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)\n", 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.\n",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.\n",i);
    //缓冲区清零
    for (c=0 ; c<sizeof(buf) ; c++)
        buf[c] = '\0';
    //如果setup程序长度小于SETUP_SECTS*512
    while (i<SETUP_SECTS*512) {
        //剩余空间填\0,补足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)\n",
        (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\n");
            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文件,写入标准输出时需要校验文件格式

tools/build.c的更多相关文章

  1. 解决 Could not find com.android.tools.build:gradle 问题

    今天拉同事最新的代码,编译时老是报如下错误: Error:Could not find com.android.tools.build:gradle:2.2.0.Searched in the fol ...

  2. Could not find com.android.tools.build:gradle:1.3.0.

    * What went wrong:          A problem occurred configuring project ':TZYJ_Android'.> Could not re ...

  3. Failed to apply plugin [id 'com.android.application'] 和 Could not find com.android.tools.build:gradle:2.XX的最正确的解决方法

    发现android studio是真的可爱啊,上一秒还没问题可以build运行,下一秒就出错...好,你任性,你牛逼.. 说下今天又遇到的两个问题:Failed to apply plugin [id ...

  4. bash: ./device/nexell/tools/build.sh: 权限不够

    /bin/bash: build/tools/diff_package_overlays.py: 鏉冮檺涓嶅 i686-linux-gcc: error trying to exec 'cc1': ...

  5. Could not find com.android.tools.build:aapt2:3.2.1-4818971.

    Could not find com.android.tools.build:aapt2:-. Searched in the following locations: file:/H:/Androi ...

  6. 解决 Could not resolve com.android.tools.build:gradle:3.1.3

      android studio 升级到3.1.3后总会遇到莫名其妙的错误,前几天刚解决了项目 dependencies报错的问题. 解决android studio 升级到3.0+之后 项目 dep ...

  7. GET 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.1.2/gradle-3

    Could not GET 'https://dl.google.com/dl/android/maven2/com/android/tools/build/gradle/3.1.2/gradle-3 ...

  8. Error:Could not find com.android.tools.build:gradle:3.0.0

    Error:Could not find com.android.tools.build:gradle:3.0.Searched in the following locations:    file ...

  9. Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法

    ref from: Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法http://blog ...

随机推荐

  1. IT公司100题-14-排序数组中和为给定值的两个数字

    问题描述: 输入一个升序排序的数组,给定一个目标值target,求数组的两个数a和b,a+b=target.如果有多个组合满足这个条件,输出任意一对即可. 例如,输入升序数组[1, 3, 4, 5, ...

  2. Linux-Gcc生成和使用静态库和动态库详解

    一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...

  3. Hibernate对象映射类型

    Hibernate understands both the Java and JDBC representations of application data. The ability to rea ...

  4. Spring学习笔记之BeanFactory

    Spring bean container 的根接口,也是一个bean容器的基本功能,更深一步的接口像ListableBeanFactory 和 ConfigurableBeanFactory 都是 ...

  5. Android 时间戳的转换

    在Android应用中,经常会碰到后台的时间是时间戳而现实的需要今天什么时候,昨天什么时候,就像微博的时间显示一样.现在我上一个把时间戳转换的代码: public static String getT ...

  6. android Xutils dbutils 注解

    xUtils DbUtils 关于实体类注解 汇总 RockyZhang 发布于 1年前,共有 0 条评论 先来官方demo DbUtils db = DbUtils.create(this);    ...

  7. ubuntu安装多个qt版本--不同qt版本编译同一个程序时出现错误--解决方案

    方法: 在ubuntu终端: # make clean   //有Makefile文件的情况 # rm Makefile *.pro.user # qmake  //有多个qt版本,最好指定qmake ...

  8. poj1651 区间dp

    //Accepted 200 KB 0 ms //dp区间 //dp[i][j]=min(dp[i][k]+dp[k][j]+a[i]*a[k]*a[j]) i<k<j #include ...

  9. JS中关于 一个关于计时器功能效果的实现

    optionSearch(); function optionSearch() { //定义一个清除计时器的变量 var timer = null; //自选标题区域 $("#optiona ...

  10. Reachability判断网络是否连接

    类似于一个网络状况的探针. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(reachabili ...