commit e1611d367521c5e84d69ef4bbf62f39020fe95a0 Author: superconvert <48017165+superconvert@users.noreply.github.com> Date: Sun Jul 24 23:14:23 2022 +0800 init repo diff --git a/01_run_nat.sh b/01_run_nat.sh new file mode 100644 index 0000000..c68c6d0 --- /dev/null +++ b/01_run_nat.sh @@ -0,0 +1,81 @@ +#!/bin/sh + +#--------------------- +# 停掉 NAT +#--------------------- +stop() { + # 停掉 tap0 + ip link set tap0 down + # 断开与网桥链接 + brctl delif br0 tap0 + # 停掉网桥 + ip link set br0 down + # 删除设备 tap0 + ip tuntap del mode tap tap0 + # 删除网桥 + brctl delbr br0 +} + +#--------------------- +# 启动 NAT +#--------------------- +start() { + # 创建虚拟网桥 + brctl addbr br0 + # 创建虚拟tap设备 + ip tuntap add dev tap0 mode tap + # 将tap设备介入网桥 + brctl addif br0 tap0 + # 配置网桥ip + ip addr add 192.168.100.1/24 dev br0 + ip addr add 192.168.100.2/24 dev tap0 + # 启动桥设备和虚拟网卡设备 + ip link set br0 up + ip link set tap0 up + # 配置iptables forward转发规则 + # 在基本环境搭建这一节中,设置了一个本地网络,虚机只能访问host,无法访问外网,如果需要访问外网需要设置SNAT + iptables -t nat -A POSTROUTING -s 192.168.100.0/24 ! -d 192.168.100.0/24 -j MASQUERADE + # 开启物理网卡的转发功能: + sysctl -w net.ipv4.ip_forward=1 + # 如果有防火墙的,特别是centos系统中,记得放开防火墙 + iptables -A FORWARD -s 192.168.100.0/24 -j ACCEPT +} + +#---------------------- +# DNS 服务 +#---------------------- +start_dns() { + +# 准备dnsmasq配置文件,启动dnsmasq服务,这样就能为虚拟机自动分配IP了 +cat<dnsmasq.conf +strict-order +pid-file=/var/run/dnsmasq.pid +except-interface=lo +bind-interfaces +listen-address=192.168.0.1 +dhcp-range=192.168.100.2,192.168.100.254 +dhcp-no-override +dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases +dhcp-lease-max=253 +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts +EOF +/usr/sbin/dnsmasq --conf-file=./dnsmasq.conf + +} + +stop_dns() { + # 杀掉 dhcp 服务 + killall dnsmasq +} + +#---------------------------------------------- +# 运行 smart-os 前,先启动这个,这样就能上网了 +#---------------------------------------------- +if [ -n "$1" ];then + stop + echo "stop" +else + start + echo "start" +fi diff --git a/02_make_sdb.sh b/02_make_sdb.sh new file mode 100644 index 0000000..85faa25 --- /dev/null +++ b/02_make_sdb.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +#---------------------------------------------- +# +# 制作磁盘 +# +#---------------------------------------------- + +echo "${CYAN}开始制作磁盘...${NC}" + +# 创建磁盘 64M +dd if=/dev/zero of=extra.img bs=1M count=64 + +# 对磁盘进行分区一个主分区 +fdisk extra.img << EOF +n +p + + + +w +EOF + +echo "${GREEN}磁盘制作成功!!!${NC}" +echo ".........................................................." + +# 磁盘镜像挂载到具体设备 +loop_dev=$(losetup -f) + +# fdisk -l disk.img 查看 start 为 2048, unit 512 所以 -o 偏移扇区 1048576 = 2048 x 512 +losetup -o 1048576 ${loop_dev} extra.img + +# 对磁盘进行格式化 +mkfs.ext3 ${loop_dev} + +losetup -d ${loop_dev} + diff --git a/03_build_disk.sh b/03_build_disk.sh new file mode 100644 index 0000000..02da7ab --- /dev/null +++ b/03_build_disk.sh @@ -0,0 +1,282 @@ +#!/bin/sh + +red='\e[0;41m' # 红色 +RED='\e[1;31m' +green='\e[0;32m' # 绿色 +GREEN='\e[1;32m' +yellow='\e[5;43m' # 黄色 +YELLOW='\e[1;33m' +blue='\e[0;34m' # 蓝色 +BLUE='\e[1;34m' +purple='\e[0;35m' # 紫色 +PURPLE='\e[1;35m' +cyan='\e[4;36m' # 蓝绿色 +CYAN='\e[1;36m' +WHITE='\e[1;37m' # 白色 +NC='\e[0m' # 没有颜色 + +#---------------------------------------------- +# +# 制作磁盘 +# +#---------------------------------------------- +# 创建磁盘 64M +dd if=/dev/zero of=disk.img bs=1M count=64 +# 对磁盘进行分区一个主分区 +fdisk disk.img << EOF +n +p + + + +w +EOF +echo ".........................................................." + +# 磁盘镜像挂载到具体设备 +loop_dev=$(losetup -f) +# fdisk -l disk.img 查看 start 为 2048, unit 512 所以 -o 偏移扇区 1048576 = 2048 x 512 +losetup -o 1048576 ${loop_dev} disk.img +# 对磁盘进行格式化 +mkfs.ext3 ${loop_dev} + +diskfs="diskfs" +# 挂载磁盘到本地目录 +mkdir -pv ${diskfs} +mount -t ext3 ${loop_dev} ${diskfs} + +# 安装grub 引导 +grub-install --boot-directory=${diskfs}/boot/ --target=i386-pc --modules=part_msdos disk.img + +#---------------------------------------------- +# +# 下载源码 +# +#---------------------------------------------- +mkdir -pv source +cd source + +#KERNEL_SOURCE_URL=https://kernel.org/pub/linux/kernel/v4.x/linux-4.14.9.tar.xz +KERNEL_SOURCE_URL=https://mirror.bjtu.edu.cn/kernel/linux/kernel/v4.x/linux-4.14.9.tar.xz +if [ ! -f "linux-4.14.9.tar.xz" ]; then + wget $KERNEL_SOURCE_URL +fi + +BUSYBOX_SOURCE_URL=https://busybox.net/downloads/busybox-1.34.1.tar.bz2 +if [ ! -f "busybox-1.34.1.tar.bz2" ]; then + wget $BUSYBOX_SOURCE_URL +fi + +cd .. + +#--------------------------------------------- +# +# 制作内核和 rootfs +# +#--------------------------------------------- +mkdir -pv work +mkdir -pv rootfs +mkdir -pv rootfs/dev +mkdir -pv rootfs/etc +mkdir -pv rootfs/sys +mkdir -pv rootfs/mnt +mkdir -pv rootfs/tmp +mkdir -pv rootfs/lib +mkdir -pv rootfs/sbin +mkdir -pv rootfs/proc +mkdir -pv rootfs/root +mkdir -pv rootfs/lib64 +mkdir -pv rootfs/lib/modules + +if [ ! -d "./work/linux-4.14.9" ]; then + tar xvf source/linux-4.14.9.tar.xz -C work/ +fi + +if [ ! -d "./work/busybox-1.34.1" ]; then + tar xvf source/busybox-1.34.1.tar.bz2 -C work/ +fi + +cd work + +# 编译内核, 最终所有模块都装到目录 /lib/modules/4.14.9 +if [ ! -f "./linux-4.14.9/arch/x86_64/boot/bzImage" ]; then + # Enable the VESA framebuffer for graphics support. + # 网络需要 TUN/TAP 驱动 [ Device Drivers ] ---> [ Network device support ] ---> [ Universal TUN/TAP device driver support ] + cd linux-4.14.9 && make x86_64_defconfig && sed -i "s/.*CONFIG_FB_VESA.*/CONFIG_FB_VESA=y/" .config && make bzImage -j8 && cd .. + #cd linux-4.14.9 && make x86_64_defconfig && make bzImage -j8 && make modules && make modules_install && cd .. +fi + +# 拷贝内核镜像 +cp linux-4.14.9/arch/x86_64/boot/bzImage ../${diskfs}/boot/bzImage + +# 编译 busybox +if [ ! -d "./busybox-1.34.1/_install" ]; then + # 静态编译 sed -i "s/# CONFIG_STATIC is not set/CONFIG_STATIC=y/g" .config + cd busybox-1.34.1 && make defconfig && make -j8 && make install && cd .. +fi + +# 拷贝 busybox 到 rootfs +echo "${CYAN}开始制作rootfs...${NC}" +cp busybox-1.34.1/_install/* ../rootfs/ -r +cd .. + +#----------------------------------------------- +# +# 制作启动文件系统 initramfs +# +#----------------------------------------------- +cd rootfs + +# 这种方法也可以 mkinitramfs -k -o ./${diskfs}/boot/initrd 4.14.9 +# 利用 Busybox 采用脚本制作 init 脚本 https://blog.csdn.net/embeddedman/article/details/7721926 + +make_init() { + +cat<<"EOF">init +#!/bin/sh + +# 必须首先挂载,否则 mdev 不能正常工作 +mount -t sysfs none /sys +mount -t proc none /proc +mount -t devtmpfs none /dev +mount -t tmpfs none /tmp -o mode=1777 +# 必须挂载一下,否则下面的 mount 不上 +mdev -s +mount -t ext3 /dev/sda1 /mnt + +# 关闭内核烦人的输出信息 +echo 0 > /proc/sys/kernel/printk +echo -e "\n\e[0;32mBoot took $(cut -d' ' -f1 /proc/uptime) seconds\e[0m" + +mkdir -p /dev/pts +mount -t devpts none /dev/pts + +# 切换之前,修改 mount 路径 +mount --move /dev /mnt/dev +mount --move /sys /mnt/sys +mount --move /proc /mnt/proc +mount --move /tmp /mnt/tmp + +# 切换到真正的磁盘系统上 rootfs(initramfs) ---> diskfs +exec switch_root /mnt /sbin/init +EOF + +# /sbin/init [switch_root 执行] ---> /etc/inittab [定义了启动顺序] ---> +# /etc/init.d/rcS [系统 mount, 安装驱动,配置网络] ---> +# /etc/init.d/rc.local [文件配置应用程序需要的环境变量] ---> +# /etc/profile [部分初始化] +chmod +x init + +} +make_init + +# 下面这些不用了,利用脚本里面的 busybox 的 mdev -s 自动挂载 +# mknod -m 644 dev/tty0 c 4 1 +# mknod -m 644 dev/tty c 5 0 +# mknod -m 600 dev/console c 5 1 +# mknod -m 644 dev/null c 1 3 +# mknod -m 640 dev/sda1 b 8 1 + +# 指定了利用 /etc/init.d/rcS 启动 +cat<<"EOF">etc/inittab +::sysinit:echo "sysinit 1++++++++++++++++++++++++++++++++++++++" +::sysinit:/etc/init.d/rcS +::sysinit:echo "sysinit 2++++++++++++++++++++++++++++++++++++++" +::restart:/sbin/init +::ctrlaltdel:/sbin/reboot +::shutdown:/bin/umount -a -r +tty1::once:echo "hello smart-os tty1" +tty1::respawn:/bin/sh +tty2::once:echo "hello smart-os tty2" +tty2::respawn:/bin/sh +tty3::once:echo "hello smart-os tty3" +tty3::respawn:/bin/sh +EOF + +# dns 测试 +# 0. 启动脚本 run_nat.sh +# 1. busybox 必须动态编译 +# 2. ifconfig eth0 192.168.100.6 && ifconfig eth0 up +# 3. route add default gw 192.168.100.1 +# 4. echo "nameserver 114.114.114.114" >> /etc/resolv.conf +cp -rf ../fixed/lib* lib/ && cp ../fixed/ld-linux-x86-64.so.2 lib64/ + +find . | cpio -R root:root -H newc -o | gzip -9 > ../${diskfs}/boot/initrd +echo "${GREEN}rootfs制作成功!!!${NC}" +echo ".........................................................." +cd .. + +#-------------------------------------------------------------- +# +# 生成磁盘文件系统(利用 busybox 结构,省的自己创建了) +# +#-------------------------------------------------------------- +echo "${CYAN}开始制作diskfs...${NC}" +cp rootfs/* ${diskfs} -r +rm -rf ${diskfs}/init && rm -rf ${diskfs}/linuxrc && rm -rf ${diskfs}/lost+found + +# 我们测试驱动, 制作的镜像启动后,我们进入此目录 insmod hello_world.ko 即可 +./make_driver.sh $(pwd)/${diskfs}/lib/modules +# 编译网卡驱动 ( 目前版本内核已集成 e1000 ) +# cd work/linux-4.14.9 && make M=drivers/net/ethernet/intel/e1000/ && cd ../.. + +# 生成 grub.cfg 文件 +cat - > ${diskfs}/boot/grub/grub.cfg << EOF +set timeout=6 +menuentry "smart-os" { + root=(hd0,msdos1) + linux /boot/bzImage console=tty0 + initrd /boot/initrd +} +EOF + +# 生成 rcS 文件 +title=$(cat< ${diskfs}/etc/init.d/rcS << EOF +#!/bin/sh +echo -e "\n“${title}”\n" + +# 测试驱动加载 +cd /lib/modules && insmod hello_world.ko + +# dns 测试 +ifconfig eth0 192.168.100.6 && ifconfig eth0 up +route add default gw 192.168.100.1 +echo "nameserver 114.114.114.114" >> /etc/resolv.conf + + + +# exec 执行 /etc/init.d/rc.local 脚本 +EOF +chmod +x ${diskfs}/etc/init.d/rcS + +cat -> ${diskfs}/rtmpd.sh << EOF +wget http://www.qiyicc.com/download/rtmpd.zip +unzip rtmpd.zip +rm rtmpd.zip -rf +cd rtmpd +mv smart_rtmp/smart_rtmpd.multithread.centos* ./ +tar zxvf *.tar.gz +rm *.tar.gz -rf +rm smart_rtmp -rf +EOF +chmod +x ${diskfs}/rtmpd.sh + +echo "${GREEN}diskfs制作成功!!!${NC}" +echo ".........................................................." + +# 卸载映射 +umount ${loop_dev} +losetup -d ${loop_dev} \ No newline at end of file diff --git a/04_run_docker.sh b/04_run_docker.sh new file mode 100644 index 0000000..2ca0197 --- /dev/null +++ b/04_run_docker.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +dock_name=smart-os +loop_dev=$(losetup -f) + +# fdisk -l disk.img 查看 start 为 2048, unit 512 所以 -o 偏移扇区 1048576 = 2048 x 512 +losetup -o 1048576 ${loop_dev} disk.img + +# 挂载磁盘到本地目录 +mkdir -p ./tmp_docker +mount -t ext3 ${loop_dev} ./tmp_docker +cd ./tmp_docker +tar -cvpf ../${dock_name}.tar --directory=./ --exclude=proc --exclude=sys --exclude=dev --exclude=run --exclude=boot . +cd .. +umount ./tmp_docker +rm -rf ./tmp_docker +losetup -d ${loop_dev} + +# 删除镜像 +clear() { + if [ ! "`docker ps -a | grep ${dock_name}`" = "" ] ; then + docker stop `docker ps -a | grep ${dock_name} | awk '{print $1}'` + docker rm `docker ps -a | grep ${dock_name} | awk '{print $1}'` + fi + + if [ ! "`docker images -a | grep ${dock_name}`" = "" ] ; then + docker rmi `docker images -a | grep ${dock_name} | awk '{print $1}'`:1.0 + fi +} + +# 导入镜像 +run() { + cat smart-os.tar | docker import - ${dock_name}:1.0 + docker run -t -i ${dock_name}:1.0 /bin/sh +} + +clear +run +clear + +# 删除镜像文件 +if [ -f "${dock_name}.tar" ]; then + rm -rf ${dock_name}.tar +fi diff --git a/04_run_qemu.sh b/04_run_qemu.sh new file mode 100644 index 0000000..6c90d5f --- /dev/null +++ b/04_run_qemu.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# 启动镜像 网络对应 run_nat.sh 里面的配置 +qemu-system-x86_64 -drive format=raw,file=disk.img -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 + +#---------------------------------------------------- +# +# 多硬盘测试 -hdb extra.img +# +#---------------------------------------------------- +# make_sdb.sh +# qemu-system-x86_64 -drive format=raw,file=disk.img -hdb extra.img + diff --git a/README.md b/README.md new file mode 100644 index 0000000..550ee44 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# ramfs : +# ramfs是一种非常简单的文件系统,它直接利用linux内核已有的高速缓存机制(所以其实现代码很小, 也由于这个原因, ramfs特性不能通过内核配置参数屏蔽, +# 它是内核的天然属性), 使用系统的物理内存,做成一个大小可以动态变化的的基于内存的文件系统, 系统不会回收, 只有 root 用户使用它 +# +# tmpfs : +# tmpfs是ramfs的衍生物,在ramfs的基础上增加了容量大小的限制和允许向交换空间(swap) 写入数据。由于增加了这两个特性,所以普通用户也可以使用tmpfs。 +# tmpfs 占用的是虚拟内存,不全是 RAM ,性能可能没 ramfs 高 +# +# ramdisk : +# ramdisk是一种将内存中的的一块区域作为物理磁盘来使用的一种技术,也可以说,ramdisk是在一块内存区 域中创建的块设备,用于存放文件系统。对于用 +# 户来说,可以把ramdisk与通常的硬盘分区同等对待来使用。系统读写它还会在内存中存储一份对应的缓存,污染 CPU 缓存,性能也差,需要对应驱动支持 +# +# rootfs : +# rootfs是一个特定的ramfs(或tmpfs,如果tmpfs被启用)的实例,它始终存在于linux2.6的系统中。rootfs不能被卸载(与其添加特殊代码用来维护空的链表, +# 不如把rootfs节点始终加入,因此便于kernel维护。rootfs是ramfs的一个空实例,占用空间极小)。大部分其他的文件系统安装于rootfs之上,然后忽略它。 +# 它是内核启动初始化根文件系统。 + +# rootfs又分为虚拟rootfs和真实rootfs。 +# 虚拟rootfs由内核自己创建和加载,仅仅存在于内存之中(后续的InitRamfs也是在这种基础上实现),其文件系统是tmpfs类型或者ramfs类型。 +# 真实rootfs则是指根文件系统存在于存储设备上,内核在启动过程中会在虚拟rootfs上挂载这个存储设备,然后将/目录节点切换到这个存储设备上,这样存储 +# 设备上的文件系统就会被作为根文件系统使用(后续InitRamdisk是在这种基础上实现),其文件系统类型更加丰富,可以是ext2、yaffs、yaffs2等等类型, +# 由具体的存储设备的类型决定。 + +# 我们的启动文件系统其实就是为 rootfs 准备文件,让内核按照我们的意愿执行 +# 在早期的linux系统中,一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式 +# 系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。 +# 在内核模块自动加载机制udev中,我们看到利用udevd可以实现内核模块的自动加载,因此我们希望如果存储根文件系统的存储设备的驱动程序也能够实现自动加载, +# 那就好了。但是这里有一个矛盾,udevd是一个可执行文件,在根文件系统被挂载前,是不可能执行udevd的,但是如果udevd没有启动,那就无法自动加载存储根文件 +# 系统设备的驱动程序,同时也无法在/dev目录下建立相应的设备节点。 +# 为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中 +# 必须的驱动模块,可执行文件和启动脚本,也包括上面提到的udevd(实现udev机制的demon)。当系统启动的时候,bootloader会把initrd文件读到内存中,然后把 +# initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,然后执行根目录中的 /init +# 脚本(cpio格式的initrd为/init,而image格式的initrd<也称老式块设备的initrd或传统的文件镜像格式的initrd>为/initrc),您就可以在这个脚本中运行initrd +# 文件系统中的udevd,让它来自动加载realfs(真实文件系统)存放设备的驱动程序以及在/dev目录下建立必要的设备节点。在udevd自动加载磁盘驱动程序之后,就 +# 可以mount真正的根目录,并切换到这个根目录中来。 diff --git a/cat_disk.sh b/cat_disk.sh new file mode 100644 index 0000000..34260e6 --- /dev/null +++ b/cat_disk.sh @@ -0,0 +1,21 @@ +loop_dev=$(losetup -f) + +# fdisk -l disk.img 查看 start 为 2048, unit 512 所以 -o 偏移扇区 1048576 = 2048 x 512 +losetup -o 1048576 ${loop_dev} disk.img + +# 挂载磁盘到本地目录 +mkdir -p ./mnt1 +mount -t ext3 ${loop_dev} ./mnt1 +echo "/ ---------------------------------------" +ls ./mnt1/ +echo "boot ---------------------------------------" +ls ./mnt1/boot +echo "sbin ---------------------------------------" +ls ./mnt1/sbin +echo "etc ---------------------------------------" +ls ./mnt1/etc +echo "dev ---------------------------------------" +ls ./mnt1/dev +umount ./mnt1 +rm -rf mnt1 +losetup -d ${loop_dev} diff --git a/make_driver.sh b/make_driver.sh new file mode 100644 index 0000000..f02bef9 --- /dev/null +++ b/make_driver.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +mkdir -pv driver && cd driver + +cat<hello_world.c +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int __init hello_world_init(void) +{ + printk(KERN_DEBUG "hello world!!!\n"); + return 0; +} + +static void __exit hello_world_exit(void) +{ + printk(KERN_DEBUG "goodbye world!!!\n"); +} + +module_init(hello_world_init); +module_exit(hello_world_exit); +EOF + +cat<Makefile +obj-m += hello_world.o +all: + make -C ../work/linux-4.14.9 M=`pwd` modules +clean: + make -C ../work/linux-4.14.9 M=`pwd` clean +EOF + +echo $1 +make && mv hello_world.ko $1 && make clean && cd .. && rm -rf driver