系统移植一

使用设备是fs4412开发板

一、系统移植

  • 系统移植是将一个操作系统或软件从一个硬件平台或处理器架构转移到另一个平台的过程。系统移植的主要目标是使软件在新的硬件环境下能够正常运行。
  • 在系统移植过程中,主要的改动集中在硬件相关的底层部分以及操作系统的核心模块。
二、主要步骤
1.嵌入式环境搭建
  1. 在嵌入式开发中,通常使用交叉编译工具将源代码编译成目标平台(例如ARM架构)的可执行代码。
  2. 示例
sudo apt-get install gcc-arm-none-eabi
该工具将帮助你将代码编译为ARM架构指令集。
  1. TFTP协议
  • TFTP是一种简单的文件传输协议,用于嵌入式系统中通过网络传输文件。它通常用于传输启动文件和固件。
  • 安装TFTP工具
sudo apt-get install tftpd-hpa tftp-hpa
  • 配置TFTP服务器: 编辑配置文件
sudo vi /etc/default/tftpd-hpa

确保如下配置

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"  # 创建该目录并设置权限:chmod 777 /tftpboot
# 这是TFTP服务器的根目录。所有通过TFTP传输的文件将被限制在这个目录中。
# 我设置的是/home/ubuntu/tftpboot
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-c -s -l"

  • 重启TFTP服务器
sudo service tftpd-hpa restart
  • 测试TFTP服务器
    • tftp 127.0.0.1连接TFTP服务器
    • 使用get filename下载文件
    • 使用put filename上传文件
    • 使用quit退出
      在这里插入图片描述
  1. NFS协议(Network File System)
  • NFS允许网络上的文件系统像本地文件一样被访问,常用于嵌入式系统开发中通过网络加载根文件系统。
    1. 安装NFS服务器
    sudo apt-get install nfs-kernel-server
    
    1. 配置NFS导出的目录: 编辑/etc/exports文件,在底部添加要导出的目录,NFS 服务器可以指定哪些目录可以被客户端访问,以及每个目录的访问权限和规则。
    sudo vi /etc/exports
    
    我设置的是
    /home/lsf/source/rootfs *(rw,sync,no_root_squash,no_subtree_check)
    //所有客户端
    
    1. 重启NFS服务器
    sudo service nfs-kernel-server restart
    
    1. 测试:在另一个终端上,作为客户端进行测试
cd /mnt/ 
mkdir testdir  # 创建挂载点
sudo mount -t nfs 127.0.0.1:/home/ubuntu/rootfs ./testdir
//是将本地NFS服务器上导出的目录 /home/ubuntu/rootfs 挂载到本地的 ./testdir 目录。

断开连接

sudo umount ./testdir

在这里插入图片描述

2. 三大件移植
  • 在嵌入式系统中,移植主要涉及三大件:Bootloader、操作系统、文件系统。以下是常见的三大件的对比和流程:
  1. Bootloader
    Bootloader是系统启动的第一阶段,负责加载操作系统内核。在PC中,BIOS扮演这个角色,而在嵌入式系统中,常用u-boot作为bootloader。

    • PC: BIOS启动 -> 加载Windows操作系统 -> 加载文件系统
    • Android: Recovery模式 -> 加载Android操作系统 -> 文件系统
    • 嵌入式系统: u-boot -> 加载Linux操作系统 -> 文件系统
  2. 操作系统(OS)
    嵌入式系统的操作系统通常为Linux。在移植过程中,需要针对目标平台的处理器架构、内存管理和外设驱动进行修改和适配。典型的流程包括:

  • 修改内核源代码以支持目标硬件。
  • 编译内核并通过Bootloader加载到内存中执行。
  1. 文件系统(FS)
    文件系统负责管理系统中的文件和目录。在嵌入式系统中,文件系统通常存储在NAND Flash、SD卡等非易失性存储设备上。常见的嵌入式文件系统包括ext4、jffs2、squashfs等。
  • 文件系统移植:根据目标平台的存储设备,选择合适的文件系统,并通过NFS或TFTP加载。
  1. 嵌入式系统整体移植流程
  • 使用交叉编译工具生成可执行的Bootloader和操作系统。
  • 配置TFTP或NFS用于传输和挂载根文件系统。
  • 将Bootloader(如u-boot)移植到目标平台,并通过它加载Linux内核。
  • 通过NFS、TFTP或其他方式加载并挂载文件系统。

bootloader

  • Bootloader 是系统启动加载器的统称,用于加载操作系统(OS)。它在嵌入式系统中起到了关键作用,尤其是在系统损坏时,可以通过 Bootloader 进行系统修复或重新刷机。
  • 作用:
    • 系统启动:Bootloader 在开机后执行部分硬件初始化,准备加载操作系统。
    • 系统修复:当系统损坏时,可以通过 Bootloader 进入交互模式,进行系统的修复或重新刷机。
    • 双系统管理:支持双系统的设备可以通过 Bootloader 选择要启动的系统。
    • 硬件初始化:在加载操作系统之前,Bootloader 需要初始化关键硬件组件,如内存、CPU 时钟、外设等,以确保操作系统的正常启动。

工作过程

  • Bootloader 通常分为两个阶段
    • 第一阶段(汇编级别)
      • 启动与硬件初始化:在系统加电后,Bootloader 负责执行最初的硬件初始化,如设置 CPU 时钟、初始化内存控制器、配置堆栈指针等。
      • 跳转到 C 语言代码:完成最基本的硬件设置后,控制权会跳转到用 C 语言编写的第二阶段 Bootloader。
    • 第二阶段(C 语言阶段)
      • 进一步的硬件初始化:在 C 语言代码中,Bootloader 完成更多复杂的硬件初始化,如网络、串口、存储设备等外设的配置。
      • 引导过程:根据设定的启动命令和环境变量,Bootloader 加载操作系统内核和设备树,并将控制权交给操作系统。
U-Boot 概述
  • U-Boot(Universal Bootloader)是一款广泛用于嵌入式系统中的开源 Bootloader,支持多种 CPU 架构,如 ARM、PowerPC、x86、MIPS 等。它体积小、功能强大,广泛用于嵌入式系统启动和调试。
  • U-Boot 与其他 Bootloader 的对比:
    • BIOS(通常用于 PC):大约 300MB,功能强大,带有图形用户界面。
    • Recovery 模式(用于 Android):大约 3.5MB,功能一般,界面较为简单。
    • U-Boot:大约 200KB,功能足够,提供字符界面,非常适合嵌入式设备使用。
使用U-boot

U-Boot 提供了丰富的环境变量和命令,用于配置和控制启动过程。下面是 U-Boot 的常用功能和命令介绍:

  1. U-Boot 环境变量

    • U-Boot 通过环境变量存储启动时的配置信息,用户可以查看、修改和保存这些变量。
    baudrate=115200:串口通信的波特率设置。
    bootargs:Linux 内核的启动参数,指定文件系统的加载方式、控制台设置、IP 配置等。
    bootcmd:定义了 U-Boot 启动后要执行的命令序列,用于加载操作系统。
    ipaddr:开发板的 IP 地址。
    serverip:TFTP 服务器的 IP 地址。
    
  2. 设置环境变量

setenv 变量名 值

例如,设置 Linux 内核启动参数:

setenv bootargs root=/dev/nfs nfsroot=192.168.2.64:/home/ubuntu/source/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.2.245
//这条命令告诉 Linux 使用 NFS 作为根文件系统,并通过 UART2 输出控制台信息。
//ttySAC2 表示控制台将输出到串口2。
//bootargs 是一个特殊的环境变量,表示内核启动时的参数。
//root=/dev/nfs:指定根文件系统的路径。表示根文件系统位于一个 NFS(Network File System)服务器上,而不是在本地存储设备上.这意味着在系统启动时,它将通过网络挂载一个远程文件系统作为根文件系统。
//nfsroot 参数用于指定 NFS 服务器的IP地址和路径。
//rw:指定根文件系统为可读写(read-write)。这意味着启动后的系统能够对根文件系统进行写操作。
//init=linuxrc 指定启动时内核将运行的初始程序。
//ip=192.168.2.245:这个参数用于指定启动时设备的 IP 地址。
  1. 保存环境变量: 将修改后的环境变量保存到 Flash,这样环境变量在下次启动时依然有效。
saveenv
  1. U-Boot 命令集
printenv
setenv 变量名 值
saveenv
bootm//启动操作系统内核的命令,支持传递设备树文件和文件系统。
help//查看所有可用的 U-Boot 命令及其简要说明。
ping serverIP //测试网络连接(Ping 服务器 IP)
reset://重启开发板,可以通过该命令在 Bootloader 中进行软重启。
tftp 41000000 uImage
使用 TFTP 下载文件: U-Boot 支持通过 TFTP 协议下载文件,例如下载操作系统内核镜像 uImage 到 RAM 中的地址 41000000

bootm 41000000 - 42000000
启动内核(bootm 命令): bootm 命令用于启动操作系统。通常需要提供操作系统内核的地址、设备树文件(如果有)的地址。其中 41000000 是内核镜像的加载地址,42000000 是设备树的加载地址,- 表示没有提供文件系统镜像的地址。
U-Boot 启动过程的配置
  1. Bootargs 环境变量
    bootargs 是 U-Boot 传递给 Linux 内核的启动参数,定义了如何加载文件系统、IP 地址、控制台设置等。例如:
setenv bootargs root=/dev/nfs nfsroot=192.168.2.64:/home/ubuntu/source/rootfs rw console=ttySAC2,115200 init=linuxrc ip=192.168.2.245
  1. Bootcmd 环境变量
    bootcmd 定义了 U-Boot 启动后的操作步骤。
setenv bootcmd tftp 41000000 uImage;tftp 42000000 exynos4412-fs4412.dtb;bootm 41000000 - 42000000
//以下为解释
tftp 41000000 uImage:通过 TFTP 下载内核镜像到地址 41000000
tftp 42000000 exynos4412-fs4412.dtb:通过 TFTP 下载设备树文件到地址 42000000。
bootm 41000000 - 42000000:启动内核,并使用设备树文件。
  1. 常见的U-boot环境变量
  • bootdelay=1:设置启动延迟时间为 1 秒。
  • ethaddr:以太网 MAC 地址。
  • ipaddr:开发板的 IP 地址。
  • serverip:TFTP 服务器的 IP 地址。
  • netmask:子网掩码,通常为 255.255.255.0。
  • serverip:TFTP 服务器的 IP 地址,用于下载内核和其他启动文件。
  • fileaddr 和 filesize:这些变量用于指定下载文件的地址和大小。TFTP 下载完成后,U-Boot 会自动设置这些变量。
  • gatewayip:网关地址,通常在跨网络连接时使用。嵌入式系统中一般不需要配置网关。
  • stdin、stdout、stderr:定义标准输入、输出和错误的设备。通常这些值设置为 serial,表示通过串口进行输入输出操作。
  • Environment size:环境变量的大小,通常会有一个上限值(例如 16KB),并且会显示当前已使用的大小。
启动流程解读
  1. U-boot阶段
    • 启动 U-Boot,在开发板上上电启动后,U-Boot 启动并首先完成部分硬件的初始化。
    • 环境变量设置:根据设置的 bootargs 和 bootcmd,U-Boot 知道从哪里加载内核和文件系统
  2. TFTP 文件下载
    • 下载 uImage(内核镜像)
    • 下载设备树文件(.dtb 文件)
  3. 启动内核
    • 下载完成后,U-Boot 使用 bootm 命令启动内核,并传递设备树文件地址
  4. 加载根文件系统
    • 根据 bootargs 环境变量中的设置,Linux 内核知道通过 NFS 加载根文件系统
  5. 系统启动完成
  6. 注意事项
    • TFTP 和 NFS 的协同工作:
      • 在 U-Boot 中,TFTP 常用于加载内核镜像(uImage)和设备树文件(.dtb 文件),因为这类文件的体积较小,适合通过网络快速传输。
      • NFS 则用于加载较大的根文件系统,NFS 服务器能够提供一个远程文件系统,供 Linux 内核使用。这种方式在嵌入式开发中非常常见,因为不需要将文件系统写入 Flash,方便调试和更新。

u-boot的编译和移植

  • 从芯片原厂或开源社区获取,例如从官方获取 u-boot-2013.01 源码。
  • 在 Linux 环境下,使用以下命令解压 U-Boot 源代码
    tar -xvf u-boot-2013.01.tar.bz2
    
    • 解压完成后,将得到 u-boot-2013-xxx 目录,该目录为顶级目录,后续的所有操作(如编译、移植)都基于此目录进行。
U-Boot 目录结构说明
  • U-Boot 的源码目录结构非常清晰,分为 平台相关 和 平台无关 的部分。
平台相关的代码

这一部分包含与具体的硬件平台相关的代码,主要包括不同的 CPU 架构和开发板的实现代码。由于不同 CPU 和开发板的硬件资源和配置不同,U-Boot 针对每个平台都有对应的实现。

  • arch/arm/cpu/armv7
    • 这里是与 ARMv7 架构相关的代码,因为 fs4412 是基于 ARM Cortex-A9 的处理器,属于 ARMv7 架构。在这个目录中,你会看到与 ARMv7 架构的处理器相关的代码。
    • 包含处理器的初始化、时钟设置、缓存管理、启动等。
  • board/samsung/origen
    • 不同的开发板有各自的板级代码。由于 fs4412 是基于三星的芯片,因此对应的开发板代码在 board/samsung/origen 目录中。这个目录下的代码专门处理与 fs4412 硬件平台相关的初始化代码,如内存控制器、外设的初始化等。
  • include/configs/origen.h
    • 这个文件包含了与板子相关的配置宏。它定义了 fs4412 的硬件参数,如 DRAM 大小、串口波特率、启动设备等。
    • 通过修改这个文件,你可以调整板子启动时的一些行为,如 U-Boot 如何找到内核、如何配置网络等。
2.平台无关代码

这一部分代码与具体的硬件平台无关,提供了 U-Boot 的核心功能,如驱动程序、库、文件系统、网络协议等。无论你使用的是哪个平台,这些功能都是通用的。

  • api:与 API 调用相关的代码,U-Boot 提供了一些标准接口供开发者调用。
  • config.mk:U-Boot 编译时所使用的配置文件,定义了编译选项和目标文件等信息。
  • drivers:驱动程序目录,包含 U-Boot 所支持的各种硬件设备驱动,如串口、网卡、存储控制器等。
  • include:头文件目录,包含了 U-Boot 核心代码和硬件平台的头文件。
  • lib:与 U-Boot 核心库相关的代码,提供了标准的功能库。
  • fs:文件系统代码,支持各种嵌入式文件系统(如 FAT、EXT4、UBIFS 等),用于加载启动时的文件系统。
  • net:网络协议相关的代码,支持多种网络功能和协议,如 TFTP、DHCP、HTTP 等。
  • tools:编译和开发过程中所用的工具,包含一些 U-Boot 自身使用的工具程序。
  • dts:包含设备树(Device Tree Source)文件,设备树用于描述系统中的硬件配置。虽然设备树描述的是硬件信息,但设备树本身是一个通用机制,通常不依赖于特定的平台。
  • common/Makefile、rules.mk 和 config.mk:这些文件是 U-Boot 的编译系统文件,定义了如何编译 U-Boot 源代码。它们定义了各种目标和规则,以便在不同平台上编译 U-Boot。
  • 等待
u-boot的编译
  • U-Boot 的编译必须在 顶层目录 下进行,所有操作都基于这个目录进行。以下是完整的编译过程,包括配置、编译和清理步骤。
  1. 配置 U-Boot,指定板子
    在编译 U-Boot 之前,首先要为你的目标硬件板子(开发板)进行配置。这一步会根据板子生成相应的配置文件。
make <board_name>_config ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
//如果你当前系统是 x86_64,默认的 ARCH 是 x86 或 x86_64。
//ARCH=arm 表示你正在为 ARM架构 编译U-Boot。

//CROSS_COMPILE=arm-none-linux-gnueabi-  用于指定交叉编译器的前缀。
//交叉编译器是指在一种平台上编译运行于另一种平台的代码的编译器。
//构建系统将使用这个工具链来编译生成适合ARM架构的可执行文件和镜像。

针对Origen开发板的配置命令

make origen_config ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
  1. 编译 U-Boot
    在完成配置后,开始进行编译。编译的命令如下:
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

这个命令会根据之前配置的板子生成 U-Boot 可执行文件。编译过程会创建多个中间文件(如 .o 文件),并在顶层目录生成最终的 U-Boot 二进制文件。

  1. 编译结果
    编译完成后,在 U-Boot 顶层目录下会生成以下文件
  • u-boot.bin:U-Boot 可执行文件,可以烧录到开发板的 Flash 或通过 TFTP 加载运行。
  • u-boot.img(可选):有些平台可能生成 u-boot.img,用于更加复杂的启动场景。
  • tools/mkimage:这是一个重要的工具,用于将内核、设备树、文件系统等打包成 U-Boot 可识别的格式。在后续操作中会用到这个工具来生成引导映像。
  1. 清理编译
    • make clean
      • 该命令会清除编译过程中生成的所有中间文件(如 .o 文件)。但它保留了配置文件(即第1步的板子配置),因此你不需要重新配置板子。
      • 适用于你已经配置好环境,之后只想重新编译的情况。
    • make distclean
      • 该命令会清除所有生成的文件,包括中间文件和配置文件。也就是说,执行 distclean 后,你需要重新配置板子才能再次编译。
      • 适用于你需要彻底清理整个项目环境的情况。
u-boot移植

目的:将支持 Origen 开发板的 U-Boot 源码移植到 fs4412 开发板,使其可以正确运行并支持该硬件平台。

移植步骤
  1. 拷贝 Origen 开发板的代码到 fs4412
    U-Boot 的板子相关代码通常位于 board/samsung 目录下,包含硬件初始化等与板子密切相关的代码。为了让 fs4412 开发板能够正确运行 U-Boot,需要基于现有的 Origen 代码进行修改。
    执行以下命令将 Origen 板子的代码复制到 fs4412 板子
cp -a board/samsung/origen board/samsung/fs4412
//将 board/samsung/origen 目录及其内容递归地复制到 board/samsung/fs4412 目录中。

将 origen.c 文件重命名为 fs4412.c,因为 fs4412 和 origen 板子的硬件配置不同,需要在代码中进行相应的调整:

mv board/samsung/fs4412/origen.c board/samsung/fs4412/fs4412.c

编辑 board/samsung/fs4412/Makefile,将其中的 origen.o 修改为 fs4412.o,以便编译时生成正确的对象文件

vi board/samsung/fs4412/Makefile
//将obj-y += origen.o改为obj-y += fs4412.o
  1. 拷贝配置文件并修改
    U-Boot 的配置文件通常位于 include/configs 目录下,每个开发板都有自己的配置文件,里面定义了诸如内存大小、串口设置、时钟配置等信息。我们需要复制 Origen 的配置文件,并为 fs4412 进行相应的修改。
    将 Origen 的配置文件复制为 fs4412 的配置文件
cp include/configs/origen.h include/configs/fs4412.h

接下来,需要打开 include/configs/fs4412.h,根据 fs4412 的硬件配置进行调整。常见的调整项包括:
- 内存配置(如 DRAM 大小)
- 串口配置
- 启动设备(如从 NAND、MMC 启动等)

  1. 指定fs4412板子的相关信息
  • 在 U-Boot 中,boards.cfg 文件用于管理所有支持的开发板。这个文件定义了每个开发板的基本信息,如板子的名字、CPU 类型、供应商等。为了让编译系统识别 fs4412 板子,需要在 boards.cfg 中添加 fs4412 的相关信息。
  • 编辑 boards.cfg,可以复制一行 Origen 板子的配置,然后修改其中的名字、CPU 和其他相关信息。
vi boards.cfg//打开并编辑 boards.cfg
//找到 Origen 的配置行
//复制该行并修改为 fs4412 的配置

在这里插入图片描述

  1. 编译U-boot
    配置完成后,就可以编译 U-Boot 了。
    1. 配置板子
      • 首先使用 make 配置命令,根据 boards.cfg 文件中的信息为 fs4412 板子生成相关配置文件。
    make fs4412_config ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
    
    1. 编译 U-Boot
    make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
    
  2. 清理编译(如果需要清理编译过程中生成的文件)
    • 清理中间文件(保留配置文件)
      • make clean
    • 彻底清理(该命令会清除所有生成的文件,包括配置文件。)
      • make distclean
  3. 将 U-Boot 编译生成的 u-boot.bin 烧录到开发板上。
U-Boot 代码的启动过程

U-Boot 的启动分为两个阶段:汇编阶段和C 语言阶段。每个阶段负责特定的初始化任务,最终进入交互模式等待用户命令或加载操作系统。

  1. 汇编阶段:基本硬件初始化
  • 汇编阶段的主要任务是完成 CPU 和基本硬件的初始化,然后跳转到 C 语言代码。这个阶段的代码位于 arch/arm/cpu/armv7/start.S 文件中,汇编代码是执行启动的最初步骤。
  • 汇编启动流程
    • 入口点:当开发板上电启动时,程序执行的入口是 start.S 文件中的 reset 标签。
    b reset
    
    • reset 标签:
      该标签定义了程序启动的核心初始化部分,主要负责 CPU 和关键硬件的初始化。
      在这里插入图片描述
    • cpu_init_cp15:
      此函数主要用于初始化 CPU 内部的一些配置,包括 MMU(内存管理单元)、RAM、禁用 CPU 缓存等。这个初始化对于 ARM 平台的正常运行至关重要。
    • cpu_init_crit:
      该函数负责初始化开发板相关的硬件。在这里可能会调用板子特定的低级初始化代码。例如,可能调用位于 board/samsung/origen/lowlevel_init.S 的 lowlevel_init 函数。
      虽然可以自定义这个初始化函数以支持不同的硬件,但通常不推荐直接修改该部分代码,最好通过 U-Boot 提供的其他接口进行硬件初始化。
    • b _main
      当汇编部分的初始化完成后,跳转到 C 语言部分进行更多的初始化工作。这个跳转是通过 b _main 完成的,_main 是 arch/arm/lib/crt0.S 中定义的入口点。
  1. C 语言阶段:系统初始化与交互模式
    当 U-Boot 从汇编阶段进入 C 语言阶段后,开始进行更高级的硬件初始化工作,包括调用板子相关的函数、进行自拷贝操作等,最终进入 U-Boot 的交互模式。
    C 语言启动流程
    • _main 函数
      • 位于 arch/arm/lib/crt0.S 文件中,_main 函数是 C 语言阶段的入口点。
      • 主要任务是设置堆栈、初始化板子特定的硬件,并最终启动交互模式。
    • board_init_f:
      • 该函数位于 arch/arm/lib/board.c 文件中,主要是初始化与板子相关的硬件资源。
      • 在这个过程中,会调用板子特定的初始化函数。例如,如果你的板子是 fs4412,系统会调用位于 board/samsung/fs4412/fs4412.c 中的函数。你可以在这些文件中进行板子级别的初始化。
      • 在 board_init_f 函数执行时,系统还没有完全从 Flash 自拷贝到 RAM,因此它的作用是设置好基本的外设,确保后续可以从 RAM 中运行。
    • 自拷贝
      • U-Boot 的自拷贝机制是在启动时将自身从 Flash 拷贝到 RAM 中。这是因为 RAM 的访问速度比 Flash 更快,运行效率更高。
      • 自拷贝操作通常在 C 语言阶段完成,完成后程序会跳转到 RAM 中继续执行。
    • board_init_r
      • 完成自拷贝后,程序会跳转到 board_init_r,这个函数位于 arch/arm/lib/board.c 中。它负责进一步的初始化工作,完成剩余的硬件初始化,并最终进入 U-Boot 的交互模式。
void board_init_r(gd_t *id, ulong dest_addr)
{
    // 其他初始化操作...
    for (;;)
    {
        main_loop();  // 进入 U-Boot 的命令行交互模式
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/889724.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

低代码工单管理app评测,功能与效率解析

预计到2030年&#xff0c;低代码平台市场将达1870亿美元。ZohoCreator助力企业构建定制化软件应用&#xff0c;以建筑行业工作订单管理app为例&#xff0c;简化流程&#xff0c;提升管理效率&#xff0c;降低成本。其用户友好界面、自动化管理、跨平台使用及全面报告功能受企业…

【高频SQL基础50题】31-35

又到SQL。 目录 1.查询结果的质量和占比 2.求关注者的数量 3.指定日期的产品价格 4.好友申请 II &#xff1a;谁有最多的好友 5.按日期分组销售产品 1.查询结果的质量和占比 聚合题。 # Write your MySQL query statement below SELECT t1.query_name,ROUND((SUM(t1.r…

【Linux探索学习】第四弹——Linux权限管理详解:理解用户、组和权限之间的关系

前言&#xff1a; 在前面我们已经学习了Linux的基础指令&#xff0c;相信大家对Linux已经有了一定的认识&#xff0c;今天我们来学习Linux权限的相关知识点&#xff0c;Linux权限是Linux初学者必须要掌握的内容 目录 一、Linux下用户类型 二、权限基本概念 三、权限的表示 四…

WebGoat JAVA反序列化漏洞源码分析

目录 InsecureDeserializationTask.java 代码分析 反序列化漏洞知识补充 VulnerableTaskHolder类分析 poc 编写 WebGoat 靶场地址&#xff1a;GitHub - WebGoat/WebGoat: WebGoat is a deliberately insecure application 这里就不介绍怎么搭建了&#xff0c;可以参考其他…

数据结构修炼——树?二叉树?堆?从入门到代码实现,第一弹!!!

目录 一、树的概念与结构1.1 树的概念1.2 树的相关概念1.3 树的表示及实际应用 二、二叉树概念及结构2.1 二叉树的概念2.2 特殊的二叉树2.2.1 满二叉树2.2.2 完全二叉树 2.3 二叉树的存储结构 三、二叉树的顺序结构与实现3.1 堆的概念及结构3.2 堆的实现3.2.1 堆的创建与销毁3.…

安卓13禁止用户打开开发者选项 android13禁止用户打开开发者选项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.编译6.彩蛋1.前言 设置 =》关于平板电脑 =》版本号,一般的话,在这里连续点击就可以打开我们的开发者选项了。但是有些系统要进行保密,因此要禁止用户进入。 2.问题分析 这里我们是通过点…

Android Framework AMS(02)AMS启动及相关初始化5-8

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要涉及systemserver启动AMS及初始化AMS相关操作。同时由于该部分内容过多&#xff0c;因此拆成2个章节&#xff0c;本章节是第二章节&…

【技术】Jaskson的序列化与反序列化

文章目录 概念解释1.Jasksona.JSONJSON 的基本特点JSON 的基本结构JSON 示例 b.ObjectMapper类 2.序列化与反序列化a.序列化对象序列化集合序列化ListSetMap b.反序列化反序列化单个对象反序列化集合对象 概念解释 1.Jaskson Jackson 是一个用于处理 JSON 数据的 Java 库,所以…

vue-插槽作用域实用场景

vue-插槽作用域实用场景 1.插槽1.1 自定义列表渲染1.2 数据表格组件1.3 树形组件1.4 表单验证组件1.5 无限滚动组件 1.插槽 插槽感觉知道有这个东西&#xff0c;但是挺少用过的&#xff0c;每次看到基本都会再去看一遍用法和概念。但是在项目里&#xff0c;自己还是没有用到过…

基于SpringBoot+Vue的疫情物资管理系统(带1w+文档)

基于SpringBootVue的疫情物资管理系统(带1w文档) 基于SpringBootVue的疫情物资管理系统(带1w文档) 本课题研究和开发疫情物资管理系统管理系统&#xff0c;让安装在计算机上的该系统变成管理人员的小帮手&#xff0c;提高疫情物资管理系统信息处理速度&#xff0c;规范疫情物资…

C++入门基础知识107—【关于C++continue 语句】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C continue 语句的相关内容&#xff01;…

关于Java部署项目,文件上传路径问题 、Windows是\ linux是/

Windows是\ linux是/ &#xff0c;踩坑。报错如下&#xff1a;

SpringBootWeb快速入门!详解如何创建一个简单的SpringBoot项目?

在现代Web开发中&#xff0c;SpringBoot以其简化的配置和快速的开发效率而受到广大开发者的青睐。本篇文章将带领你从零开始&#xff0c;搭建一个基于SpringBoot的简单Web应用~ 一、前提准备 想要创建一个SpringBoot项目&#xff0c;需要做如下准备&#xff1a; idea集成开发…

信息安全工程师(28)机房安全分析与防护

前言 机房安全分析与防护是一个复杂而细致的过程&#xff0c;涉及到物理安全、环境控制、电力供应、数据安全、设备管理、人员管理以及紧急预案等多个方面。 一、机房安全分析 1. 物理安全威胁 非法入侵&#xff1a;未经授权的人员可能通过门窗、通风口等进入机房&#xff0c;…

《大规模语言模型从理论到实践》第一轮学习笔记

第一章 绪论 本章主要介绍大规模语言模型基本概念、发展历程和构建流程。 大规模语言模型&#xff08;Large Language Models&#xff0c;LLM&#xff09;&#xff0c;也称大语言模型 或大型语言模型。 1.1 大规模语言模型基本概念 1.语言模型&#xff08;Language Model&a…

LeetCode 3310. 移除可疑的方法

LeetCode 3310. 移除可疑的方法 你正在维护一个项目&#xff0c;该项目有 n 个方法&#xff0c;编号从 0 到 n - 1。 给你两个整数 n 和 k&#xff0c;以及一个二维整数数组 invocations&#xff0c;其中 invocations[i] [ai, bi] 表示方法 ai 调用了方法 bi。 已知如果方法 k…

Leetcode 37. 解数独

1.题目基本信息 1.1.题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 33 宫内只能出现一次。&#xff08;请参考…

文件IO及目录操作

一、文件IO 1.1 close函数&#xff08;关闭文件&#xff09; #include <unistd.h>---所需头文件 int close(int fd); 功能&#xff1a;关闭文件 参数&#xff1a;fd&#xff1a;文件描述符 返回值&#xff1a;成功返回0&#xff0c;失败返回-1&#xff0c;置位错误码 …

主机加固的关键要素:服务器防病毒

在数字化浪潮中&#xff0c;网络安全已成为企业不可忽视的一环。尤其是安全运维人员&#xff0c;他们肩负着保护企业数据不受侵害的重任。MCK主机加固解决方案&#xff0c;正是为了应对这一挑战而生。 网络安全的严峻现实 不久前&#xff0c;一家知名企业因勒索病毒攻击而被迫…

二分查找一>0~n-1中缺失的数字(点名)

1.题目&#xff1a; 2.解析&#xff1a;方法一&#xff1a;用哈希表&#xff1a;记录存在的数字&#xff0c;找到哈希表为空的数字输出 Set<Integer> set new HashSet<>();for(int x : records) set.add(x);for(int i 0; i < set.size(); i){if(!set.contain…