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
相关推荐
疯狂飙车的蜗牛1 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
远游客07133 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<3 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟3 小时前
centos-stream9系统安装docker
linux·docker·centos
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
cominglately6 小时前
centos单机部署seata
linux·运维·centos
魏 无羡6 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos
CircleMouse6 小时前
Centos7, 使用yum工具,出现 Could not resolve host: mirrorlist.centos.org
linux·运维·服务器·centos
木子Linux7 小时前
【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
linux·运维·服务器·centos·云计算
mit6.8247 小时前
Ubuntu 系统下性能剖析工具: perf
linux·运维·ubuntu