嵌入式Linux的AXI平台(platform)驱动教程

news2024/11/7 7:34:02

本文以JFMQL100的Linux系统的AXI接口的平台驱动为例,介绍嵌入式Linux的平台驱动编写、测试软件编写以及验证方式。本文的方法适用于任意嵌入式芯片Linux的物理地址映射的平台(platform)驱动的编写、测试与应用。

       本文中AXI的开始地址为0x80000000,长度为0x20008KB)的地址空间进行地址映射。Vivado中查看AXI的地址范围如下所示:

图1 AXI地址映射

        本文PL-PS的中断(IRQ_F2P[0]),提醒PS端进行AXI数据读取。该中断在进口ZYNQ7的中断号为61,在JFMQL100TAI的中断号为57。在Linux系统设备树配置上均需要中断号减32,即ZYNQ7的中断号配置为29,JFMQL100TAI的中断号配置为25

图2  PL-PS的IRQ_F2P中断使能

1 设备树修改

在设备树的根节点添加自定义的axi驱动节点,如下所示:

图3 添加自定义的axi平台驱动

2 驱动源码

1.新建axi驱动目录,如下图所示:

图4 新建custom_axi_driver目录

2.在axi驱动目录下,新建axi驱动源文件custom_axi_driver.c,驱动源文件如下所示:

图5 新建custom_axi_driver.c的源文件

#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/version.h>
#include <linux/io.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/delay.h>
 
#include <linux/string.h>
#include <linux/uaccess.h>

#include <linux/errno.h>    
#include <linux/interrupt.h>
#include <linux/init.h>

#include <linux/of_address.h>
#include <linux/of_dma.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>


#define DEVICE_NAME "custom_axi_driver"

#define AXI_BASE_ADDR_LEN       0x4000
#define AXI_BASE_ADDR           0x80000000

enum IOCTL_CMD
{
    CMD_GET_FPGA_VERSION = 10,      //获得FPGA版本号 10
    CMD_GET_FPGA_TEMP ,             //获得FPGA温度   11
    CMD_READ_REG,                   //读axi寄存器,单个寄存器操作  12
    CMD_WRITE_REG                   //写axi寄存器,单个寄存器操作  13
};

void __iomem *axi_base_addr;        //ioremap映射的虚拟地址

/*定义一个平台*/
typedef struct axi_struct
{
    int major;
    struct class            *axi_class;     //
    struct device           *axi_class_dev; //设备
    struct cdev             axi_cdev;       //cdev 结构
    struct file_operations  *drv_fops;      //操作函数接口
    char                    axi_name[20];   //设备名称
    struct platform_device  *pdev;          //平台设备
    struct device_node      *nd;            //设备节点
}struct_axi_driver,*ptstruct_axi_driver;

static dev_t dev_id; //设备编号
static int irq; //中断号

static struct fasync_struct *irq_async;
//设备打开
static int custom_axi_open(struct inode *inode, struct file *file)
{
	
    printk(KERN_INFO"%s axi_open!!\n",__FUNCTION__);
   
    return 0;
}
//设备关闭
static int custom_axi_release(struct inode *inode, struct file *file)
{
   
    printk(KERN_INFO"%s axi_release!!\n",__FUNCTION__);
    
    return 0;
}
//设备写
static ssize_t custom_axi_write(struct file *flip,const char __user *buf,size_t cnt,loff_t *offt)
{
    unsigned int start_addr = 0;
    unsigned int len = 0;


    if(copy_from_user(&start_addr, buf, sizeof(unsigned int)))
    {
        printk(KERN_ERR"%s copy_from_user is error!!\n",__FUNCTION__);
        return -1;
    }


    if(copy_from_user(&len, buf + sizeof(unsigned int), sizeof(unsigned int)))
    {
        printk(KERN_ERR"%s copy_from_user is error!!\n",__FUNCTION__);
        return -1;
    }

    if(len <= AXI_BASE_ADDR_LEN)
    {
        if(copy_from_user((unsigned int *)(axi_base_addr + start_addr), buf + sizeof(unsigned int)+ sizeof(unsigned int), len))
        {
            printk("%s copy_from_user is error!!\n",__FUNCTION__);
            return -1;
        }
    }
    else
    {
        printk("%s write num beyond AXI_ADDRESS_LEN!!\n",__FUNCTION__);
        return -1;
    }

    return len;
}
//设备读
static ssize_t custom_axi_read(struct file *flip, char __user *buf, size_t cnt, loff_t *offt)
{

    unsigned int start_addr = 0;
    unsigned int len = 0;

    if(copy_from_user(&start_addr, buf, sizeof(unsigned int)))
    {
        printk(KERN_ERR"%s copy_from_user start_addr is error!!\n",__FUNCTION__);
        return -1;
    }
	
    if(copy_from_user(&len, buf + sizeof(unsigned int), sizeof(unsigned int)))
    {
        printk(KERN_ERR"%s copy_from_user len is error!!\n",__FUNCTION__);
        return -1;
    }

    if(len <= AXI_BASE_ADDR_LEN)
    {
        if(copy_to_user(buf + sizeof(unsigned int) + sizeof(unsigned int), (unsigned int *)(axi_base_addr + start_addr), len) != 0)
        {
            printk(KERN_ERR"copy to user error!!\n");
            return -1;
        }
    }
    else
    {
        printk("%s read num beyond AXI_ADDRESS_LEN!!\n",__FUNCTION__);
        return -1;
    }

	return len;
}
//设备IO Control
static long custom_axi_ioctl(struct file *flip, unsigned int cmd, unsigned long arg)
{
    void __user *argp = (void __user *)arg;
    unsigned int reg_value = 0;

    unsigned int reg_addr = 0;

    switch(cmd)
    {
        case CMD_GET_FPGA_VERSION://读FPGA版本号
                reg_value=__raw_readl(axi_base_addr);
                if(copy_to_user(argp,(unsigned int *)&reg_value ,sizeof(unsigned int)))
                {

                    printk("%s copy_to_user is error!!\n",__FUNCTION__);
                    return -1;
                }
                break;

        case CMD_GET_FPGA_TEMP://读FPGA温度
                reg_value=__raw_readl((axi_base_addr + sizeof(unsigned int)));
                if(copy_to_user(argp,(unsigned int *)&reg_value ,sizeof(unsigned int)))
                {

                    printk("%s copy_to_user is error!!\n",__FUNCTION__);
                    return -1;
                }
                break;
        case CMD_READ_REG://读axi寄存器
                if(copy_from_user((unsigned int *)&reg_addr,argp,sizeof(unsigned int)))
                {
                    printk("%s copy_from_user is error!!\n",__FUNCTION__);
                    return -1;
                }

                reg_value=__raw_readl((axi_base_addr + reg_addr));
                if(copy_to_user(argp + sizeof(unsigned int),(unsigned int *)&reg_value ,sizeof(unsigned int)))
                {

                    printk("%s copy_to_user is error!!\n",__FUNCTION__);
                    return -1;
                }
                break;
        case CMD_WRITE_REG://写axi寄存器
                if(copy_from_user((unsigned int *)&reg_addr,argp,sizeof(unsigned int)))
                {
                    printk("%s copy_from_user is error!!\n",__FUNCTION__);
                    return -1;
                }

                if(copy_from_user((unsigned int *)&reg_value,argp+sizeof(unsigned int),sizeof(unsigned int)))
                {
                    printk("%s copy_from_user is error!!\n",__FUNCTION__);
                    return -1;
                }
                __raw_writel(reg_value,(axi_base_addr + reg_addr));
                break;
        default:
                break;
    }
 
    return sizeof(unsigned int);//返回操作字节数
}
//中断
static int irq_drv_fasync (int fd, struct file *filp, int on)
{
	return fasync_helper (fd, filp, on, &irq_async);
}

//中断触发函数
static irqreturn_t irq_interrupt(int irq, void *dev_id)
{

	kill_fasync (&irq_async, SIGIO, POLL_IN);
	return 0;
}

struct file_operations axi_fops = {
    .owner = THIS_MODULE,
    .open = custom_axi_open,
    .release = custom_axi_release,
    .read = custom_axi_read,
    .write = custom_axi_write,
    .fasync = irq_drv_fasync,
    .unlocked_ioctl = custom_axi_ioctl
};

static int custom_axi_probe(struct platform_device *pdev)
{
    int ret;

    ptstruct_axi_driver pt_axidriver = NULL;
    
    printk("axi probe start!\n");
   
    /***********************************************************************
     * register character device    
    ***********************************************************************/
    printk("axi-reg-driver: register  device...\n");

    pt_axidriver = (ptstruct_axi_driver)kmalloc(sizeof(struct_axi_driver),GFP_KERNEL);
    if (pt_axidriver == NULL)
    {
        printk(KERN_ERR"%s kmalloc is error!\n",__FUNCTION__);
        return -1;
    }
    axi_base_addr = ioremap(AXI_BASE_ADDR, AXI_BASE_ADDR_LEN);//映射本地地址
    if (!axi_base_addr) 
    {
        printk(KERN_ERR"%s ioremap AXI_base is error!!\n",__FUNCTION__);
        goto error5;
    }

    pt_axidriver->pdev = pdev;
    platform_set_drvdata(pdev, pt_axidriver);

    pt_axidriver->drv_fops = &axi_fops;
    strcpy(pt_axidriver->axi_name,DEVICE_NAME);


    /*从系统获取主设备编号*/
    ret = alloc_chrdev_region(&dev_id, 0, 5, pt_axidriver->axi_name);
    if (ret < 0)
    {
        printk(KERN_ERR"cannot alloc_chrdev_region!\n");
        goto error4;
    }
    pt_axidriver->major = MAJOR(dev_id);

    printk("MAJOR dev is successed!\n");
    
    cdev_init(&pt_axidriver->axi_cdev , &axi_fops); //初始化axi结构,fops

    printk("axi_cdev init!\n");
    
    if(cdev_add(&pt_axidriver->axi_cdev , dev_id, 5) != 0)
    {
        printk(KERN_ERR"add axi error\n");
        goto error3;
    }

    printk("axi_cdev add ok!\n");

    pt_axidriver->axi_class = class_create(THIS_MODULE, pt_axidriver->axi_name);
    if(pt_axidriver->axi_class==NULL)
    {
        printk(KERN_ERR"creat axi class error\n");
        goto error2;
    }
    
    printk("axi_cdev class init!\n");

    pt_axidriver->axi_class_dev = device_create(pt_axidriver->axi_class, NULL, MKDEV(pt_axidriver->major, 0), NULL, pt_axidriver->axi_name);
    if(pt_axidriver->axi_class_dev == NULL)
    {
        printk(KERN_ERR"device_create is error!\n");
        goto error1;
    }
    printk("axi_cdev class dev init!\n");
    
    irq = platform_get_irq(pdev,0);
	if (irq <= 0)
    {
        goto error0;
    }
	
    printk("system irq  = %d\n", irq);
    //申请上升沿中断触发
    ret = request_irq(irq,
                irq_interrupt,
                IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                pt_axidriver->axi_name, NULL);
	if (ret) 
    {
		printk(KERN_ERR"irq_probe irq	error!\n");
        goto error0;
	}

    return 0;

    free_irq(irq, NULL);
error0:
    device_destroy(pt_axidriver->axi_class,MKDEV(pt_axidriver->major, 0));
error1:
    class_destroy(pt_axidriver->axi_class);
error2:
    cdev_del(&pt_axidriver->axi_cdev);   //移除字符设备
error3:
    unregister_chrdev_region(dev_id, 5);
error4:
    iounmap(axi_base_addr);//释放地址映射
error5:
    kfree(pt_axidriver);
    return -1;
}

static int  custom_axi_remove(struct platform_device *pdev)
{
    ptstruct_axi_driver  pt_axidriver = (ptstruct_axi_driver)platform_get_drvdata(pdev);
    
    free_irq(irq, NULL);//释放中断
    device_destroy(pt_axidriver->axi_class,MKDEV(pt_axidriver->major, 0));
    class_destroy(pt_axidriver->axi_class);
    cdev_del(&pt_axidriver->axi_cdev);       //移除字符设备
    unregister_chrdev_region(dev_id, 5);    //释放设备
    iounmap(axi_base_addr);                 //释放axi虚拟地址映射
    kfree(pt_axidriver);                    //释放驱动

    return 0;
}

/*定义,初始化平台驱动*/
static const struct of_device_id custom_axi_of_match[] = {
    {.compatible = "lsl,custom_axi_driver"},
    {},
};
MODULE_DEVICE_TABLE(of, custom_axi_of_match);
static struct platform_driver custom_axi_platform_driver = {
    .driver = {
        .name = "custom_axi_driver",
        .of_match_table = custom_axi_of_match,
    },
    .probe = custom_axi_probe,
    .remove = custom_axi_remove,
};

module_platform_driver(custom_axi_platform_driver);



MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("lsl custom_axi_driver platform driver");
MODULE_AUTHOR("LSL");

3.在axi驱动目录下,新建Makefile文件,Makefile文件中指定内核源码路径。如下图所示:

图6 新建Makefile文件
图7 Makefile文件内容
图8 给Makefile文件添加可执行权限

4.在axi驱动目录下,新建编译脚本build.sh,编译脚本内容如下所示:

图9 新建编译脚本
图10 编译脚本build.sh内容
图11  编译脚本添加可执行权限

5.运行编译脚本,对驱动进行动态编译,生成驱动的ko文件custom_axi_driver.ko,编译结果如下所示:

图12 生成驱动的ko文件

 3 驱动测试程序

1.新建驱动测试程序目录app_driver_test,如下图所示:

图13 新建app_driver_test目录

2.在驱动测试目录下,新建驱动测试软件app_driver_test.c,驱动测试源文件如下图所示:

图14 新建app_driver_test.c的源文件

3.在驱动测试目录下,新建驱动测试软件app_driver_test.c,驱动测试源文件如下图所示:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <linux/ioctl.h>
#include "app_driver_test.h"



int pl_axi_fd;
static int irq_count = 0;

int axi_writeReg(unsigned int reg,unsigned int value, unsigned int axi_offset_addr)
{
    
    Axi_CtrlRwStruct Axi_CtrlRwStructure;
    int ret;

    Axi_CtrlRwStructure.reg_addr=REG_ADDR(reg)+axi_offset_addr;
    Axi_CtrlRwStructure.reg_value=value;

    
    ret = ioctl(pl_axi_fd,CMD_WRITE_REG,&Axi_CtrlRwStructure);  
    if(ret<0)
    {
        printf("axi_writeReg addr %xis error!\n",Axi_CtrlRwStructure.reg_addr);
        return -1;
    
    }
    return ret;
}

int axi_readReg(unsigned int reg,unsigned int *value,unsigned int axi_offset_addr)
{

    int ret=0;
    Axi_CtrlRwStruct Axi_CtrlRwStructure;

    Axi_CtrlRwStructure.reg_addr=REG_ADDR(reg)+axi_offset_addr;
   
	ret = ioctl(pl_axi_fd,CMD_READ_REG,&Axi_CtrlRwStructure);  
    if(ret<0)
    {
        printf("axi_readReg addr %xis error!\n",Axi_CtrlRwStructure.reg_addr);
        return -1;
       
    }
    *value=Axi_CtrlRwStructure.reg_value;
    return ret;
}


int axi_GetFpga_Version(unsigned int *version)
{
    unsigned int buf;
    int ret;
   
	ret = ioctl(pl_axi_fd,CMD_GET_FPGA_VERSION,&buf);  
    if(ret<0)
    {
        printf("axi_GetFpga_Version is error!\n");
        return -1;
      
    }
    *version=buf;
    return ret;
}


int axi_GetFpga_Temp(unsigned int *temp)
{
    unsigned int buf;
    int ret;

	ret = ioctl(pl_axi_fd,CMD_GET_FPGA_TEMP,&buf);  
    if(ret<0)
    {
        printf("axi_GetFpga_Temp is error!\n");
        return -1;

    }
    *temp=buf;
    return ret;
}

int axi_writeData(unsigned int start_addr, unsigned int len, unsigned char *value)
{
    int ret;
    Axi_DataRwStruct Axi_DataRwStructure;
    
    if(len>MAX_DATA_BUFF_SIZE)
    {
        printf("write the data len beyond Max buffer!\n");
        
        return -1;
    }
    Axi_DataRwStructure.start_addr=(start_addr/4)*4;//开始地址4字节对齐
    Axi_DataRwStructure.len=(len/4)*4;//长度4字节对齐

    memcpy(Axi_DataRwStructure.buff,value,Axi_DataRwStructure.len);

	ret=write(pl_axi_fd, &Axi_DataRwStructure, Axi_DataRwStructure.len+2*sizeof(unsigned int));
    if(ret<0)
    {
        printf("axi_writeData is error!\n");
        
        return -1;
    }
    return ret;
}

int axi_readData(unsigned int start_addr, unsigned int len, unsigned char *value)
{
    int ret;
    Axi_DataRwStruct Axi_DataRwStructure;
    
    if(len>MAX_DATA_BUFF_SIZE)
    {
        printf("read the data len beyond Max buffer!\n");
        
        return -1;
    }
    Axi_DataRwStructure.start_addr=(start_addr/4)*4;//开始地址4字节对齐
    Axi_DataRwStructure.len=(len/4)*4;//长度4字节对齐
   
	ret=read(pl_axi_fd, &Axi_DataRwStructure, Axi_DataRwStructure.len+2*sizeof(unsigned int));
    if(ret<0)
    {
        printf("axi_readData is error!\n");
        return -1;
    }

    memcpy(value,Axi_DataRwStructure.buff,ret);

    return ret;
} 

void pl_axi_device_init(void)
{
	int Oflags; 

	pl_axi_fd = open(PL_AXI_DEV, O_RDWR);
	if (pl_axi_fd < 0)
    {
        printf("can't open PL_AXI_DEV!\n");
	}

	fcntl(pl_axi_fd, F_SETOWN, getpid());
	
	Oflags = fcntl(pl_axi_fd, F_GETFL); 
	
	fcntl(pl_axi_fd, F_SETFL, Oflags | FASYNC);
	

}

void sigio_irq_service(int signum)
{
    irq_count+=1;
    printf("recv the irq_count=%d\n",irq_count);//打印irq中断计数
    
}  

void pl_sigio_irq_init(void)
{
	signal(SIGIO, sigio_irq_service);//注册irq服务函数
}

//main入口函数
int main(int argc, char **argv)
{
    unsigned int ver,temp;//定义版本号和温度的变量
    unsigned int reg_in=0x5aa51234;
    unsigned int reg_out;
    unsigned char data_in[12]={1,2,3,4,5,6,7,8,9,10,11,12};
    unsigned char data_out[12];
    unsigned int i,flag;

    pl_sigio_irq_init(); //中断使能
	pl_axi_device_init();//pl_axi设备打开
    axi_GetFpga_Version(&ver);
    printf("the fpga version is=0x%x\n",ver);//打印版本号
    axi_GetFpga_Temp(&temp);
    printf("the fpga temp is=0x%x\n",temp);//打印温度
    while(1)
    {
        axi_writeReg(8,reg_in, 0);//向8号寄存器写入reg_in的值
        axi_readReg(8,&reg_out,0);
        if(reg_in==reg_out)//判断读写寄存器函数是否正确
        {
            printf("write read reg is right!\n");
        }
        else
        {
            printf("write read reg is error!\n");
        }
        axi_writeData(8,sizeof(data_in),data_in);//向8号寄存器写入连续的数据
        axi_readData(8,sizeof(data_out),data_out);
        for(i=0;i<sizeof(data_out);i++)
        {
            if(data_in[i]!=data_out[i])//判断读写寄存器函数是否正确
            {
                flag=1;
                printf("write read data is error!\n");
            }
           
        }
        if(flag==0)
           printf("write read data is right!\n"); 
    }

	return 0;
}

4.在axi驱动目录下,新建app_driver_test.h的头文件。头文件内容如下图所示:

图15 app_driver_test.h头文件

5.在axi驱动测试程序目录下,新建Makefile文件,Makefile指定交叉编译器环境变量。如下图所示:

图16 新建Makefile文件
图17 Makefile文件内容

6.在axi驱动目录下,新建编译脚本build.sh,编译脚本内容如下所示:

图18 新建编译脚本
图19 编译脚本build.sh内容
图20 编译脚本添加可执行权限

7.运行编译脚本,对驱动测试程序进行编译,生成驱动测试程序的可执行文件app_driver_test,编译结果如下所示:

图21 生成可执行文件

4 驱动与测试软件的验证

1.拷贝驱动ko文件和驱动测试程序可执行文件到嵌入式系统的工作目录下。

tftp -g -r custom_axi_driver.ko 192.168.0.11

tftp -g -r app_driver_test 192.168.0.11

chmod +x app_driver_test

图22 驱动和测试软件的下载

2.驱动加载

insmod custom_axi_driver.ko

图23 驱动程序加载

3.运行嵌入式程序的可执行文件。

./app_driver_test

图24 驱动程序测试,获得AXI的信息

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Visual Studio Code(VSCode)中编写 TypeScript 代码

在 Visual Studio Code&#xff08;VSCode&#xff09;中编写 TypeScript 代码通常需要以下配置&#xff1a; 一、安装必要的扩展 TypeScript 插件&#xff1a;由微软官方提供&#xff0c;提供了语法高亮、错误检查、代码补全等功能。 二、配置 tsconfig.json 文件&#xff08;…

视频设备一体化监控运维方案

随着平安城市、雪亮工程等项目建设的号召&#xff0c;视频监控系统的建设如火如荼地开展。无论在公共场所、企业单位、住宅小区、矿山工地还是交通枢纽&#xff0c;视频监控系统已成为保障安全、维护秩序和提升管理效率的重要工具。但由于对视频监控系统中的前端设备&#xff0…

第十八章 Vue组件样式范围配置之scoped

目录 一、引言 二、案例演示 2.1. 工程结构图 2.2. 核心代码 2.2.1. main.js 2.2.2. App.vue 2.2.3. BaseOne.vue 2.2.4. BaseTwo.vue 2.3. 运行效果 2.4. 调整代码 2.4.1. BaseTwo.vue 2.4.2. 运行效果 三、scoped原理 一、引言 前面的几个章节在介绍组件的时…

可口可乐三季报 | 数字化助力,营收超预期 | ​eBest

可口可乐公司近日公布了2024年第三季度业绩报告。报告特别强调了数字技术&#xff0c;尤其是AI人工智能对推动增长的重要作用。 第三季度&#xff0c;可口可乐公司交出了一份亮眼的成绩单&#xff0c;营收和每股收益均超出市场预期&#xff0c;显示出公司业务的强大韧性和长期…

书生大模型实战营 L0 入门岛

书生大模型训练营入门岛任务——训练营链接 1. Linux前置知识 任务&#xff1a;端口转发 当使用vscode远程连接服务器时&#xff0c;在服务器运行的任务&#xff0c;vscode会自动帮忙进行端口映射&#xff0c;方便本地进行访问。 2. Python前置知识 任务1&#xff1a;Leec…

配置mysql 主主模式 GTID

文章目录 一、前提二、修改my.cnf主1 10.255.131.9主2 10.255.131.10 三、配置主主3.1 配置主 10.255.131.93.2 配置从 10.255.131.103.3 配置主 10.255.131.103.4 配置从 10.255.131.9 四、验证五、同步问题排查以及恢复5.1 查看同步状态5.2 查看同步是否数据一致性&#xff0…

【Vulnhub靶场】DC-5

DC-5靶机下载地址&#xff1a; https://download.vulnhub.com/dc/DC-5.zip 目标 本机IP&#xff1a;192.168.118.128 靶机IP&#xff1a;192.168.118.0/24 信息收集 扫描存活主机&#xff0c;扫描端口&#xff0c;扫描服务 第一步使用nmap扫描出目标IP为&#xff1a;192.168…

docker 安装kuboard

mkdir /root/kuboard-data docker run --restartunless-stopped -p 8453:80 -d --name kuboard -e KUBOARD_AGENT_SERVER_TCP_PORT8453 -e KUBOARD_ENDPOINThttps://192.168.31.177 -v /root/kuboard-data:/data eipwork/kuboard:v3http://192.168.31.177:8453/ 默认账号&…

SpringBoot和弦:创建Web音乐网站指南

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理音乐网站的相关信息成为必然。开发合适的音…

LinkedList和链表(下)

1. 什么是LinkedList 在练习了单链表的自我实现和单链表的一些习题之后,我们正式来认识一下java提供的LinkedList,这是一种双向链表结构,在增删元素的时候效率比较高,不需要像ArrayList一样搬运元素.但是在查找方面效率比较低(需要遍历链表),ArrayList效率就比较高(直接由数组下…

DevOps赋能:优化业务价值流的实战策略与路径(下)

下篇&#xff1a;加速工作项流动与持续改进优化 —— 跨越差距&#xff0c;迈向卓越交付 在上篇中&#xff0c;我们已经深入探讨了看板方法的四大核心实践&#xff0c;它们共同致力于实现“顺畅且高质量地交付价值”的终极目标。然而&#xff0c;理想与现实之间往往存在一定的…

day14:RSYNC同步

一&#xff0c;概述 概述 rsync &#xff08;开源&#xff09;是一个高效的文件同步和传输工具&#xff0c;广泛用于 Linux 和 Unix 系统中。它可以在本地和远程系统之间同步文件和目录&#xff0c;同时支持增量备份&#xff0c;能够只传输更改过的文件部分&#xff0c;以减少…

Leaflet查询矢量瓦片偏移的问题

1、问题现象 使用Leaflet绘制工具查询出来的结果有偏移 2、问题排查 1&#xff09;Leaflet中latLngToContainerPoint和latLngToLayerPoint的区别 2&#xff09;使用Leaflet查询需要使用像素坐标 3&#xff09;经排查发现&#xff0c;container获取的坐标是地图容器坐标&…

JSP水果商城管理系统WEB项目

一、项目简介 > FruitsDay 是一个用于销售水果的WEB商城项目。 > 该项目主要通过Java和JSP实现&#xff0c;旨在帮助用户实现网购水果&#xff0c;并帮助商家管理水果库存。 > 项目采用Maven构建&#xff0c;使用JSP和Servlet实现&#xff0c;比较适合JAVA初学者…

Rust 力扣 - 1. 两数相加

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个全局的备忘录&#xff0c;然后我们遍历数组&#xff0c;如果当前元素在备忘录里面找到了&#xff0c;就返回备忘录里面记录的下标和当前下标记录&#xff0c;没找到就把当前元素匹配的元素和当前元素…

ssm016基于 Java Web 的校园驿站管理系统(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;校园驿站管理系统的设计与实现 摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好…

NCCL安装(Ubuntu等)

目录 一、NCCL的定义二、安装NCCL的原因1、加速多GPU通信2、支持流行的深度学习框架3、提高计算效率4、易于使用和集成5、可扩展性 三、NCCL安装方法1、下载安装包2、更新APT数据库3、使用APT安装libnccl2包&#xff0c;另外&#xff0c;如果需要使用NCCL编译应用程序&#xff…

Spring的IOC技术(配置文件形式)

目录 一、什么是IOC 二、IOC的程序入门 1.创建mavenJava项目&#xff0c;引入依赖 2.编写接口和实现类 3.编写spring核心配置文件(applicationContext.xml) 4.测试类 5.测试结果-------一个对象 三、Spring框架的Bean管理的配置文件 四、实例化Bean对象的三种方式 1.无…

论文阅读(三十二):EGNet: Edge Guidance Network for Salient Object Detection

文章目录 1.Introduction2.Related Works3.Salient Edge Guidance Network3.1Complementary information modeling3.1.1Progressive salient object features extraction3.1.2Non-local salient edge features extraction 3.2One-to-one guidance module 4.Experiments4.1Imple…

深度学习:卷积神经网络中的img2col

im2col 是一种在卷积神经网络&#xff08;CNN&#xff09;中常用的技术&#xff0c;用于将输入图像数据转换为适合卷积操作的矩阵形式。通过这种转换&#xff0c;卷积操作可以被高效地实现为矩阵乘法&#xff0c;从而加速计算。 在传统的卷积操作中&#xff0c;卷积核&#xff…