16、RK3399 qemu仿真环境配置ubuntu制作文件系统


测试环境:Firefly-RK3399 2+16

1、Ubuntu base源码下载

​ 在 Ubuntu 上,ubuntu-base 是指一个用于构建自定义操作系统镜像的基础系统包。它提供了 Ubuntu 操作系统的最小基础文件集,通常不包含桌面环境或其他应用程序。这对于嵌入式系统、容器化应用或其他定制化环境非常有用,用户可以在此基础上添加所需的包和功能,构建适合自己需求的操作系统。

源码官方地址:《ttp://cdimage.ubuntu.com/ubuntu-base/releases》。

本地文件链接:下载好的源码

打开网址后,单击20.04/

点击 release

点击arm64版本

root@liu-virtual-machine:/home/liu/rockchip/rootfs# mkdir another_way_qemu
root@liu-virtual-machine:/home/liu/rockchip/rootfs# cd another_way_qemu/
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# ls
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# mv '/var/run/vmblock-fuse/blockdir/XXDx5D/ubuntu-base-20.04.2-base-arm64.tar.gz' .
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# ls
ubuntu-base-20.04.2-base-arm64.tar.gz
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# mkdir -p rootfs/ubuntu
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# sudo tar -xpvf ubuntu-base-20.04.2-base-arm64.tar.gz -C rootfs/ubuntu/
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu# cd rootfs/ubuntu/
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# ls
bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
需要注意的是:解压后的文件,需要保留ubuntu-base中的文件权限及所有者,解压时需要root权限或者sudo操作,且使用-p参数保留权限;

-p参数保留权限;

2、配置qemu

qemu-user-static是一个仿真器,可以选取arm64配置文件仿真开发板运行环境,然后挂载下载的ubuntu-base文件,从而构建ubuntu文件系统。

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# sudo apt-get install qemu-user-static
Reading package lists... Done
Building dependency tree       
Reading state information... Done
qemu-user-static is already the newest version (1:2.11+dfsg-1ubuntu7.42).
qemu-user-static set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 24 not upgraded.

由于下载的ubuntu-baseaarch64架构的,因此需要拷贝qemu-aarch64-staticubuntu/usr/bin/下;

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# ls
bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# sudo cp /usr/bin/qemu-aarch64-static ./usr/bin/
2.1设置源:

这里要用ARM源,不能复制我们本机的源

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# sudo vim ./etc/apt/sources.list
替换为以下华为源:
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# cat etc/apt/sources.list
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal main multiverse restricted universe
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-backports main multiverse restricted universe
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-proposed main multiverse restricted universe
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-security main multiverse restricted universe
deb http://mirrors.huaweicloud.com/ubuntu-ports/ focal-updates main multiverse restricted universe
deb-src http://mirrors.huaweicloud.com/ubuntu-ports/ focal main multiverse restricted universe
deb-src http://mirrors.huaweicloud.com/ubuntu-ports/ focal-backports main multiverse restricted universe
deb-src http://mirrors.huaweicloud.com/ubuntu-ports/ focal-proposed main multiverse restricted universe
deb-src http://mirrors.huaweicloud.com/ubuntu-ports/ focal-security main multiverse restricted universe
deb-src http://mirrors.huaweicloud.com/ubuntu-ports/ focal-updates main multiverse restricted universe
或清华源:
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-proposed main restricted universe multiverse
deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu-ports/ focal-proposed main restricted universe multiverse
或163源:(我用的这个)
deb http://mirrors.163.com/ubuntu-ports/ focal main restricted universe multiverse
deb http://mirrors.163.com/ubuntu-ports/ focal-security main restricted universe multiverse
deb http://mirrors.163.com/ubuntu-ports/ focal-updates main restricted universe multiverse
deb http://mirrors.163.com/ubuntu-ports/ focal-proposed main restricted universe multiverse
deb http://mirrors.163.com/ubuntu-ports/ focal-backports main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu-ports/ focal main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu-ports/ focal-security main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu-ports/ focal-updates main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu-ports/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.163.com/ubuntu-ports/ focal-backports main restricted universe multiverse
2.2 配置DNS

为了可以联网更新软件,我们拷贝本机的dns配置文件到根文件系统;

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# sudo cp /etc/resolv.conf ./etc/resolv.conf

然后在/etc/resolv.conf(ubuntu文件夹下)文件中添加dns

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# sudo vim ./etc/resolv.conf
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu# cat etc/resolv.conf 
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "systemd-resolve --status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0
nameserver 8.8.8.8
nameserver 114.114.114.114

修改./etc/systemd/resolved.conf

[Resolve]
DNS=8.8.8.8 114.114.114.114
2.3 挂载卸载根文件系统

rootfs目录下创建挂载脚本mnt_ubuntu.sh

#!/bin/bash
mnt() {
    echo "MOUNTING"
    sudo mount -t proc /proc ${2}proc
    sudo mount -t sysfs /sys ${2}sys
    sudo mount -o bind /dev ${2}dev
    sudo mount -o bind /dev/pts ${2}dev/pts
    sudo chroot ${2}
}
umnt() {
    echo "UNMOUNTING"
    sudo umount ${2}proc
    sudo umount ${2}sys
    sudo umount ${2}dev/pts
    sudo umount ${2}dev
}
 
if [ "$1" == "-m" ] && [ -n "$2" ] ;
then
    mnt $1 $2
elif [ "$1" == "-u" ] && [ -n "$2" ];
then
    umnt $1 $2
else
    echo ""
    echo "Either 1'st, 2'nd or both parameters were missing"
    echo ""
    echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
    echo "2'nd parameter is the full path of rootfs directory(with trailing '/')"
    echo ""
    echo "For example: ch-mount -m /media/sdcard/"
    echo ""
    echo 1st parameter : ${1}
    echo 2nd parameter : ${2}
fi

给脚本执行权限 chmod +x mnt_ubuntu.sh

挂载根文件系统

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ./mnt_ubuntu.sh -m ubuntu/

解析上面的脚本
(1) proc文件系统是指一类虚拟文件系统,它不是从磁盘上的分区中读取数据,而是通过内核在内存中动态生成的。

proc文件系统通常用于提供有关系统内核和进程信息的接口,例如系统内存使用情况、硬件设备信息等。在Linux系统中挂载proc文件系统的命令格式如下:

mount -t proc [选项] /proc [挂载点]
其中,-t proc参数表示将要挂载的文件系统类型是proc文件系统;/proc表示要挂载的proc文件系统的挂载点;ubuntu/proc表示挂载点在当前目录下的一个名为ubuntu的子目录中的proc子目录。通过这个命令,可以将proc文件系统挂载到指定的挂载点,以便访问其中包含的有关系统内核和进程信息的接口。

(2)mount -y sysfs命令和mount -t proc同理;

(3) mount -o bind命令将前一个目录挂载到后一个目录上,所有对后一个目录的访问其实都是对前一个目录的访问;

(4) chroot ubuntu/命令把根目录换成指定的目的目录,此时根目录就变成了ubuntu-base所在目录的;用ll可以看到文件系统也有变化,此终端里的根文件系统已经切换到ubuntu目录里的根文件系统,就像进入了一个新系统,所以这也叫作是模拟运行根文件系统;

文件系统配置完成,输入exit ,然后运行脚本卸载文件系统

卸载根文件系统

执行如下命令卸载文件系统:

root@liu-virtual-machine:/# exit
exit
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ls
mnt_ubuntu.sh  ubuntu
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ./mnt_ubuntu.sh -u ubuntu/
UNMOUNTING

实际上就是把之前挂载的全部卸载掉

安装软件以及桌面环境等

以下安装需要在挂载ubuntu-base文件系统之后进行。

安装必要软件

默认下,ubuntu-base基本没安装什么工具,如果要正常使用,我们可以根据需要安装,以下基本的几个建议都进行安装

root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ./mnt_ubuntu.sh -m ubuntu/
MOUNTING
root@liu-virtual-machine:/# apt-get update
root@liu-virtual-machine:/# apt-get install net-tools
root@liu-virtual-machine:/# apt-get install ethtool
root@liu-virtual-machine:/# apt-get install ifupdown
root@liu-virtual-machine:/# apt-get install psmisc
root@liu-virtual-machine:/# apt-get install nfs-common
root@liu-virtual-machine:/# apt-get install htop
root@liu-virtual-machine:/# apt-get install vim
apt-get install rsyslog
apt-get install iputils-ping
apt-get install language-pack-en-base
apt-get install sudo
apt-get install network-manager systemd   时区 6  70
apt install iputils-ping
apt install openssh-sftp-server

安装桌面环境(暂不安装)

ubuntu官方考虑到使用者的不同需求,提供各种不同的发行板。虽然发布了几种版本的ubuntu系统,但是他们的核心系统是一模一样的,可以这么说不同发行版的ubuntu的区别在于:桌面环境的不同和预设安装的软件的不同;

(1) ubuntuubuntu是主要的发行版,它使用GNOME这个桌面环境,相依的虚拟套件是ubuntu-desktop

(2) kubuntu:采用以功能强大闻名的KDE当成桌面环境,功能众多以及华丽桌面配置为其卖点,相依的虚拟套件是kubuntu-desktop

(3) xubuntu:采用了比较轻量级的桌面环境Xfce,所以这个版本的诉求是针对比较老旧的电脑。Xfce的设计理念是减少使用的系统资源,并且成为一套完整可用的桌面环境。功能来说,虽没有像ubuntukubuntu功能众多,但也具备基本文书、上网与影音等功能。相依的虚拟套件是xubuntu-desktop

(4) lubuntu:采用了比Xfce更轻量的桌面环境Lxde,是自从10.04之后才新增的版本。这个版本的诉求是针对小笔电、效能较差的电脑或追求快速的使用者。虽然精简,但仍然符合大多数使用者对于桌面的要求。同样具备文书处理、上网和影音,更特别的是,它已经内建了几乎所有播放需要使用到的解码器,可直接播放mp3rmvb等格式的档案,相依的虛擬套件是lubuntu-desktop

(5) edubuntu:是ubuntu的教育分支版。它主要的诉求是教育使用,所以里面有很多精心挑选的教育相关套件,和一些小游戏等。而为了可以让教师们快速安装到电脑教室或安装到老旧的电脑里,它还使用了LTSP技术,可以让老师们在短短的一个小时内建立整个电脑教师环境。使用GNOME桌面环境相依的虚拟套件是edubuntu-desktop;使用KDE桌面环境相依的虚拟套件是edubuntu-desktop-kde

LTSP (Linux Terminal Server Project)的发展目的是提供多个工作站只负责显示,实际软体和计算在伺服器上面,也叫做thin-clients机制。它的好处是工作站可以使用很老旧的电脑,因为工作站只用来当XTerminal,所以一切资源都放在伺服器上。这个方式可以让维修成本和管理成本减少很多,所以特别适合公司和学校使用;

这里我们选择一个虚拟套件安装,这里我最初的虚拟套件是ubuntu-desktop;(我没有安装)

apt-get install ubuntu-desktop

安装ubuntu-restricted-extras

ubuntu-restricted-extras是一个包含各种基本软件,如Flash插件、unrargstreamermp4ubuntu中的chromium浏览器的编解码器等的软件包。

由于这些软件不是开源软件,并且其中一些涉及软件专利,因此ubuntu默认情况下不会安装它们。你必须使用multiverse仓库,它是ubuntu专门为用户提供非开源软件而创建的仓库。

由于ubuntu-restrcited-extras软件包在multiverse仓库中,因此你应验证系统上已启用multiverse仓库:

sudo add-apt-repository multiverse

然后你可以使用以下命令安装:

sudo apt install ubuntu-restricted-extras

安装完成后,由于新安装的媒体编解码器,你应该可以播放MP3和其他媒体格式了

系统设置

以下配置需要在挂载ubuntu-base文件系统之后进行。

修改root用户密码:

passwd root

修改sshd配置文件的PermitRootLogin属性

vim ./etc/ssh/sshd_config
在最后面加上,PermitRootLogin yes:
PermitRootLogin yes #是否允许root登录,默认是允许的,但建议设置为no
LoginGraceTime 600m #设置指定时间内没有成功登录,将会断开连接,若无单位则默认时间为秒

新增用户

新增用户,这个根据具体的情况,嵌入式的环境下,我们可以不用新增,直接使用root的用户就行了,如果要新增,执行如下的步骤:

adduser XXXX

这里需要输入用户的一些信息,也可以直接回车保留默认值即可。默认情况下新用户是不能使用sudo命令的,我们需要修改/etc/sudoers文件。/etc/sudoers文件默认是只读的,因此需要先修改此文件的写权限,使用如下命令:

chmod u+w /etc/sudoers

然后使用vim打开/etc/sudoers,找到root ALL=(ALL:ALL) ALL这一行,在这一行下面添加:

XXXX ALL=(ALL:ALL) ALL

修改完成以后保存退出,重新恢复/etc/sudoers的只读属性,使用如下命令:

chmod u-w /etc/sudoers

设置主机名称和IP

echo "liu" > /etc/hostname
echo "127.0.0.1 localhost" >> /etc/hosts
echo "127.0.0.1 liu" >> /etc/hosts

/etc/hostname中存放的是主机名,/etc/hosts存放的是域名与ip的对应关系,域名与主机名没有任何关系,你可以为任何一个IP指定任意一个名字。

配置DHCP

我们配置一下网络DHCP,这样系统启动以后就会自动设置好网络。RK3399默认有1个有线网卡、此外板载2.4G & 5G双频WiFi模组。

网卡eth0

echo auto eth0 > /etc/network/interfaces.d/eth0
echo iface eth0 inet dhcp >> /etc/network/interfaces.d/eth0

其中,eth0是接口的名称,inetIPV4协议的设置方式,dhcp表示使用DHCP服务器分配IP地址,如果需要使用静态IP地址,其值应改为static,例如/etc/network/interfaces.d/eth0(不做此操作)

auto eth0
iface eth0 inet static
address 192.168.0.105     #设置IP地址为192.168.0.105
netmask 255.255.255.0     #设置掩码为255.255.255.0
gateway 192.168.0.1       #设置默认网关为192.168.0.1

无线网卡wlan:(暂时不配置)

echo auto wlan0 > /etc/network/interfaces.d/wlan0
echo allow-hotplug wlan0 >> /etc/network/interfaces.d/wlan0
echo iface wlan0 inet dhcp >> /etc/network/interfaces.d/wlan0

在实际测试中网口必须接入网线系统才能正常启动,就是在不联网的情况下,每次开机都要等待很久,卡在网络连接上5分钟,这里我们可以修改下面这个文件:

vim /lib/systemd/system/networking.service

将里面的TimeoutStartSec=5min修改为:

TimeoutStartSec=1sec

修改系统重启默认等待时间

重启开发板的时候,如果有进程没有结束,系统就会等待,默认等待时间很长,导致重启速度慢。

我们可以修改默认等待时间

vim /etc/systemd/system.conf

找到这几行:

#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultTRestartSec=100ms

解除注释并将DefaultTimeoutStopSec=90s修改为:

DefaultTimeoutStopSec=1s

设置开机免密登录到图形界面(未加)

(1) 我们使用以下命令修改50-ubuntu.conf文件:

root@ubuntu:/# vim /usr/share/lightdm/lightdm.conf.d/50-ubuntu.conf

在文件末尾加入以下内容:

greeter-show-manual-login=true
 
all-guest=false

修改完成后保存退出。

(2) 输入以下命令修改gdm-autologin文件内容:

root@ubuntu:/# vim /etc/pam.d/gdm-autologin

注释掉下面这一行,并保存退出。

#auth    required        pam_succeed_if.so user != root quiet_success

(3) 输入以下命令修改gdm-password文件内容:

root@ubuntu:/# vim /etc/pam.d/gdm-password

注释掉下面这一行,并保存退出。

auth    required        pam_succeed_if.so user != root quiet_success

(4) 输入以下命令修改/root/.profile文件:

root@ubuntu:/# vim /root/.profile

将文件最后一行改为以下内容,修改完成如所示:

tty -s && mesg n || true

(5) 输入以下命令修改custom.conf文件:

root@ubuntu:/# vim /etc/gdm3/custom.conf

在文件末尾添加以下内容:

[daemon]
AutomaticLoginEnable=true
AutomaticLogin=root
TimedLoginEnable=true
TimedLogin=root
TimedLoginDelay=10

至此,我们构建的文件系统,就可以开启root用户免密登录可视界面了!

安装Linux-headers(暂时不添加)

如果想在开发板上进行编译安装源代码,必须安装linux-headers

编译内核头文件:

root@ubuntu:/work/sambashare/rk3399/linux-6.3# make -j$(nproc) bindeb-pkg

make bindeb-pkg是一个用于构建debian包的命令,它通常用于编译linux内核并生成对应的debian软件包。

当执行make bindeb-pkg 命令时,它会读取当前目录下的linux内核源代码,并根据配置文件进行内核编译。

编译过程将包括编译内核、生成模块、创建initramfs等步骤。最后,它将生成一组二进制文件和相关的debian控制文件,用于创建 debian包。

linux 6.3执行完成会在内核源码debian目录生成以下文件;

root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll debian/
-rw-r--r--  1 root root    6 130 23:06 arch
-rw-r--r--  1 root root  137 130 23:06 changelog
-rw-r--r--  1 root root 1239 130 23:06 control
-rw-r--r--  1 root root  691 130 23:06 copyright
-rw-r--r--  1 root root  269 130 23:12 files
drwxr-xr-x  5 root root 4096 130 23:11 linux-headers/
drwxr-xr-x  7 root root 4096 130 23:11 linux-image/
drwxr-xr-x  4 root root 4096 130 23:11 linux-image-dbg/
drwxr-xr-x  4 root root 4096 130 23:11 linux-libc-dev/
-rwxr-xr-x  1 root root  486 130 23:06 rules*

同时会在内核上一级目录下生成如下deb包:

root@ubuntu:/work/sambashare/rk3399# ll | grep linux
-rw-r--r--  1 root root  8407716 130 23:11 linux-headers-6.3.0_6.3.0-17_arm64.deb
-rw-r--r--  1 root root 25455204 130 23:11 linux-image-6.3.0_6.3.0-17_arm64.deb
-rw-r--r--  1 root root 69655120 130 23:12 linux-image-6.3.0-dbg_6.3.0-17_arm64.deb
-rw-r--r--  1 root root  1260012 130 23:11 linux-libc-dev_6.3.0-17_arm64.deb
-rw-r--r--  1 root root     7391 130 23:12 linux-upstream_6.3.0-17_arm64.buildinfo
-rw-r--r--  1 root root     2161 130 23:12 linux-upstream_6.3.0-17_arm64.changes

其中:

  • linux-image-<version>.deb:内核镜像文件,用于安装和引导新的内核;
  • linux-headers-<version>.deb:内核头文件,用于开发其他软件或编译内核模块;
  • linux-libc-dev_<version>.deb:用于构建用户空间软件的头文件和静态库;

这些生成的debian包可以在 debian或基于debian的系统上安装和使用。

安装linux-headers

ubuntu宿主机将我们编译的头文件拷贝到根文件系统/opt目录下;

root@ubuntu:/work/sambashare/rk3399/rootfs/ubuntu# cp /work/sambashare/rk3399/linux-headers-6.3.0_6.3.0-17_arm64.deb ./opt

首先需要挂载ubuntu-base文件系统;

root@ubuntu:/work/sambashare/rk3399/rootfs# ./mnt_ubuntu.sh -m ubuntu/

安装linux-headers

root@ubuntu:/# cd /opt
root@ubuntu:/opt# dpkg -i /opt/linux-headers-*.deb
Selecting previously unselected package linux-headers-6.3.0.
(Reading database ... 114184 files and directories currently installed.)
Preparing to unpack .../linux-headers-6.3.0_6.3.0-17_arm64.deb ...
Unpacking linux-headers-6.3.0 (6.3.0-17) ...
Setting up linux-headers-6.3.0 (6.3.0-17) ...

安装完成后,我们可以看一下/usr/src目录下是否创建了linux-headers-$(uname-r)文件;

root@ubuntu:/# ll /usr/src/
drwxr-xr-x 5 root root 4096 Nov 13 00:35 linux-headers-6.3.0
root@ubuntu:/# ll /usr/src/linux-headers-6.3.0/
-rw-r--r--  1 root root  264166 Sep 23 20:58 .config
-rw-r--r--  1 root root   71751 Jun 12  2023 Makefile
-rw-r--r--  1 root root 1064676 Sep 23 20:58 Module.symvers
drwxr-xr-x  3 root root    4096 Nov 13 00:35 arch/
drwxr-xr-x 33 root root    4096 Nov 13 00:35 include/
drwxr-xr-x 17 root root   12288 Nov 13 00:35 scripts/

文件系统配置完成,输入exit ,然后执行如下命令卸载文件系统:

root@ubuntu:/work/sambashare/rk3399/rootfs# ./mnt_ubuntu.sh -u ubuntu/
安装驱动模块(暂时不添加)

编译驱动模块

首先编译内核模块,如果已经编译过忽略即可:

root@ubuntu:/work/sambashare/rk3399/linux-6.3# export KMODULES_OUTDIR=`pwd`/out/output_rk3399_kmodules
root@ubuntu:/work/sambashare/rk3399/linux-6.3# rm -rf ${KMODULES_OUTDIR}
root@ubuntu:/work/sambashare/rk3399/linux-6.3# mkdir -p ${KMODULES_OUTDIR}
root@ubuntu:/work/sambashare/rk3399/linux-6.3# make modules -j$(nproc)

安装驱动模块

然后执行如下脚本install_modules.sh

#!/bin/bash
CROSS_COMPILE=arm-linux-
ARCH=arm64
# 用于构建并输出内核版本号
KERNEL_VER=`make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} kernelrelease`
KMODULES_OUTDIR=`pwd`/out/output_rk3399_kmodules/${KERNEL_VER}
rm -rf ${KMODULES_OUTDIR}
make CROSS_COMPILE=${CROSS_COMPILE} ARCH=${ARCH} INSTALL_MOD_PATH=${KMODULES_OUTDIR} modules_install
if [ $? -ne 0 ]; then
    echo "failed to build kernel modules."
         exit 1
fi
# 如果模块依赖文件modules.dep不存在,则生成内核模块的依赖关系
[ ! -f "${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER}/modules.dep" ] && depmod -b ${KMODULES_OUTDIR} -E Module.symvers -F System.map -w ${KERNEL_VER}
# 去除驱动中的符号信息
(cd ${KMODULES_OUTDIR} && find . -name \*.ko | xargs ${CROSS_COMPILE}strip --strip-unneeded)

# 更新内核模块依赖
(cd ${KMODULES_OUTDIR}/lib/modules/${KERNEL_VER}/ && {
	rm -rf ./build ./source
	echo "depmod ${KMODULES_OUTDIR} ${KERNEL_VER} ..."
	depmod -a -b ${KMODULES_OUTDIR} ${KERNEL_VER}
})

ubuntu宿主机将我们编译的驱动模块拷贝到根文件系统/lib/modules目录下;

root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll ${KMODULES_OUTDIR}
drwxr-xr-x 3 root root 4096 23 11:57 lib/
root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll ${KMODULES_OUTDIR}/lib
drwxr-xr-x 3 root root 4096 23 11:57 modules/
root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll ${KMODULES_OUTDIR}/lib/modules
drwxr-xr-x 3 root root 4096 23 12:02 6.3.0/
root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll ${KMODULES_OUTDIR}/lib/modules/6.3.0
drwxr-xr-x 9 root root   4096 23 12:02 kernel/
-rw-r--r-- 1 root root 383978 23 12:02 modules.alias
-rw-r--r-- 1 root root 376985 23 12:02 modules.alias.bin
-rw-r--r-- 1 root root  45077 23 12:01 modules.builtin
-rw-r--r-- 1 root root  83833 23 12:02 modules.builtin.alias.bin
-rw-r--r-- 1 root root  48994 23 12:02 modules.builtin.bin
-rw-r--r-- 1 root root 252258 23 12:01 modules.builtin.modinfo
-rw-r--r-- 1 root root  73761 23 12:02 modules.dep
-rw-r--r-- 1 root root 118208 23 12:02 modules.dep.bin
-rw-r--r-- 1 root root    128 23 12:02 modules.devname
-rw-r--r-- 1 root root  41203 23 12:01 modules.order
-rw-r--r-- 1 root root    402 23 12:02 modules.softdep
-rw-r--r-- 1 root root 131791 23 12:02 modules.symbols
-rw-r--r-- 1 root root 162601 23 12:02 modules.symbols.bin
root@ubuntu:/work/sambashare/rk3399/linux-6.3# cp -af ${KMODULES_OUTDIR}/lib/modules/* /work/sambashare/rk3399/rootfs/ubuntu/lib/modules
root@ubuntu:/work/sambashare/rk3399/linux-6.3# ll /work/sambashare/rk3399/rootfs/ubuntu/lib/modules
drwxr-xr-x   3 root root 4096 23 12:18 6.3.0/
3、制作ext4根文件系统镜像
3.1初始化

建立根文件系统挂载点ubuntu_rootfs

root@ubuntu:/work/sambashare/rk3399/rootfs# mkdir ubuntu_rootfs

创建空镜像文件ubuntu_ext4_rootfs.img,大小6144(设置为文件系统大小x2),具体需要的大小可以通过du build -h查看我们根文件系统大小调整;

root@ubuntu:/work/sambashare/rk3399/rootfs# dd if=/dev/zero of=ubuntu_ext4_rootfs.img bs=1M count=6144
root@ubuntu:/work/sambashare/rk3399/rootfs# ll ubuntu_ext4_rootfs.img
-rw-r--r-- 1 root root 6442450944 May 30 20:53 ubuntu_ext4_rootfs.img
root@ubuntu:/work/sambashare/rk3399/rootfs# mkfs.ext4 ubuntu_ext4_rootfs.img

dd: Unix/Linux 下的一个低级数据复制命令,常用于创建镜像、备份和恢复数据。

if=/dev/zero: 输入文件 (if) 是 /dev/zero,这是一个特殊的设备文件,它会无限输出零值。也就是说,所有数据都将是 0。

of=ubuntu_ext4_rootfs.img: 输出文件 (of) 是 ubuntu_ext4_rootfs.img,也就是将生成的数据写入到这个文件中。这个文件将是一个包含 0 的空白镜像文件。

bs=1M: 每次读写的块大小为 1 MB (bs 表示 block size)。这决定了 dd 每次从 /dev/zero 读取和写入的块大小是 1 MB。

count=6144: 表示复制 6144 个块,每个块的大小为 1 MB。所以生成的文件总大小为 6144 MB,即 6 GB。

mkfs.ext4:表示使用 ext4 文件系统格式化镜像文件。

ubuntu_ext4_rootfs.img:目标镜像文件。它将被格式化为 ext4 文件系统。

3.2 挂载

将该镜像文件挂载到ubuntu_rootfs

root@ubuntu:/work/sambashare/rk3399/rootfs# mount ubuntu_ext4_rootfs.img ubuntu_rootfs/

然后将ubuntu的文件复制到该空文件夹中:

root@ubuntu:/work/sambashare/rk3399/rootfs# cp ./ubuntu/* ./ubuntu_rootfs/ -af

注意:记得是copy ubuntu 中所有文件/文件夹

-a:归档模式,表示递归地复制所有文件和目录,同时保留文件的属性(如时间戳、权限、链接等)。等价于 -dR --preserve=all

-f:强制复制,表示如果目标文件已存在,直接覆盖而不提示。

使用df命令可以查看是否已经挂载:

root@ubuntu:/work/sambashare/rk3399/rootfs# df ubuntu_rootfs
文件系统         1K-块    已用    可用 已用% 挂载点
/dev/loop12    6102624 3804372 1967296   66% /work/sambashare/rk3399/rootfs/ubuntu_rootfs
3.3卸载

将之前挂载的卸载掉:

root@ubuntu:/work/sambashare/rk3399/rootfs# umount ubuntu_rootfs
root@ubuntu:/work/sambashare/rk3399/rootfs# ll ubuntu_rootfs/
总用量 8
drwxr-xr-x 2 root root 4096 May 30 20:57 ./
drwxr-xr-x 5 root root 4096 May 30 20:58 ../

此时我们已经得到了ext4根文件系统镜像ubuntu_ext4_rootfs.img

root@ubuntu:/work/sambashare/rk3399/rootfs# ll ubuntu_ext4_rootfs.img
-rw-r--r-- 1 root root 6442450944 May 30 21:05 ubuntu_ext4_rootfs.img

删除文件夹ubuntu_rootfs

root@ubuntu:/work/sambashare/rk3399/rootfs# rm -rf ubuntu_rootfs

e2fsck修复及检测镜像文件系统,resize2fs减小镜像文件的大小;

root@ubuntu:/work/sambashare/rk3399/rootfs# e2fsck -p -f ubuntu_ext4_rootfs.img
root@ubuntu:/work/sambashare/rk3399/rootfs# resize2fs -M ubuntu_ext4_rootfs.img
root@ubuntu:/work/sambashare/rk3399/rootfs# ll ubuntu_ext4_rootfs.img
-rw-r--r-- 1 root root 4323823616 May 30 21:08 ubuntu_ext4_rootfs.img
root@ubuntu:/work/sambashare/rk3399/rootfs# du -sh ubuntu_ext4_rootfs.img
3.8G    ubuntu_ext4_rootfs.img

最终得到的ext4根文件系统镜像ubuntu_ext4_rootfs.img大小为1.1G

Q1:创建image对象失败

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方式:重新烧录一遍RK3399官方的miniloader.bin (下载好的MiniLoaderAll.bin)

补充:

安装udhcpc gcc

root@liu-virtual-machine:/# apt-get install gcc
root@liu-virtual-machine:/# gcc -v

Q2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

4、扩容磁盘

(1)查看emmc块设备文件

ls /dev/mmc* -lha

root@liu:/home/XXXX# ls /dev/mmc* -lha
brw-rw---- 1 root disk 179,  0 Jun 18 04:29 /dev/mmcblk1
brw-rw---- 1 root disk 179, 32 Jun 18 04:29 /dev/mmcblk1boot0
brw-rw---- 1 root disk 179, 64 Jun 18 04:29 /dev/mmcblk1boot1
brw-rw---- 1 root disk 179,  1 Jun 18 04:29 /dev/mmcblk1p1
brw-rw---- 1 root disk 179,  2 Jun 18 04:29 /dev/mmcblk1p2
brw-rw---- 1 root disk 179,  3 Jun 18 04:29 /dev/mmcblk1p3
brw-rw---- 1 root disk 179,  4 Jun 18 04:29 /dev/mmcblk1p4
brw-rw---- 1 root disk 179,  5 Jun 18 04:29 /dev/mmcblk1p5
brw-rw---- 1 root disk 179, 96 Jun 18 04:29 /dev/mmcblk1rpmb

这里一共有9个块设备节点;其中:

  • /dev/mmcblk1表示的是eMMC这个设备,其主设备号为179,次设备号为0
  • mmcblk0boot0mmcblk0boot1对应两个Boot Area Partition;每一个Boot Area Partition大小都是4MB
  • mmcblk0rpmb则为RPMB Partition;大小为4MB
  • mcblk0pxUser Data Area划分出来的SW Partitions;实际上就是通过解析GPT分区表创建的分区,分区编号依次为1,2,3,4,5

使用cat /proc/partitions,可以查看全部分区信息:

root@liu:/home/XXXX# cat /proc/partitions
major minor  #blocks  name

   1        0       4096 ram0
 179        0   15267840 mmcblk1
 179        1       4000 mmcblk1p1
 179        2       4096 mmcblk1p2
 179        3       4096 mmcblk1p3
 179        4     114688 mmcblk1p4
 179        5   15136751 mmcblk1p5
 179       96       4096 mmcblk1rpmb
 179       64       4096 mmcblk1boot1
 179       32       4096 mmcblk1boot0

其中blocks表示分区的容量,每个blocks1KB。这里:

  • mmcblk1p1对应loader1分区,大小为4000KB
  • mmcblk1p2对应loader2分区,大小为4MB
  • mmcblk1p3对应trust分区,大小为4MB
  • mmcblk1p4对应boot分区,大小为112MB
  • mmcblk1p5对应rootfs分区,大小为剩余所有空间; 15136751 / 1024 /1024 = 14G

查看磁盘空间:

df -hT

root@liu:/home/XXXX# df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/root      ext4      1.7G  1.1G  524M  68% /
devtmpfs       devtmpfs  957M     0  957M   0% /dev
tmpfs          tmpfs     965M     0  965M   0% /dev/shm
tmpfs          tmpfs     193M  1.3M  192M   1% /run
tmpfs          tmpfs     5.0M     0  5.0M   0% /run/lock
tmpfs          tmpfs     965M     0  965M   0% /sys/fs/cgroup
tmpfs          tmpfs     193M     0  193M   0% /run/user/1000

显示内容参数说明:

  • Filesystem:文件系统;
  • Type:文件系统类型;
  • Siz: 分区大小;
  • Used: 已使用容量;
  • Avail: 还可以使用的容量;
  • Use%: 已用百分比;
  • Mounted on: 挂载点;

这里我们可以看到根目录挂载在/dev/root设备节点上,文件系统格式是ext4/dev/root其实就是/dev/mmcblk0p5,也就是eMMC设备的rootfs分区;

我们可以通过resize2fs指令调整ext2ext3ext4文件系统的大小,以便利用分区中的额外空间或者缩小文件系统来适应较小的分区大小:

root@liu:/home/XXXX# resize2fs /dev/mmcblk1
mmcblk1       mmcblk1boot1  mmcblk1p2     mmcblk1p4     mmcblk1rpmb
mmcblk1boot0  mmcblk1p1     mmcblk1p3     mmcblk1p5
root@liu:/home/XXXX# resize2fs /dev/mmcblk1p5
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/mmcblk1p5 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 2
The filesystem on /dev/mmcblk1p5 is now 3784187 (4k) blocks long.

root@liu:/home/XXXX# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        15G  1.1G   13G   8% /
devtmpfs        957M     0  957M   0% /dev
tmpfs           965M     0  965M   0% /dev/shm
tmpfs           193M  1.3M  192M   1% /run
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           965M     0  965M   0% /sys/fs/cgroup
tmpfs           193M     0  193M   0% /run/user/1000

需要烧录自动扩容:

需要找到自启动脚本是哪个?

只需要在/etc下增加rc.local文件增加其可执行权限即可。
修改文件系统:
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ./mnt_ubuntu.sh -m ubuntu/
MOUNTING
root@liu-virtual-machine:/# cd etc/
root@liu-virtual-machine:/etc# vi rc.local 
root@liu-virtual-machine:/etc# cat rc.local 
#!/bin/bash -e

resize2fs /dev/mmcblk1p5
touch /home/XXXX/version.txt
echo "V1.0.0.0" >> /home/XXXX/version.txt
root@liu-virtual-machine:/etc#chmod +x rc.local
5、制作打包脚本加载扩容指令
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# vi package_rootfs.sh
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# cat package_rootfs.sh 
#!/bin/bash

mkdir ubuntu_rootfs
dd if=/dev/zero of=ubuntu_ext4_rootfs.img bs=1M count=6144
mkfs.ext4 ubuntu_ext4_rootfs.img
mount ubuntu_ext4_rootfs.img ubuntu_rootfs/
cp ./ubuntu/* ./ubuntu_rootfs/ -af
df ubuntu_rootfs
umount ubuntu_rootfs
rm -rf ubuntu_rootfs
e2fsck -p -f ubuntu_ext4_rootfs.img
resize2fs -M ubuntu_ext4_rootfs.img
du -sh ubuntu_ext4_rootfs.img
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# chmod +x package_rootfs.sh
root@liu-virtual-machine:/home/liu/rockchip/rootfs/another_way_qemu/rootfs# ./package_rootfs.sh 
6144+0 records in
6144+0 records out
6442450944 bytes (6.4 GB, 6.0 GiB) copied, 8.55838 s, 753 MB/s
mke2fs 1.44.1 (24-Mar-2018)
Discarding device blocks: done                            
Creating filesystem with 1572864 4k blocks and 393216 inodes
Filesystem UUID: 60b18a42-7934-491f-ab07-d924286868ba
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done 

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/loop17      6102624 1212908   4558760  22% /home/liu/rockchip/rootfs/another_way_qemu/rootfs/ubuntu_rootfs
ubuntu_ext4_rootfs.img: 24860/393216 files (0.1% non-contiguous), 350435/1572864 blocks
resize2fs 1.44.1 (24-Mar-2018)
Resizing the filesystem on ubuntu_ext4_rootfs.img to 535498 (4k) blocks.
The filesystem on ubuntu_ext4_rootfs.img is now 535498 (4k) blocks long.

1.3G	ubuntu_ext4_rootfs.img

6、优化用户权限
root@liu:/home# ls -lh
total 8.0K
drwxr-xr-x 2 XXXX XXXX 4.0K Sep 29  2024 XXXX
drwxr-xr-x 3 XXXX XXXX 4.0K Jun 18 04:30 XXXX

第一个字母d表示这是一个目录
接下来的三个字符 rwx 表示所有者(owner)的权限:读(r)、写(w)、执行(x)。
接下来的三个字符 r-x 表示同组用户(group)的权限:读(r)、执行(x),没有写权限。
最后三个字符 r-x 表示其他用户(others)的权限:读(r)、执行(x),没有写权限

同组用户:	root@liu:/home# groups XXXX
            XXXX: XXXX
            root@liu:/home# groups XXXX
            XXXX: XXXX
要求XXXX目录不可被其他用户访问:(虚拟机操作)
root@liu-virtual-machine:/home# chmod 750 XXXX/
root@liu-virtual-machine:/home# ls -lh
total 8.0K
drwxr-xr-x 2 XXXX XXXX 4.0K Sep 29 10:04 XXXX
drwxr-x--- 2 XXXX XXXX 4.0K Sep 27 18:08 XXXX

参考:https://www.cnblogs.com/zyly/p/17442055.html 侵权删

韦东山老师为啥要录升级版嵌入式视频?200x年左右,嵌入式Linux在全世界、在中国刚刚兴起。我记得我2005年进入中兴时,全部门的人正在努力学习Linux。在2008年,我写了一本书《嵌入式Linux应用开发完全手册》。它的大概内容是:裸机、U-boot、Linux内核、Linux设备驱动。那时还没有这样讲解整个系统的书,芯片厂家Linux开发包也还不完善,从bootloader到内核,再到设备驱动都不完善。有全系统开发能力的人也很少。于是这书也就恰逢其时,变成了畅销书。我也根据这个思路录制了视频:裸机、U-boot、Linux内核、Linux设备驱动。收获些许名声,带领很多人进入Linux世界。11年过去了,嵌入式Linux世界发生了翻天覆地的变化① 基本系统能用芯片厂家都会提供完整的U-boot、Linux内核、芯片上硬件资源的驱动。方案厂家会做一些定制,比如加上某个WIFI模块,会添加这个WIFI模块的驱动。你可以使用厂家的原始方案,或是使用/借鉴方案商的方案,做出一个“能用”的产品。② 基础驱动弱化;高级驱动专业化基础的驱动,比如GPIO、UART、SPI、I2C、LCD、MMC等,有了太多的书籍、视频、示例代码,修修改改总是可以用的。很多所谓的驱动工程师,实际上就是“调参工程师”。我们群里有名的火哥,提出了一个概念:这些驱动就起一个“hardware enable”的作用。高级的驱动,比如USB、PCIE、HDMI、MIPI、GPU、WIFI、蓝牙、摄像头、声卡。体系非常复杂,很少有人能讲清楚,很多时候只是一笔带过。配置一下应用层工具就了事,能用就成。这些高级驱动,工作中需要专门的人来负责,非常专业。他们是某一块的专家,比如摄像头专家、音频专家。③ 项目为王你到一个公司,目的是把产品做出来,会涉及APP到内核到驱动全流程。中小公司玩不起华为中兴的配置,需要的是全面手。大公司里,只负责很小很小一块的镙丝钉,位置也不太稳固啊。所以,如果你不是立志成为某方面的专家,那就做一个全栈工程师吧。④ 调试很重要都说代码是3分写7分调,各种调试调优技术,可以为你的升职加薪加一把火。基于上述4点,我录制的全新视频将有这些特点:1. 快速入门,2. 实战项目,3. 驱动大全,4. 专题,5. 授人以渔,6. 要做任务另外,我们会使用多款芯片同时录制,先讲通用的原理,再单独讲各个板子的操作。这些芯片涵盖主流芯片公司的主流芯片,让你学习工作无缝对接。1.快速入门入门讲究的是快速,入门之后再慢慢深入,特别是对于急着找工作的学生,对于业余时间挑灯夜读的工作了的人,一定要快!再从裸机、U-boot、内核、驱动这样的路线学习就不适合了,时间就拉得太长了。搞不好学了后面忘了前面。并且实际工作中并不需要你去弄懂U-boot,会用就行:U-boot比驱动还复杂。讲哪些内容?怎么讲呢?混着讲比如先讲LED APP,知道APP怎么调用驱动,再讲LED硬件原理和裸机,最后讲驱动的编写。这样可以快速掌握嵌入式Linux的整套开发流程,不必像以前那样光学习裸机就花上1、2个月。而里面的裸机课程,也会让你在掌握硬件操作的同时,把单片机也学会了。讲基础技能中断、休眠-唤醒、异步通知、阻塞、内存映射等等机制,会配合驱动和APP来讲解。这些技能是嵌入式Linux开发的基础。而这些驱动,只会涉及LED、按制、LCD等几个驱动。掌握了这些输入、输出的驱动和对应的APP后,你已经具备基本的开发能力了。讲配置我们从厂家、从方案公司基本上都可以拿到一套完整的开发环境,怎么去配置它?需要懂shell和python等配置脚本。效果效率优先以前我都是现场写代码、现场写文档,字写得慢,降低了学习效率。这次,效果与效率统一考虑,不再追求所有东西都现场写。容易的地方可先写好代码文档,难的地方现场写。2.实战项目会讲解这样的涉及linux网关/服务器相关项目(不限于,请多提建议):                   定位为:快速掌握项目开发经验,丰满简历。涉及的每一部分都会讲,比如如果涉及蓝牙,在这里只会讲怎么使用,让你能写出程序;如果要深入,可以看后面的蓝牙专题。3. 驱动大全包括基础驱动、高级驱动。这些驱动都是独立成章,深入讲解。虽然基础驱动弱化了,但是作为Linux系统开发人员,这是必备技能,并且从驱动去理解内核是一个好方法。在讲解这些驱动时,会把驱动的运行环境,比如内核调度,进程线程等概念也讲出来,这样就可以搭建一个知识体系。没有这些知识体系的话,对驱动的理解就太肤浅了,等于在Linux框架下写裸机,一叶障目,不见泰山。定位为:工具、字典,用到再学习。4. 专题想深入学习的任何内容,都可独立为专题。比如U-boot专题、内核内存管理专题、systemtap调试专题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值