GVKun编程网logo

Linux Lab 项目启动 6 年后,终于发布了 v1.0 正式版(linux-lab)

2

此处将为大家介绍关于LinuxLab项目启动6年后,终于发布了v1.0正式版的详细内容,并且为您解答有关linux-lab的相关问题,此外,我们还将为您介绍关于01、开源游戏-“胡子”项目启动、Che

此处将为大家介绍关于Linux Lab 项目启动 6 年后,终于发布了 v1.0 正式版的详细内容,并且为您解答有关linux-lab的相关问题,此外,我们还将为您介绍关于01、开源游戏-“胡子”项目启动、Cherokee 终于发布了 1.0 版本、CSAPP Lab:Bomb Lab——从拆弹到爆炸。。。、CSAPP Lab:Shell Lab——理解进程控制的秘密的有用信息。

本文目录一览:

Linux Lab 项目启动 6 年后,终于发布了 v1.0 正式版(linux-lab)

Linux Lab 项目启动 6 年后,终于发布了 v1.0 正式版(linux-lab)

简介

自 Linux Lab v0.9 发布以后,又经过了 5 个月的漫长迭代,Linux Lab 终于迎来了 v1.0 正式版,同时也迎来了 Cloud Lab v0.80-rc1 版本,两者需同步升级配合使用。

  • 发布仓库

    • Gitee: https://gitee.com/tinylab/linux-lab

    • Github: https://github.com/tinyclub/linux-lab

  • 用户手册

    • Linux Lab v1.0 中文手册

    • Linux Lab v1.0 英文手册

更新情况

Linux Lab v1.0 升级了部分内核版本到 v5.17,修复了多处内存编译 Bug,优化了 make 命令自动补全功能,并重点完善和新增了 examples,同时更新文档对齐到最新的功能。

  • v1.0 rc3

    • 全面整理 Assembly 实验案例

    • 删除多余的 do target,由其他更简洁的用法替代

    • 允许更简单编译内核目标文件,例如:make kernel arch/riscv/kernel/sbi.o

    • 修复 make 自动命令补全,允许通过 tab 按键快速补全常用命令

    • 完善 make patch 命令

    • 更新文档和 License 信息

  • v1.0 rc2

    • 升级 RISC-V 支持,qemu 升级到 v6.0.0,内核升级到 v5.17

    • 升级 arm/vexpress-a9 的默认内核到 v5.17

    • 规范 build 输出路径,跟 boards/ 下的路径保持一致,方便更快找到目标文件

    • 完善 docker 文件系统运行和导出支持

    • 新增 Python 实验案例

    • 完善 Assembly 和 Shell 实验案例

  • v1.0 rc1

    • 增强 test 功能,允许在 testcase 中执行多个命令

    • 修复 test 中的内核参数传递问题,确保兼容 uboot 和 kernel

    • 允许灵活增加 app 的子 make 目标,例如 make root busybox-menuconfig

    • 修复两笔内存编译的问题

项目感想

历史回顾

Linux Lab v1.0 是一个很重要的里程碑,不仅意味着其核心功能已经非常稳定和完善,也意味着我们的工作重心将发生调整。在 v1.0 之后,我们将把重点调整到 examples 的开发上,将通过 examples 帮助更多的同学更高效地学习、研究和开发操作系统以及周边的技术。

刚刚查看了第一笔提交记录:

Author: Wu Zhangjin wuzhangjin@gmail.com
Date: Mon Jul 11 09:06:04 2016 +0800

Init linux-lab

Aims to build a Qemu-based Linux Lab to easier the Linux Learning and new features development.

Signed-off-by: Wu Zhangjin wuzhangjin@gmail.com

非常令人感慨,六年前肯定想不到,今天的 Linux Lab v1.0 已经支持了市面上所有的主流处理器架构,支持了 20 多款开发板,支持了从 v0.11 到 v5.x 的几乎所有 Linux 内核版本,加 Cloud Lab 在内,一共有 3294 笔变更,每一笔背后都是煞费苦心的设计和思考以及大量繁琐的验证和测试。

$ cd cloud-lab/labs/linux-lab
$ git log --oneline --root | wc -l
2152

$ cd ../../
$ git log --oneline --root | wc -l
1142

我想说,这份努力是值得的,作为计算机软件中偏底层最接近硬件最复杂的操作系统,向来是相对比较难上手的,最大的门槛是重复又依赖繁多的环境构建,但是有了 Linux Lab,继而有了 Linux Lab Disk,我们可以在 1 分钟内进入实验环境,在 10 分钟内编译并启动 Linux 内核,Linux 内核与嵌入式 Linux 开发从未像今天这般简单。

期待我们的工作对操作系统的人才培养、技术孵化、开发效率等方面都有所助力!

感谢致谢

感谢六年来,所有参与、支持和鼓励过这个项目的同学们!没有你们的支持,这个项目也许早就夭折了;没有你们的支持,我们不会有动力不厌其烦地去完善和迭代,那些 Bug Report,Patch,赞誉背后的支持让所有的开发不再孤立无援,而是温暖充盈。

也要特别感谢这个项目用到的所有开源项目,包括但是不限于:Ubuntu, Linux, Docker, Qemu, Buildroot, U-Boot, Busybox, Make, webvnc 等等,没有这些工作,就不可能有 Linux Lab。

同时感谢项目的托管平台:Github 和 Gitee,也要感谢曾经赞助过这个项目的企业、研究所和个人,包括购买过 Linux Lab Disk 以及社区所有其他付费服务的所有同学们!

另外,这六年来,家里的夫人和小伙伴也给了莫大的支持,这个项目牺牲了很多本应该陪伴他们的时间。随着 v1.0 版本的发布,希望后面能够有更多的时间陪伴他们。

商业化尝试

过去数年来,包括社区和项目在内,所有的开发和答疑都是公益性质的,是个人投入资金和时间在运营,虽然有获得了一些赞助,但是杯水车薪。

为了项目的持续健康发展,在经过艰难的考虑后,我们做了一些商业化尝试,希望大家能够多多支持。

  • Cloud Lab 和 Linux Lab 项目都采用双 Licenses,非商业用户采用 GPL v2 协议,商业用户需要获得商业授权。

  • 之前维护的开发板和内核版本数量巨大,答疑和维护已经令人精疲力尽,所以开发板部分,后续仅默认开放 arm/vexpress-a9,其他开发板将暂停开放并可根据需要付费购买服务。也欢迎其他企业、机构或个人联系赞助某个开发板或处理器架构,获得相应的资源后,社区将考虑重新开放对应的开发板或处理器架构。

  • 社区也研发了免安装即插即跑的 Linux Lab Disk,也叫泰晓 Linux 实验盘,插上即可开展 Linux 内核与嵌入式 Linux 开发,容量覆盖 32G-2T,支持智能启动、透明压缩、时区兼容、出厂恢复等新创特性,用户可根据需要选购。欢迎高校、企业和机构联系团购,泰晓 Linux 实验盘可用于高校计算机实验室、企业内部培训等。

更多资料

  • 使用 Linux Lab 的好处

    • Linux Lab:难以抗拒的十大理由 V1.0

    • Linux Lab:难以抗拒的十大理由 V2.0

  • Linux Lab 视频公开课:含用法介绍、使用案例分享、发布会视频回放、Linux Lab Disk功能演示等

    • CCTALK

    • B 站

    • 知乎

  • 采用 Linux Lab 作为实验环境的视频课程

    • 《360° 剖析 Linux ELF》

    • 《Rust 语言快速上手》

    • 《软件逆向工程初探》

    • 《Linux内核热补丁技术介绍与实战》

  • 采用 Linux Lab 或者 Linux Lab 正在支持的图书、课程等

    • 成功适配过 Linux Lab 的国内外图书、线上课程列表

  • 采用 Linux Lab 或者 Linux Lab 正在支持的真实硬件开发板

    • ARM IMX6ULL,野火电子

    • RISCV-64 D1, 平头哥

  • Linux Lab 社区正在开发的周边硬件

    • Linux Lab Disk,免安装、即插即用 Linux Lab 开发环境
      • 支持 Ubuntu 18.04-21.04, Deepin 20.2+, Fedora 34+, Mint 20.2+, Ezgo 14.04+, Kali, Manjaro

    • Pocket Linux Disk,免安装、即插即用 Linux 发行版
      • 支持 Ubuntu 18.04-21.04, Deepin 20.2+, Fedora 34+, Mint 20.2+, Ezgo 14.04+, Kali, Manjaro

 

01、开源游戏-“胡子”项目启动

01、开源游戏-“胡子”项目启动

如果你看过之前的文章,你就会明白我们什么这么写,如果你没看,也没必要解释了。

开源游戏“胡子”,今天正式开始设计。

“胡子”是一款以html5开发的一款即时战略游戏,即大家说的RTS,可以单人游戏和多人对战。

单人游戏时,故事情节为东北土匪的事。具体故事还在构思中。为什么叫“胡子”那,很简单,东北人把土匪叫“胡子”。我就是东北人

下一次我们写写怎么设计这个游戏。

Cherokee 终于发布了 1.0 版本

Cherokee 终于发布了 1.0 版本

Cherokee 号称是目前最快的 Web 服务器软件,在性能上,甚至比 Nginx 还略胜一筹。与 Apache、Lighttpd、Nginx 等其他同类软件的对比,大家不妨看看这个测试页面。其易用性做得也很不错。

该版本是 Cherokee 这个项目自创建以来的第一个完整的版本,完成了管理的接口和所有服务器的功能、音频视频流媒体模块、反向代理、FastCGI, SCGI, uWSGI 和 CGI 接口,兼容 Apache 的 htpasswd 和 htdigeest 的插件、日志文件、gzip 和 deflate 压缩支持、通过 MySQL 和 LDAP 的认证支持、DBSlayer 兼容数据库桥等等。

强烈建议升级。

下载  Cherokee 1.0

CSAPP Lab:Bomb Lab——从拆弹到爆炸。。。

CSAPP Lab:Bomb Lab——从拆弹到爆炸。。。

 

这个实验的要做的是用gdb逆向一段code,通过查看汇编代码以及单步调试找出这段code需要你填入的字符串,好像每个人都不一样,所以每个人都需要找到自己的拆弹密码,很有意思。

实验一共有6关,我们一关关来看一下:

phase_1

打开bomb.c看些c源码(这里的核心方法已经被删除了,只能看到最外层的代码,但能得到一些线索)。

很容易就发现这个phase_1方法是第一题的核心方法,直接逆向它,看下它的汇编。

第一句话是在为函数栈开辟空间,第二句话是关键,将一个立即数赋值给%esi,然后就调用strings not equal方法,推测很用可能这个寄存器中就存着我们拆弹的字符串,于是打断点,单步执行,查看%esi的里的内容:

没错,这就是我们拆弹的钥匙了,输入,第一个炸弹成功拆除!可以将答案放在一个文本文件中,方便之后的解题。

phase_2

 直接逆向phase_2函数观察下

 

观察read_six_numbers发现这次是要我们输入6个数字,通过观察后发现输入的6个数字会依次3存在%rsp,%rsp+4,%rsp+8,%rsp+12...%rsp+24这些位置,那么cmpl $0x1,(%rsp)这句话就很明显可以得出第一个数字是1,再接下去看跳转到52,将%rsp+4也就是第二个数字放进%rbx中,将%rbp设置成%rsp+24(可以猜到%rbp使用来判断循环是否退出的寄存器),之后跳转到27,这里将第一个数赋值给%eax,将%eax*2去和第一个数对比,如果相等就继续,以此类推,可以发现这个循环就是用来判断输入的数字是否依次增大一倍的,所以第二题的拆弹密码就是:1 2 4 8 16 32

phase_3

我首先随意输入一个字符串,调试发现%esi中的字符串内容为"%d %d",由此得知此题需要我们输入两个数字,%eax是scanf的返回值,如果=1则代表非法输入,炸弹爆炸。我们输入两个数字,这里跳转就能通过了。然后发现第一个数字不能大于7,我们随意填了个0,重新调试再试试,然后发现jmp到了57,走下去会发现%eax就是第二个数的答案,所以此题答案为0 0xcf。

其实这道题最简单的解法就是输入两个数,跟着单步调试走,你很容易就能确定两个数字的内容,但是其实你再多看两眼,就会发现其实这里是一个switch结构,答案是不唯一的,跳转表存在*0x402470中,我们打印出这张跳转表,就能得知这道题的所有答案:第一个数字是index,第二个数字就是对应分支赋值给%eax的值。

 phase_4

 这道题是个递归,花了点时间,但是复杂度还行,只要一步步跟下来就能得出结果。

拆弹关键在func4函数中,发现func4返回的参数eax必须为0才能不爆炸,我们倒退进func4

发现只有当%ecx和%edi的值相等的时候才会将%eax赋值为0,而%edi就是我们的第一个参数,那么我们只需要知道%ecx的值即可,通过推导得出ecx的值可以为7 3 0。

返回phase_4继续走下去发现第二个数为0就能拆弹了。

 

phase_5

通过这段我们可以知道这一题是要我们输入一串长度为6的字符串。

这一段是核心代码,跳转至112后将%eax赋值为0后跳转到41,然后讲%rbx+%rax的值赋值给%ecx,%rbx是我们输入内容的基地址,%rax是索引,然后做的事情其实就是将当前字符截取底4位。55行这里有个奇怪的地址,将这个地址输出看下得到:,那么这里就是以当前字符低4位的值为索引去读取这个字符串,然后得到的字符放进以$rsp+16为起始地址的内存区域。

解下来可以跳出循环看76-91行了,查看81行的字符串为"flyers",%rdi就是我们循环得到的字符串,然后调用string_not _equal方法,得知只要我们循环得出的字符串等于“flyers”即可拆弹。

分别找到“flyers”在上述字符串中的索引,然后对照ASCII码表,可得到本题答案,答案不唯一,只要低4位符合条件的字符都能拆弹。

phase_6

这题在借助谷歌的力量后才不太顺利的完成了。。

先看第一部分

这部分没有什么难度,但也有一定复杂度,稍微花点时间理一下逻辑,就能发现它是要我们输入6个数字,然后这6个数字要求互不相等,并且都不大于6。

接下来就比较困难了,没想到是用到了链表,而且还涉及到数据对齐的知识。

链表存储在0x6032d0中,链表得到后再进行排序,最后我们可以得到排序后的链表其实是单调递减了,然后反推就能得出我们的答案啦~

 

CSAPP Lab:Shell Lab——理解进程控制的秘密

CSAPP Lab:Shell Lab——理解进程控制的秘密

本次实验目的是完成一个简单的shell程序,解析命令行参数,理解并使用(fork,execve,waitpid)常见的多进程函数,了解linux进程组,以及前台进程和后台进程的相关概念,理解linux的信号机制(包括发送信号,接受信号,阻塞信号等)。实验提示以及详情请阅读CMU的实验指导:http://csapp.cs.cmu.edu/public/labs.html 。

我们要完成的shell并不是从0开始,实验本身已经帮你完成了一部分内容,并且提供一些工具函数,我们要做的是实现一下这几个核心函数:

eval: Main routine that parses and interprets the command line. [70 lines]

builtin_cmd: Recognizes and interprets the built-in commands: quit,fg,bg,and jobs. [25 lines]

dobgfg: Implements the bg and fg built-in commands. [50 lines]

waitfg: Waits for a foreground job to complete. [20 lines]

sigchld handler: Catches SIGCHILD signals. [80 lines]

sigint handler: Catches SIGINT (ctrl-c) signals. [15 lines]

sigtstp handler: Catches SIGTSTP (ctrl-z) signals. [15 lines]

eval

这是shell程序的核心函数,我们需要在这里完成以下几个事情:

1.调用parseline,生成argv以及判断是否是后台进程。

2.调用builtin_cmd判断是否是内建命令,如果是则已经在该方法中执行,shell直接返回,否则创建进程执行。

3.fork之前要注意屏蔽SIGHLD信号,否则有可能在addjob之前就调用deletejob造成竞争。

4.需要在fork后解锁SIGHLD的信号。

/* 
 * eval - Evaluate the command line that the user has just typed in
 * 
 * If the user has requested a built-in command (quit,jobs,bg or fg)
 * then execute it immediately. Otherwise,fork a child process and
 * run the job in the context of the child. If the job is running in
 * the foreground,wait for it to terminate and then return.  Note:
 * each child process must have a unique process group ID so that our
 * background children don‘t receive SIGINT (SIGTSTP) from the kernel
 * when we type ctrl-c (ctrl-z) at the keyboard.  
*/
void eval(char *cmdline) 
{
    char *argv[MAXARGS];
    char buf[MAXLINE];
    int isBg;
    pid_t pid;
    sigset_t mask;

    strcpy(buf,cmdline);
    isBg=parseline(buf,argv);
    if(argv[0]==NULL){
        return;
    }

    if(!builtin_cmd(argv)){
    //init mask
    sigemptyset(&mask);
    sigaddset(&mask,SIGCHLD);
    sigprocmask(SIG_BLOCK,&mask,NULL); //block SIGCHLD

        if((pid=fork())==0){
        sigprocmask(SIG_UNBLOCK,NULL); //unblock SIGCHLD
            if(execve(argv[0],argv,environ)<0){
                printf("%s:Command not found.\n",argv[0]);
                exit(0);
            }
        
        //set own pid as group pid
        setpgid(0,0);
        }

        if(!isBg){
            addjob(jobs,pid,FG,cmdline);
            waitfg(pid);

        }
    else{
            addjob(jobs,BG,cmdline);
        printf("%d %s",cmdline);
    }
        sigprocmask(SIG_UNBLOCK,NULL); //unblock SIGCHLD
    }
    

    return;
}

 

builtin_cmd

builtin_cmd做的事情比较简单,判断是否是内建命令,如果是,则直接执行并返回true,否则返回false。

/* 
 * builtin_cmd - If the user has typed a built-in command then execute
 *    it immediately.  
 */
int builtin_cmd(char **argv) 
{
    if(!strcmp(argv[0],"quit")||!strcmp(argv[0],"q")){
        exit(0);
    }
    if(!strcmp(argv[0],"jobs")){
        listjobs(jobs);
    return 1;
    }
    if(!strcmp(argv[0],"bg")||!strcmp(argv[0],"fg")){
    do_bgfg(argv);
    return 1;
    }
    return 0; 
}

dobgfg

这个方法还是比较复杂的,主要完成了bg和fg命令的操作,需要注意如下几点:

1.需要区分输入的是pid还是jid来调用不同函数。

2.通过发送SIGCONT来重启进程,发送对象需要为进程组。

3.不要忘记将后台进程改为前台进程后需要等待前台进程完成(调用waitfg)。

/* 
 * do_bgfg - Execute the builtin bg and fg commands
 */
void do_bgfg(char **argv) 
{
    struct job_t *job;
    char *id=argv[1];
    pid_t pid;

    if(id==NULL){
        printf("%s command requireds pid or %%jobid argument\n",argv[0]);
        return;
    }

    //process by jobid
    if(id[0]==%)
    {
        int jid = atoi(&id[1]);
        job=getjobjid(jobs,jid);
        if(job==NULL)
        {
            printf("%s:No such job\n",id);
            return;
        }
    }
    //process by pid
    else if(isdigit(id[0])){
    int pid = atoi(&id[1]);
    job = getjobpid(jobs,pid);
        if(job==NULL)
        {
            printf("%s:No such job\n",id);
            return;
        }    
    }
    else{
        printf("%s: argument must be a PID or %%jobid\n",argv[0]);
        return;
    }
    //send SIGCONT to restart
    kill(-(job->pid),SIGCONT);
    //set job status
    if(!strcmp(argv[0],"bg")){
        job->state = BG;
        printf("[%d] (%d) %s",job->jid,job->pid,job->cmdline);
    }else{
        job->state = FG;
        waitfg(job->pid);
    }


    return;
}

 

waitfg

没什么好说的,根据实验指导,这里直接使用忙等待来实现。

/* 
 * waitfg - Block until process pid is no longer the foreground process
 */
void waitfg(pid_t pid)
{
    while(pid == fgpid(jobs)){
        sleep(0);
    }
}

 

sigchld handler

回收僵尸进程的关键函数,需要注意如下几点:

1.理解waitpid的用法,这里使用WNOHANG|WUNTRACED的组合会更合适,表示立即返回,如果等待集合中没有进程被中止或停止返回0,否则返回进程的pid。

2.检验status的值来执行不同操作,status的含义有如下枚举:

  • WIFEXITED(status):
    如果进程是正常返回即为true,什么是正常返回呢?就是通过调用exit()或者return返回的
  • WIFSIGNALED(status):
    如果进程因为捕获一个信号而终止的,则返回true
  • WIFSTOPPED(status):
    如果返回的进程当前是被停止,则为true

  所以三种情况都是需要delete job的,当进程为停止状态同时需要设置job的status。

void sigchld_handler(int sig) 
{
    pid_t pid;
    int status;
    while((pid = waitpid(-1,&status,WNOHANG|WUNTRACED))>0){
        if(WIFEXITED(status)){
            deletejob(jobs,pid);
        }
        if(WIFSIGNALED(status)){
            deletejob(jobs,pid);
        }
        if(WIFSTOPPED(status)){
            struct job_t *job = getjobpid(jobs,pid);
            if(job !=NULL ){
        job->state = ST;
        }
        }
    }
    if(errno != ECHILD)
        unix_error("waitpid error");

    return;
}

 

sigint handler

ctrl-c的响应函数,直接调用kill函数给相关进程。

void sigint_handler(int sig) 
{
    pid_t pid = fgpid(jobs);
    if(pid!=0){
        kill(-pid,sig);
    }
    return;
}

 

sigtstp handler

ctrl-z的响应函数,直接调用kill函数给相关进程,需要注意kill前判断状态,不要重复发送信号。

/*
 * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
 *     the user types ctrl-z at the keyboard. Catch it and suspend the
 *     foreground job by sending it a SIGTSTP.  
 */
void sigtstp_handler(int sig) 
{
    pid_t pid = fgpid(jobs);

    if(pid!=0 ){
        struct job_t *job = getjobpid(jobs,pid);
        if(job->state == ST){
            return;
        }else{
            Kill(-pid,SIGTSTP);
        }
    }
    return;
}

今天的关于Linux Lab 项目启动 6 年后,终于发布了 v1.0 正式版linux-lab的分享已经结束,谢谢您的关注,如果想了解更多关于01、开源游戏-“胡子”项目启动、Cherokee 终于发布了 1.0 版本、CSAPP Lab:Bomb Lab——从拆弹到爆炸。。。、CSAPP Lab:Shell Lab——理解进程控制的秘密的相关知识,请在本站进行查询。

本文标签: