既然前面已经研究了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