116.龙芯2k1000-pmon(15)- 只修改env部分

既然前面已经研究了gzrom-dtb.bin的生成

从这期开始,将研究如何通过linux下的app修改gzrom.bin在flash中的内容。

本期第一步,既然要修改env的字节部分,

那首先得有一个自己要有env.bin,所以就要想办法生成一个

这个文件包含了自己想要的环境变量,但是又不想更新pmon的全部。

这里有风险:会造成存档pmon与实际运行的内容不一致的情况!!! (先忽略)

第一步:首先得有一个env的文件

之前分析过python的脚本(注意这个版本是Python 2.7.17),那直接改脚本似乎更简单粗暴吧:

要填充的环境变量写入到该文件最开始cmd的位置。

注意,每一对分成一个字符串。

python 复制代码
"""
python pmonenv.py -f gzrom.bin -o 0x70000 -s 512 al=/dev/mtd0 append="'root=/dev/mtdblock0'"
python ../tools/pmonenv.py -f gzrom-dtb.bin -d ls2k.dtb -w  al=/dev/ram@p0x110000000 al1=/dev/ram@p0x110000000 append="'console=ttyS0,115200 initcall_debug=1 loglevel=20 nosmp'" FR=1
"""

# cmd = {"al=/dev/ram@p0x110000000", "al1=/dev/ram@p0x110000000", "append='console=ttyS0,115200 initcall_debug=1 loglevel=20 nosmp' FR=1"}
cmd = {"al=(usb0,0)/boot/vmlinuz", "al1=(wd0,0)/vmlinuz", "append='console=ttyS0,115200 noinitrd root=/dev/sda2  rootfstype=ext4 rootwait rw'", "FR=1"}


import struct
import sys
import getopt
def readenv(argv): 
	d={}
	t = argv

	print(argv)
	for i in t:
		# print("i=",i)
		a=i.split('=',1)  
		# print("6 a = ",a)   # 7
		if len(a) > 1:     
			d[a[0]] = a[1]   
		elif a[0] in d:   
			del d[a[0]]
	# print("for end*******************\n")
	return d



# 2024-03-04
def creat_env_bin(fname,fsz,d):
	a=b'\x00\x00'   
	for i in d.keys():   
		a += i+b'='+d[i]+b'\x00' 
		# print("8 a = ",a)   # 9
	a += b'\x00'
	a=a.ljust(fsz,b'\xff')   
	b = struct.pack('!H',(-sum(struct.unpack('!'+str(len(a)//2)+'H',a)))&0xffff)
	# print("9 b = ",b)   # 10
	a=b+a[2:]
	# print("10 a = ",a)   # 11
	f=open(fname,'wb+')
	# f.seek(foff,0)
	f.write(a)  
	f.close()


    
if __name__ == '__main__':
	d=readenv(cmd)
	print(d) 
	creat_env_bin('env.bin',500,d)   

           

执行:(linux下)

python pmonenv_creat_evn_bin.py

注意python的版本是2.7

来看看生成的env.bin的情况

嘿嘿,成功,这个校验码与我们之前的一致。

那我们就可以随便修改了。

注意结束的位置是两个0,因为解析的时候需要判断0结束。

pmon 源码参考:GitHub - zhaozhi0810/pmon-ls2k1000-2022

为了区别原来的,随便加了一句,用于验证

cmd = {"al=(usb0,0)/boot/vmlinuz", "al1=(wd0,0)/vmlinuz", "append='console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'", "FR=1","author=zhaodazhi"}

第二步,写入env.bin,弄一个c程序

这里我选择在linux下直接写入,再读出来查看

程序写好了,附在文章末尾吧。

直接运行program_pmon_ls2k1000 能够把gzrom的内容读出来,生成gzrom-dtb-new.bin

准备做这些选项,目前还没做好

选项

-o gzrom-dtb-new.bin 读出flash中的程序(1m以内)

-e env.bin 写入env数据:要求有校验和+正确的格式

-d dtb.bin 写入dtb

-c gzrom-dtb.bin 比较flash中的与文件是否相同

gzrom-dtb.bin 直接写入gzrom-dtb.bin

没有参数,等同-o gzrom-dtb-new.bin

重启之后,看到自己加入的环境变量了,网卡的mac地址也是ff

说明成功了,yes!!!!

程序还不完整,后面继续改进。

程序包含两个源码:mymap.c,spi_w.c,Makefile

mymap.c

cpp 复制代码
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


/*

 	2024-03-02  by dazhi
	特别注意: ls2k1000 的pmon 不能大于1m ,因为它映射的空间就是1m以内

	env的起始位置0x1fcff000,大小498字节以内,还有2个字节的校验和,最大不能超过500字节
	dtb的起始位置0x1fcfb000,大小16k-8字节,8个字节留出来做校验和,最大不能超过16k
	gzrom的起始位置0x1fc00000,最大1004k字节。

	选项
	-o gzrom-dtb-new.bin 读出flash中的程序(1m以内)
	-e env.bin 写入env数据:要求有校验和+正确的格式
	-d dtb.bin  写入dtb
	-c gzrom-dtb.bin  比较flash中的与文件是否相同
	gzrom-dtb.bin 直接写入gzrom-dtb.bin 

 */


#define BIN_FILE_SIZE 1044980   //这是编译的gzrom-dtb.bin的大小



//extern int spiflash_main(char *cmd, unsigned long flashbase, unsigned long spiregbase, unsigned long spimem_base_map, ...);
//off 就是flash内部的偏移地址
extern int fl_erase_device(int off, int size, int verbose);

//off 就是flash内部的偏移地址
extern int fl_program_device(int off, void *data_base, int data_size, int verbose);

extern int set_spiflash_regaddr(unsigned long long spireg_base);


int PAGE_SIZE;
int PAGE_MASK;

#define FLASH_SIZE 0x500000



void printf_usage(char* name)
{
	printf("USAGE:\n");
	printf("%s [-o gzrom-dtb-new.bin] : read flash(1M) to  file gzrom-dtb-new.bin\n",name);
	printf("%s <-e env.bin> : write env.bin to flash offset 0xff000,size 500Bytes\n",name);
	printf("%s <-d dtb.bin> : write dtb.bin to flash offset 0xfb000,size 16KBytes\n",name);
	printf("%s <-c gzrom-dtb.bin> : compare flash(1M) and file gzrom-dtb.bin,the same or not the same\n",name);
	printf("others ,not support!!!!\n");
}





unsigned int flash_buf[FLASH_SIZE];
int main(int argc, char **argv)
{
	int fd,mem_fd,spimem_physaddr,spimem_map_len,spireg_physaddr,spireg_map_len,spireg_offset;
	void *spimem_base = NULL,*spireg_base= NULL,*buf=NULL;
	int i;
	int err;
	unsigned char* pbuf;
	int option = 0;   //0表示读出来
	char* filename = "gzrom-dtb-new.bin";   //文件名
	struct stat statbuf;


	if(argc > 3) //参数多余3个
	{
		printf_usage(argv[0]);
		return -1;
	}
	else if(argc == 2)
	{
		printf_usage(argv[0]);
		return -1;
	}
	else if(argc == 1)
	{
		option = 0;
	}
	else  //argc == 3
	{
		filename = argv[2];  //保存文件名;
		if(strcmp(argv[1], "-o")==0)
		{
			option = 0;
	
		}
		else if(strcmp(argv[1], "-e")==0)
		{
			option = 1;  //写环境变量 env

		}
		else if(strcmp(argv[1], "-d")==0)
		{
			option = 2;  //写dtb文件 

		}
		else if(strcmp(argv[1], "-c")==0)
		{
			option = 3;  //比较文件

		}
		else{  //其他不能识别
			printf_usage(argv[0]);
			return -1;
		} 
	}


    spimem_physaddr = 0x1fc00000;   //0x1d000000; //3a5000的地址   //0x1fc00000 2k1000的地址
    spimem_map_len = 0x100000;//1M


    PAGE_SIZE = getpagesize();
    PAGE_MASK = (~(PAGE_SIZE-1));


	mem_fd = open("/dev/mem", O_RDWR|O_SYNC);
    if(mem_fd == -1)
        error(-1,errno,"error open /dev/mem\n");

    //spi 内存读写方式
    spimem_base = mmap(0, spimem_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spimem_physaddr&PAGE_MASK);
    if(spimem_base == MAP_FAILED)
        error(err,errno,"spimem_base map failed.\n");


    spireg_physaddr = 0x1fff0220;//0x1fe001f0;    //0x1fff0220 2k1000的地址
    spireg_map_len = 0x1000; //4K
    spireg_offset = spireg_physaddr & (PAGE_SIZE-1);   //偏移地址

	spireg_base = (unsigned char*)mmap(NULL, spireg_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spireg_physaddr&PAGE_MASK);
    if(spireg_base == MAP_FAILED){
        error(err,errno,"spireg_base map failed.\n");
        return -1;
    }



    close(mem_fd);

    pbuf = spimem_base;

    printf("spireg_base = %p\n",spireg_base);
	set_spiflash_regaddr((unsigned long long) spireg_base + spireg_offset);

    // for(i=0;i<100;i++)
    // {
    //     printf("%02hhx ",pbuf[i]);
    //     if(i%16 ==15)
    //         printf("\n");
    // }

    //是读操作
    if(option == 0)  //读出flash的内容,大小BIN_FILE_SIZE个字节
    {
    	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC,0666);
		if(fd == -1)
		    error(err,errno,"error open file.\n");

		int ret =	write(fd,pbuf,BIN_FILE_SIZE);  //一次性写进去
		printf("read size = %d\n",ret);

		close(fd);
    }
    else if(option == 1) //写环境变量 env
    {
    	//1 打开env。bin文件,限制文件不能大于500字节
    	fd = open(filename, O_RDONLY);
	    if(fd == -1)
	        error(err,errno,"error open file. %s\n",filename);
    	
	    int size = lseek(fd,0,SEEK_END);  //长度
	    if(size > 500)
	    {
	    	printf("file size too large (len=%d > 500Bytes)\n",size);
	    	munmap(spimem_base,spimem_map_len);  
	    	close(fd);
	    	return -1;
	    }



		buf = mmap(0, 500, PROT_READ, MAP_SHARED, fd, 0);
		if(buf == MAP_FAILED)
			error(err,errno,"map failed.%s\n",filename);

		fl_erase_device(0xff000, size, 0);
		fl_program_device(0xff000, buf, size, 0);

		printf("erase and program down\n");
    }




//     int fd,mem_fd,physaddr,spimem_physaddr,spireg_physaddr;
//     void *mem = NULL, *spimem_base = NULL;
//     unsigned char *spireg_base;
//     int err,i,map_len,len,spimem_map_len,spireg_map_len;
//     char *filename = NULL, *buf = NULL, *devname = "/dev/mem";
//     struct stat statbuf;
//     if(argc < 2)
//         goto usage;
	
//     filename = argv[1];
    
//     PAGE_SIZE = getpagesize();
//     PAGE_MASK = (~(PAGE_SIZE-1));
    
//     physaddr = 0x1fc00000;
//     map_len = 0x100000;//1M
	
//     spimem_physaddr = 0x1fc00000;   //0x1d000000; //3a5000的地址   //0x1fc00000 2k1000的地址
//     spimem_map_len = 0x1000000;//16M
	
//     spireg_physaddr = 0x1fff0220;//0x1fe001f0;    //0x1fff0220 2k1000的地址
//     spireg_map_len = 0x1000; //4K
	
//     mem_fd = open(devname, O_RDWR|O_SYNC);
//     if(mem_fd == -1)
//         error(-1,errno,"error open /dev/mem\n");
	
//     mem = mmap(0, map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, physaddr&PAGE_MASK);
//     if(mem == MAP_FAILED)
//         error(err,errno,"mem map failed.\n");
	
//     spimem_base = mmap(0, spimem_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spimem_physaddr&PAGE_MASK);
//     if(spimem_base == MAP_FAILED)
//         error(err,errno,"spimem_base map failed.\n");
	
//     spireg_base = (unsigned char*)mmap(NULL, spireg_map_len, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, spireg_physaddr&PAGE_MASK);
//     if(spireg_base == MAP_FAILED)
//         error(err,errno,"spireg_base map failed.\n");
    
// 	close(mem_fd);
	
//     printf("file name is: %s\n",filename);
//     if((err = stat(filename, &statbuf)) != 0)
//         error(err,errno,"error find file.\n");
    
// 	if(statbuf.st_size > FLASH_SIZE){
//         error(-1,0,"File size is too large.\n");
//         return -1;
//     }
	
//     fd = open(filename, O_RDONLY);
//     if(fd == -1)
//         error(err,errno,"error open file.\n");
	
//     buf = mmap(0, map_len, PROT_READ, MAP_SHARED, fd, 0);
//     if(buf == MAP_FAILED)
//         error(err,errno,"map failed.\n");
	
//     close(fd);
	
//     printf("file size is: %ld KB\n",(long)((statbuf.st_size)/1024));
//     //spiflash_main("iep",(unsigned long)mem, (unsigned long)(spireg_base+0x1f0),(unsigned long)spimem_base, 0, (unsigned long)statbuf.st_size, 0x1000, buf, 0, (unsigned long)statbuf.st_size);
	
// 	spiflash_main("i", (unsigned long)mem, (unsigned long)(spireg_base+0x220), (unsigned long)spimem_base, 0, (unsigned long)statbuf.st_size, 0x1000, buf, 0, (unsigned long)statbuf.st_size);

//     //memcpy(flash_buf,mem,statbuf.st_size);
//     memcpy(flash_buf, spimem_base, statbuf.st_size);
	
//     for(i=0;i<100;i++)
//     {
//         printf("%#hhx ",flash_buf[i]);
//         if(i%10 ==9)
//             printf("\n");
//     }

//     for(i=0;i<100;i++)
//     {
//         printf("%#hhx ",buf[i]);
//         if(i%10 ==9)
//             printf("\n");
//     }
    
//     if (memcmp(flash_buf, buf, statbuf.st_size))
//     {
// 	    printf("verify miscompare,exit flash program,please retry!!\r\n");
// 	    //exit(0);
//     }
// 	else
//     {

// 	    printf("verify mach OK, you can reboot!!\r\n");
//     }
	
//     munmap(mem,map_len);
//     munmap(spimem_base,spimem_map_len);
//     munmap(spireg_base,spireg_map_len);
//     munmap(buf,map_len);  
	
//     return 0;
	
// usage:
//     printf("usage: proparm filename.\n");
//     return -1;

	munmap(spimem_base,spimem_map_len);     
    return 0;
}

spi_w.c (从pmon中拷贝出来的,有改动)

cpp 复制代码
/*
* @Author: dazhi
* @Date:   2024-03-05 15:29:25
* @Last Modified by:   dazhi
* @Last Modified time: 2024-03-05 16:29:59
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//#include <pmon.h>
//#include <include/types.h>
//#include <pflash.h>

//#define SPI_BASE  0x1fff0220
//#define PMON_ADDR 0xa1000000
//
unsigned long long SPI_BASE;   //reg 的基地址
#define PAGE_SIZE_4K 0x1000    //4k
#define PAGE_MASK_4K (PAGE_SIZE_4K-1)

#define FLASH_ADDR 0x000000

#define SPCR      0x0
#define SPSR      0x1
#define TXFIFO    0x2
#define RXFIFO    0x2
#define SPER      0x3
#define PARAM     0x4
#define SOFTCS    0x5
#define PARAM2    0x6

#define WFFULL (1<<3)   //发送缓存满
#define RFEMPTY 1
#define KSEG1_STORE8(addr,val)	 *(volatile char *)(addr) = val
#define KSEG1_LOAD8(addr)	 *(volatile char *)(addr) 

#define SET_SPI(addr,val)        KSEG1_STORE8(SPI_BASE+addr,val)
#define GET_SPI(addr)            KSEG1_LOAD8(SPI_BASE+addr)
#define NEW_SPI_ZZ


static int delay(int value)
{
	int i, j;
	for (i = 0; i < value; i++) {
		for (j = 0; j < 1000; j++) {
			;
		}
	}

	return 0;
}


int set_spiflash_regaddr(unsigned long long spireg_base)
{   
    //寄存器的偏移地址
    SPI_BASE = spireg_base;
    printf("spi_base = %llx\n",SPI_BASE);
}




int write_sr(char val);
void spi_initw()
{ 
	//printf("11spi_base = %llx\n",SPI_BASE);
  	SET_SPI(SPSR, 0xc0);   
  	SET_SPI(PARAM, 0x40);    //这里没有读使能了         //espr:0100
 	SET_SPI(SPER, 0x05); //spre:01 
  	SET_SPI(PARAM2,0x01); 
  	SET_SPI(SPCR, 0x50);
  	printf("11spi_base = %llx\n",SPI_BASE);
}

void spi_initr()
{
  	SET_SPI(PARAM, 0x47);             //espr:0100
}


#ifdef NEW_SPI_ZZ

//发送数据,需配合写使能,片选操作。
static unsigned char spi_send_byte(unsigned char val)
{	
	while((GET_SPI(SPSR))&WFFULL);  //发送缓存满!!,等待
	SET_SPI(TXFIFO,val);
	while((GET_SPI(SPSR))&RFEMPTY); //等待发送结束
	return GET_SPI(RXFIFO); //读缓存
}
#endif


///read status reg /

int read_sr(void)
{
	int val;
	
	SET_SPI(SOFTCS,0x01);  //设置片选

#ifdef NEW_SPI_ZZ
	spi_send_byte(0x05);
	val = spi_send_byte(0x00);
#else
	SET_SPI(TXFIFO,0x05);  //发送命令
	while((GET_SPI(SPSR))&RFEMPTY);  //等待发送结束

	val = GET_SPI(RXFIFO);  //读缓存
	SET_SPI(TXFIFO,0x00);	//写数据0,是为了读取一个数据

	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY); //等待发送结束

	val = GET_SPI(RXFIFO); //读缓存
#endif	
	SET_SPI(SOFTCS,0x11);  //取消片选
      
	return val;
}

#ifdef NEW_SPI_ZZ
static void spi_flash_check_busy(void)
{
	unsigned char res;

	do{
		res = read_sr();  //读flash状态寄存器
	}while((res&0x01));  //忙则继续等
}
#endif


set write enable//
int set_wren(void)
{
	int res;

#ifdef NEW_SPI_ZZ
	//spi_flash_check_busy();
	SET_SPI(SOFTCS,0x01);  //片选
	spi_send_byte(0x06);  //写使能	
	SET_SPI(SOFTCS,0x11);   //取消片选
	spi_flash_check_busy();
	return 1;
#else	
	res = read_sr();  //读flash状态寄存器
	while(res&0x01 == 1)  //忙则继续等
	{
		res = read_sr();  
	}
	
	SET_SPI(SOFTCS,0x01);  //片选
	
	SET_SPI(TXFIFO,0x6);    //发出命令0x6
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){  //等待发送接收
	}
	GET_SPI(RXFIFO);  //读接收缓存,数据丢掉

	SET_SPI(SOFTCS,0x11);   //取消片选

	return 1;
#endif
}

///write status reg///
int write_sr(char val)
{
	int res;
#ifdef NEW_SPI_ZZ
	set_wren(); //flash写使能操作

	//spi_flash_check_busy();
	SET_SPI(SOFTCS,0x01);  //片选
	spi_send_byte(0x01);  //写状态寄存器	
	spi_send_byte(val);  //写入值
#else	
	set_wren();	//flash写使能操作
	res = read_sr();  //读flash状态寄存器
	while(res&0x01 == 1)  //忙则继续等
	{
		res = read_sr();
	}
	
	SET_SPI(SOFTCS,0x01);  //片选
	SET_SPI(TXFIFO,0x01);  //发出命令0x1,这里是写发送缓存,写入发送缓存的数据,就会发送给flash
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){ //读控制器的状态,读缓存为空吗?没收完整就是空     			
	}				//发送是串行的,数据写入缓存,到发送完是有个时间的。
	GET_SPI(RXFIFO);  //读接收缓存,数据丢掉

	SET_SPI(TXFIFO,val);  //再发送值,由参数传入
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){   //等待发送完    			
	}
	GET_SPI(RXFIFO);  //读接收缓存,数据丢掉
#endif
	SET_SPI(SOFTCS,0x11);  //取消片选
	
	return 1;	
}

///erase all memory/
int erase_all(void)
{
	int res;
	int i=1;

	spi_initw();
	set_wren();
	res = read_sr();
	while(res&0x01 == 1)
	{
		res = read_sr();
	}
	SET_SPI(SOFTCS,0x1);
	
	SET_SPI(TXFIFO,0xC7);
       	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){      			
	}
	GET_SPI(RXFIFO);
	
	SET_SPI(SOFTCS,0x11);
    while(i++){
        if(read_sr() & 0x1 == 0x1){
            if(i % 10000 == 0)
                printf(".");
        }else{
            printf("done...\n");
            break;
        }   
    }
	return 1;
}



void spi_read_id(void)
{
    unsigned char val;
    spi_initw();
    val = read_sr();
    while(val&0x01 == 1)
    {
        val = read_sr();
    }
    /*CE 0*/
    SET_SPI(SOFTCS,0x01);
    /*READ ID CMD*/
    SET_SPI(TXFIFO,0x9f);
    while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

    }
    GET_SPI(RXFIFO);

    /*Manufacturer's ID*/
    SET_SPI(TXFIFO,0x00);
    while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

    }
    val = GET_SPI(RXFIFO);
    printf("Manufacturer's ID:         %x\n",val);

    /*Device ID:Memory Type*/
    SET_SPI(TXFIFO,0x00);
    while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

    }
    val = GET_SPI(RXFIFO);
    printf("Device ID-memory_type:     %x\n",val);
    
    /*Device ID:Memory Capacity*/
    SET_SPI(TXFIFO,0x00);
    while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

    }
    val = GET_SPI(RXFIFO);
    printf("Device ID-memory_capacity: %x\n",val);
    
    /*CE 1*/
    SET_SPI(SOFTCS,0x11);

}

#ifdef NEW_SPI_ZZ
#define PAGE_SIZE 0x100  //# 256B
//返回写入的字节数
static int spi_write_pagebytes(unsigned int addr,unsigned char *data,int len)
{
	unsigned int i = 0;

//	printf("1 addr = %#x i = %u, len = %d data[0] = %hhx\n",addr,i,len,data[0]);
	
	if(len > PAGE_SIZE)
		len = PAGE_SIZE;   //最多一次编程1page

	i = addr & (0xff);  //起始地址是不是256的整数倍
	if(len + i > PAGE_SIZE) //页内有偏移,从写入的位置开始,到结束不能超过页的边界
		len = PAGE_SIZE - i; //写入页内字节数
	
//	printf("addr = %#x i = %u, len = %d data[0] = %hhx\n",addr,i,len,data[0]);
	//1. 写使能
	set_wren();

	//2 .片选,页编程命令
	SET_SPI(SOFTCS,0x01);/*CE 0*/
	spi_send_byte(0x02);  //写页编程指令

	//3. 发送地址
	spi_send_byte((addr)>>16);  //写地址
	spi_send_byte((addr)>>8);  //写地址
	spi_send_byte(addr);  //写地址

	//4. 发送数据
	for(i=0;i<len;i++)
	{
		spi_send_byte(data[i]);  //写地址
	}
	
	//5.取消片选  /*CE 1*/
	SET_SPI(SOFTCS,0x11);  //取消片选

	spi_flash_check_busy(); //等待数据写入完成

	return len;   //返回实际写入的字节数
}

//写入数据
static void spi_write_bytes(unsigned int addr,unsigned char *data,int len)
{
	int ret = 0;

	while(len>0)
	{
		delay(3000);    //必须延时,否则写失败
		ret = spi_write_pagebytes(addr,data,len);  //返回写入了多少个字节
	//	printf("spi_write_bytes ret = %d\n",ret);
		addr+=ret;  //指针向后移动
		data+=ret;  //指针向后移动
		len -= ret;
	//	udelay(10000);    //必须延时,否则写失败
		//dotik(32, 0);			//显示旋转的字符
	}	
}
#endif

void spi_write_byte(unsigned int addr,unsigned char data)
{
#ifdef NEW_SPI_ZZ
	spi_write_pagebytes(addr,&data,1);
#else
    /*byte_program,CE 0, cmd 0x2,addr2,addr1,addr0,data in,CE 1*/
	unsigned char addr2,addr1,addr0;
        unsigned char val;
	addr2 = (addr & 0xff0000)>>16;
    	addr1 = (addr & 0x00ff00)>>8;
	addr0 = (addr & 0x0000ff);
        set_wren();
        val = read_sr();
        while(val&0x01 == 1)
        {
            val = read_sr();
        }
		SET_SPI(SOFTCS,0x01);/*CE 0*/

        SET_SPI(TXFIFO,0x2);/*byte_program */
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        val = GET_SPI(RXFIFO);
        
        /*send addr2*/
        SET_SPI(TXFIFO,addr2);     
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        val = GET_SPI(RXFIFO);
        
        /*send addr1*/
        SET_SPI(TXFIFO,addr1);
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        val = GET_SPI(RXFIFO);
        
        /*send addr0*/
        SET_SPI(TXFIFO,addr0);
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        val = GET_SPI(RXFIFO);

        /*send data(one byte)*/
       	SET_SPI(TXFIFO,data);
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        val = GET_SPI(RXFIFO);
        
        /*CE 1*/
	SET_SPI(SOFTCS,0x11);
#endif
}
int write_pmon_byte(int argc,char ** argv)
{
    unsigned int addr;
   unsigned char val; 
    if(argc != 3){
        printf("\nuse: write_pmon_byte  dst(flash addr) data\n");
        return -1;
    }
    addr = strtoul(argv[1],0,0);
    val = strtoul(argv[2],0,0);
    spi_write_byte(addr,val);
	return 0;

}


int write_pmon(int argc,char **argv)
{
	long int j=0;
        unsigned char val;
        unsigned int ramaddr,flashaddr,size;
	if(argc != 4){
        printf("\nuse: write_pmon src(ram addr) dst(flash addr) size\n");
        return -1;
    }

    ramaddr = strtoul(argv[1],0,0);
    flashaddr = strtoul(argv[2],0,0);
    size = strtoul(argv[3],0,0);
        
	spi_initw();
    write_sr(0);
// read flash id command
    spi_read_id();
	val = GET_SPI(SPSR);
	printf("====spsr value:%x\n",val);
	
	SET_SPI(0x5,0x10);
// erase the flash     
	write_sr(0x00);
//	erase_all();
    printf("\nfrom ram 0x%08x  to flash 0x%08x size 0x%08x \n\nprogramming            ",ramaddr,flashaddr,size);
    for(j=0;size > 0;flashaddr++,ramaddr++,size--,j++)
    {
        spi_write_byte(flashaddr,*((unsigned char*)ramaddr));
        if(j % 0x1000 == 0)
            printf("\b\b\b\b\b\b\b\b\b\b0x%08x",j);
    }
    printf("\b\b\b\b\b\b\b\b\b\b0x%08x end...\n",j);

    SET_SPI(0x5,0x11);
	return 1;
}

int read_pmon_byte(unsigned int addr,unsigned int num)
{
        unsigned char val,data;
	val = read_sr();
	while(val&0x01 == 1)
	{
		val = read_sr();
	}
	
	SET_SPI(0x5,0x01);
// read flash command 
	SET_SPI(TXFIFO,0x03);
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
	
// addr
	SET_SPI(TXFIFO,0x00);
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
        GET_SPI(RXFIFO);
	
	SET_SPI(TXFIFO,0x00);
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
	
	SET_SPI(TXFIFO,0x00);
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
	
        
        SET_SPI(TXFIFO,0x00);
        while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){

        }
        data = GET_SPI(RXFIFO);
	SET_SPI(0x5,0x11);
        return data;
}

int read_pmon(int argc,char **argv)
{
	unsigned char addr2,addr1,addr0;
	unsigned char data;
	int val,base=0;
	int addr;
	int i;
        if(argc != 3)
        {
            printf("\nuse: read_pmon addr(flash) size\n");
            return -1;
        }
        addr = strtoul(argv[1],0,0);
        i = strtoul(argv[2],0,0);
	spi_initw();
	val = read_sr();
	while(val&0x01 == 1)
	{
		val = read_sr();
	}
	
	SET_SPI(0x5,0x01);
// read flash command 
	SET_SPI(TXFIFO,0x03);
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
	
// addr
	SET_SPI(TXFIFO,((addr >> 16)&0xff));
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
        GET_SPI(RXFIFO);
	
	SET_SPI(TXFIFO,((addr >> 8)&0xff));
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
	
	SET_SPI(TXFIFO,(addr & 0xff));
	while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
	}
	GET_SPI(RXFIFO);
// addr end
	
        
        printf("\n");
        while(i--)
	{
		SET_SPI(TXFIFO,0x00);
		while((GET_SPI(SPSR))&RFEMPTY == RFEMPTY){
      			
		}
	        data = GET_SPI(RXFIFO);
                if(base % 16 == 0 ){
                    printf("0x%08x    ",base);
                }
                printf("%02x ",data);
                if(base % 16 == 7)
                    printf("  ");
                if(base % 16 == 15)
                    printf("\n");
		base++;	
	}
        printf("\n");
	return 1;
	
}

int spi_erase_area(unsigned int saddr,unsigned int eaddr,unsigned sectorsize)
{
	unsigned int addr;
       	spi_initw(); 

	for(addr=saddr;addr<eaddr;addr+=sectorsize)
	{

	SET_SPI(SOFTCS,0x11);

	set_wren();

	write_sr(0x00);

	while(read_sr()&1);

	set_wren();

	SET_SPI(SOFTCS,0x01);

        /* 
         * 0x20 erase 4kbyte of memory array
         * 0x52 erase 32kbyte of memory array
         * 0xd8 erase 64kbyte of memory array                                                                                                           
         */
	SET_SPI(TXFIFO,0x20);
       	while((GET_SPI(SPSR))&RFEMPTY);
	GET_SPI(RXFIFO);
	SET_SPI(TXFIFO,addr >> 16);

       	while((GET_SPI(SPSR))&RFEMPTY);
	GET_SPI(RXFIFO);

	SET_SPI(TXFIFO,addr >> 8);
       	while((GET_SPI(SPSR))&RFEMPTY);
	GET_SPI(RXFIFO);

	SET_SPI(TXFIFO,addr);
	
       	while((GET_SPI(SPSR))&RFEMPTY);
	GET_SPI(RXFIFO);
	
	SET_SPI(SOFTCS,0x11);

	while(read_sr()&1);
	}
	SET_SPI(SOFTCS,0x11);
	delay(10);

	return 0;
}

int spi_write_area(int flashaddr,char *buffer,int size)
{
	int j;
	spi_initw();    //spi控制设置为写模式
//	SET_SPI(0x5,0x10); //spi控制器,设置片选,输出低,低有效
	write_sr(0x00);  //写flash的状态寄存器,不是控制器的
#ifdef NEW_SPI_ZZ
	spi_write_bytes(flashaddr,buffer,size);
#else
    for(j=0;size > 0;flashaddr++,size--,j++)
    {
        spi_write_byte(flashaddr,buffer[j]);   //写入数据,一个字节一个字节
    	dotik(32, 0);			//延时
    }
#endif
//	SET_SPI(SOFTCS,0x11); //取消片选,之前写入的数据是先到flash的缓存,然后才会编程到flash中,这样速度快一些
	delay(10);	//延时,结束,写入数据之后,flash会忙一阵子(把缓存的数据编程到flash中去)
	return 0;
}


int spi_read_area(int flashaddr,char *buffer,int size)
{
	int i;
	spi_initw();

	SET_SPI(SOFTCS,0x01);

	SET_SPI(TXFIFO,0x03);

        while((GET_SPI(SPSR))&RFEMPTY);
        GET_SPI(RXFIFO);
        
        SET_SPI(TXFIFO,flashaddr>>16);     
        while((GET_SPI(SPSR))&RFEMPTY);
        GET_SPI(RXFIFO);

        SET_SPI(TXFIFO,flashaddr>>8);     
        while((GET_SPI(SPSR))&RFEMPTY);
        GET_SPI(RXFIFO);

        SET_SPI(TXFIFO,flashaddr);     
        while((GET_SPI(SPSR))&RFEMPTY);
        GET_SPI(RXFIFO);
        

        for(i=0;i<size;i++)
        {
        SET_SPI(TXFIFO,0);     
        while((GET_SPI(SPSR))&RFEMPTY);
        buffer[i] = GET_SPI(RXFIFO);
        }

        SET_SPI(SOFTCS,0x11);
	delay(10);
	return 0;
}




//off 就是flash内部的偏移地址
int fl_erase_device(int off, int size, int verbose)
{
	//struct fl_map *map;
	//int off = (int)fl_base;
	//map = fl_find_map(fl_base);
	//off = (int)(fl_base - map->fl_map_base) + map->fl_map_offset;
	spi_erase_area(off,off+size,0x1000);
	spi_initr();
	return 0;
}


//off 就是flash内部的偏移地址
int fl_program_device(int off, void *data_base, int data_size, int verbose)
{
	//struct fl_map *map;
	//int off = (int)fl_base;
	//map = fl_find_map(fl_base);
	//off = (int)(fl_base - map->fl_map_base) + map->fl_map_offset;
	spi_write_area(off,data_base,data_size);
	spi_initr();
	return 0;
}

makefile(需要设置交叉编译工具路径)

cpp 复制代码
CC= mips64el-loongson-linux-gcc

all: mymap.o spi_w.o
	$(CC) --static  -o  program_pmon_ls2k1000 $^

%.o:%.c
	$(CC) -c $^


clean:
	rm -f program_pmon_ls2k1000 *.o
相关推荐
即将头秃的程序媛19 分钟前
centos 7.9安装tomcat,并实现开机自启
linux·运维·centos
fangeqin28 分钟前
ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
linux·python·ubuntu·openssl
爱奥尼欧2 小时前
【Linux 系统】基础IO——Linux中对文件的理解
linux·服务器·microsoft
超喜欢下雨天2 小时前
服务器安装 ros2时遇到底层库依赖冲突的问题
linux·运维·服务器·ros2
tan77º3 小时前
【Linux网络编程】网络基础
linux·服务器·网络
笑衬人心。4 小时前
Ubuntu 22.04 + MySQL 8 无密码登录问题与 root 密码重置指南
linux·mysql·ubuntu
chanalbert5 小时前
CentOS系统新手指导手册
linux·运维·centos
星宸追风6 小时前
Ubuntu更换Home目录所在硬盘的过程
linux·运维·ubuntu
热爱生活的猴子6 小时前
Poetry 在 Linux 和 Windows 系统中的安装步骤
linux·运维·windows
myloveasuka6 小时前
[Linux]内核如何对信号进行捕捉
linux·运维·服务器