I want to declare few regions in linker script, one after another. Do I need to reduce the length by one to avoid overlapping ?
MEMORY
{
region_1 : org = 0x100, len = 0x100 /* or len = 0xFF ? */
region_2 : org = 0x200, len = 0x100 /* or len = 0xFF ? */
region_3 : org = 0x300, len = 0x100 /* or len = 0xFF ? */
[...]
}
Do I need to reduce the length by one to avoid overlapping ?
No. What you are doing is correct.
From GNU Linker manual Memory Layout section:
len is the size in bytes of the region
Example:
MEMORY
{
region_1 : org = 0x10000000, len = 1 /* 1 byte */
region_2 : org = 0x20000000, len = 256K /* 256 kilobytes */
region_3 : org = 0x30000000, len = 4M /* 4 megabytes ? */
[...]
}
Related
I'm trying to erase flash for STM32F779II.
The start up file starts with that section:
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1664K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
SRAM1 (xrw) : ORIGIN = 0x20020000, LENGTH = 368K
SRAM2 (xrw) : ORIGIN = 0x2007C000, LENGTH = 16K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
So I'm leaving that three sections.
I'm trying to clear sector number 22. but I get Write Protection Error.
Here is how I'm earsing it.
Sectors is an array with one element, which is 22 sector number which has address
0x081C0000
secbool flash_erase_sectors(const uint8_t *sectors, int len,
void (*progress)(int pos, int len)) {
ensure(flash_unlock_write(), NULL);
HAL_FLASH_OB_Unlock();
FLASH_EraseInitTypeDef EraseInitStruct;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.NbSectors = 1;
if (progress) {
progress(0, len);
}
for (int i = 0; i < len; i++) {
EraseInitStruct.Sector = sectors[i];
uint32_t SectorError;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) {
ensure(flash_lock_write(), NULL);
return secfalse;
}
// check whether the sector was really deleted (contains only 0xFF)
const uint32_t addr_start = FLASH_SECTOR_TABLE[sectors[i]],
addr_end = FLASH_SECTOR_TABLE[sectors[i] + 1];
for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
if (*((const uint32_t *)addr) != 0xFFFFFFFF) {
ensure(flash_lock_write(), NULL);
return secfalse;
}
}
if (progress) {
progress(i + 1, len);
}
}
ensure(flash_lock_write(), NULL);
return sectrue;
}
I've been working on this for 3 days, can't see the error, I need fresh eyes :)
I work on a online embedded class, and at this particular lab we need to implement a file system.
I have unexpected results as described in the code comments in the main function. (E=expected, R=result)
Write/read functions:
#define EDISK_ADDR_MIN 0x00020000 // Flash Bank1 minimum address
#define EDISK_ADDR_MAX 0x0003FFFF // Flash Bank1 maximum address
// Write an array of 32-bit data to flash starting at given address.
int Flash_FastWrite(uint32_t *source, uint32_t addr, uint16_t count)
{
uint32_t flashkey;
uint32_t volatile *FLASH_FWBn_R = (uint32_t volatile*)0x400FD100;
int writes = 0;
if(MassWriteAddrValid(addr))
{
DisableInterrupts(); // may be optional step
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){}; // wait for hardware idle
while((writes < 32) && (writes < count))
{
FLASH_FWBn_R[writes] = source[writes];
writes = writes + 1;
}
FLASH_FMA_R = addr;
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY) // by default, the key is 0xA442
flashkey = FLASH_FMC_WRKEY;
else // otherwise, the key is 0x71D5
flashkey = FLASH_FMC_WRKEY2;
FLASH_FMC2_R = (flashkey|FLASH_FMC2_WRBUF); // start writing
while(FLASH_FMC2_R&FLASH_FMC2_WRBUF){};
EnableInterrupts();
}
return writes;
}
// Write 1 sector of 512 bytes of data to the disk, data comes from RAM
enum DRESULT eDisk_WriteSector(
const uint8_t *buff, // Pointer to the data to be written
uint8_t sector){ // sector number
uint32_t addr;
uint32_t *copybuff;
copybuff =(uint32_t*)(buff);//Flash_WriteArray needs uint32_t format
addr=EDISK_ADDR_MIN+(512*sector);// starting ROM address
if(addr>EDISK_ADDR_MAX) // return RES_PARERR if exceeds
return RES_PARERR;
Flash_WriteArray(copybuff, addr, 512);// write 512 bytes from RAM into ROM
// written by the instructor.
return RES_OK;
}
// Read 1 sector of 512 bytes from the disk, data goes to RAM
enum DRESULT eDisk_ReadSector(
uint8_t *buff, // Pointer to a RAM buffer into which to store
uint8_t sector){ // sector number to read from
uint16_t i;
uint8_t *diskpt;
diskpt=(uint8_t *)(EDISK_ADDR_MIN+512*sector); // starting ROM address
if(EDISK_ADDR_MIN+512*sector>EDISK_ADDR_MAX)
return RES_PARERR;
else
{
for ( i = 0; i < 512; i++ )// copy 512 bytes from ROM into RAM
buff[i] = *diskpt++;
return RES_OK;
}
}
enum DRESULT eDisk_Format(void){
// erase all flash from EDISK_ADDR_MIN to EDISK_ADDR_MAX
for(uint32_t i=EDISK_ADDR_MIN;i<=EDISK_ADDR_MAX;i++)
Flash_Erase(i);
return RES_OK;
}
uint8_t Buff[512];
int main(void)
{
eDisk_Init(0); // if(drive == 0){return RES_OK;}
eDisk_Format();
testbuildbuff("auf0");
eDisk_WriteSector(Buff,0);
testbuildbuff("Excelent"); // writes "Excelent" onto Buff
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,2);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,3);
// E=expected. R=result
eDisk_ReadSector(Buff, 0); //E: Buff="auf0" R:Buff="auf0"
eDisk_ReadSector(Buff, 1); //E: Buff="Excelent" R: Buff is empty
eDisk_ReadSector(Buff, 2); //E: Buff="bus3" R: Buff is empty
eDisk_ReadSector(Buff, 3); //E: Buff="bus4" R: 4Buff is empty
return 0;
}
The Buff results after reed are unexpected. Why does it work for 0 but not the rest?
Even more strange is when I run this test:
testbuildbuff("auf0 buf1 buf2");
eDisk_WriteSector(Buff,2);
testbuildbuff("Excelent");
eDisk_WriteSector(Buff,1);
testbuildbuff("bus3");
eDisk_WriteSector(Buff,3);
testbuildbuff("bus4");
eDisk_WriteSector(Buff,4);
eDisk_ReadSector(Buff, 4); //Buff is empty
eDisk_ReadSector(Buff, 3); //Buff is empty
eDisk_ReadSector(Buff, 2); //Buff = "auf0 buf1 buf2"
eDisk_ReadSector(Buff, 1); //Buff = "Excelent"
What is happening?
PS: IDE Keil uVision v5.2, uC: TM4C123
The issue is at call of function Flash_WriteArray().
In Flash_WriteArray(), the last parameter should be the number of words (32-bit or 4 bytes) we want to write. To write 512 bytes, this parameter should be 128 (512/4).
Writing words and reading bytes may give you an endian issue if your cpu is big endian.
As mentioned I have a Zynq SoC (ZC706 Eval Board) and I'm trying to read an image from the SD Card. To do this I'm using the FatFs lib (http://elm-chan.org/fsw/ff/00index_e.html).
In my code I read 4096 Byte from the file and save it to a buffer. After that i copy the buffer to an unsigned char pointer that size I increase after every read operation.
Then I'm using realloc, the for loop in the copyU32ArrayToUnsignedCharArray function 'failed' because the size variable is overwritten by the out array.
Code that overwrite the "size" in the copyU32ArrayToUnsignedCharArray function:
u32 buffer[1024];
unsigned char *img = NULL;
bytesreaded = 0;
for (;;) {
br=0;
fr = f_read(&fil, buffer, sizeof(buffer), &br); /* Read a chunk of source file */
if (fr || br == 0)
break; /* error or eof */
img = realloc(img,br);
copyU32ArrayToUnsignedCharArray(buffer, &img[bytesreaded], br/4); // /4 because u32(32 bit) in to unsigned char(8 bit)
bytesreaded += br; // update readed bytes
}
The code that worked:
u32 buffer[1024];
unsigned char *img = NULL;
img = malloc(512*512*3+100);
bytesreaded = 0;
for (;;) {
br=0;
fr = f_read(&fil, buffer, sizeof(buffer), &br); /* Read a chunk of source file */
if (fr || br == 0)
break; /* error or eof */
copyU32ArrayToUnsignedCharArray(buffer, &img[bytesreaded], br/4); // /4 because u32(32 bit) in to unsigned char(8 bit)
bytesreaded += br; // update readed bytes
}
The copyU32ArrayToUnsignedCharArray function:
void copyU32ArrayToUnsignedCharArray(u32 *in, unsigned char* out, uint size){
int i,x;
x = 0;
for (i = 0; i < size; i++) {
if(size != 1024)
break;
in[i] = Xil_In32BE(&in[i]);
out[x] = (u32) in[i] >> 24;
out[x + 1] = (u32) in[i] >> 16 & 0x00FF;
out[x + 2] = (u32) in[i] >> 8 & 0x0000FF;
out[x + 3] = (u32) in[i] & 0x000000FF;
x += 4;
}
}
I want to use realloc because I don't know how big the image will be that I read.
Update:
Some further information to the code that doesn't work. I debugged it and the pointer to *img isn't null, so the realloc was successfully. If I'm using gdb the following things happen in the copyU32ArrayToUnsignedCharArray function:
- pointer to the variable "out" is 0x001125a8
- the address of the "size" variable is 0x0011309c (the value that is stored at this location is correct)
- the space in memory between this two variables is 0xaf4 = 2804 dec (difference of the two addresses)
- if the for loop within the copyU32ArrayToUnsignedCharArray function reached i=702 and x=2808 the size variable is changed to another value
Sincerely,
Arno
I solved the problem with the hint from Notlikethat. The problem was the small heap size. Increasing the heap is done by editing the linker script file
The original xv6-rev7 operating system contains:
12 directed blocks
1 indirect blcok(points to 128 blocks)
This means we have 140 blocks.
Each block's size is 512KB ==> 512 * 140 = 71,680 ~= 70KB is the limit of file's size in xv6.
I want to implemet triple indirect access in xv6 in order to support files with size of 40MB.
In order to do it I will need to implement double indirect before the triple indirect.
So I took 2 directed blocks from the 12 I had.
1 for the double indirect and the other for the triple indirect.
This is what I have right now:
Direct: 10 blocks
Single indirect: 128
Double indirect: 128*128
Triple indirect: 4*128*128 (I am using 4 instead of 128 because this is enough for 40MB)
This is why #define NDIRECT 10 and uint addrs[NDIRECT+3];
File's size limit = (10 + 128 + 128*128 + 4*128*128)*512kb = 42,013,696 ~= 42MB
So I understand the concept.
The implementation of the triple-indirection is in function bmap in file fs.c.
This is how it looks:
For some reason when I am trying to create file with size of 8.5MB it fails:
I am using bochs emulator
I am also not sure to what values I need to change in mkfs.c:
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
fs.h:
// On-disk file system format.
// Both the kernel and user programs use this header file.
// Block 0 is unused.
// Block 1 is super block.
// Blocks 2 through sb.ninodes/IPB hold inodes.
// Then free bitmap blocks holding sb.size bits.
// Then sb.nblocks data blocks.
// Then sb.nlog log blocks.
#define ROOTINO 1 // root i-number
#define BSIZE 512 // block size
// File system super block
struct superblock {
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
};
#define NDIRECT 10
#define NINDIRECT (BSIZE / sizeof(uint))
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT*NINDIRECT + 4*NINDIRECT*NINDIRECT)
// On-disk inode structure
struct dinode {
short type; // File type
short major; // Major device number (T_DEV only)
short minor; // Minor device number (T_DEV only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+3]; // Data block addresses
};
// Inodes per block.
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i) ((i) / IPB + 2)
// Bitmap bits per block
#define BPB (BSIZE*8)
// Block containing bit for block b
#define BBLOCK(b, ninodes) (b/BPB + (ninodes)/IPB + 3)
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
struct dirent {
ushort inum;
char name[DIRSIZ];
};
fs.c:
// Return the disk block address of the nth block in inode ip.
// If there is no such block, bmap allocates one.
static uint
bmap(struct inode *ip, uint bn)
{
uint addr, *a;
struct buf *bp;
if(bn < NDIRECT){
if((addr = ip->addrs[bn]) == 0)
ip->addrs[bn] = addr = balloc(ip->dev);
return addr;
}
bn -= NDIRECT;
if(bn < NINDIRECT){
// Load indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT]) == 0)
ip->addrs[NDIRECT] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if((addr = a[bn]) == 0){
a[bn] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
/* Double indirect */
bn -= NINDIRECT;
if(bn < NINDIRECT*NINDIRECT){
// Load 2nd indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT+1]) == 0) // 2d block. NDIRECT+1 is to get the index vector
ip->addrs[NDIRECT+1] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT)]) == 0) { /* get index for 1st
indirection. (NINDIRECT is 128) */
a[bn/(NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp); /* release the double indirect table
(main level) */
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn%(NINDIRECT)]) == 0) { /* get the 2nd level table */
a[bn%(NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
/* Triple indirect */
bn -= NINDIRECT*NINDIRECT;
if(bn < 4*NINDIRECT*NINDIRECT){
// Load 3rd indirect block, allocating if necessary.
if((addr = ip->addrs[NDIRECT+2]) == 0) // 3d block. NDIRECT+2 is to get the index vector
ip->addrs[NDIRECT+2] = addr = balloc(ip->dev);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT*4)]) == 0) { /* get index for 2st
indirection. (NINDIRECT is 128) */
a[bn/(NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
bp = bread(ip->dev, addr);
a = (uint*)bp->data;
if ((addr = a[bn/(NINDIRECT*NINDIRECT*4)]) == 0) {
a[bn/(NINDIRECT*NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
if ((addr = a[bn%(NINDIRECT*NINDIRECT*4)]) == 0) {
a[bn%(NINDIRECT*NINDIRECT*4)] = addr = balloc(ip->dev);
log_write(bp);
}
brelse(bp);
return addr;
}
panic("bmap: out of range");
}
mkfs.c:
#define stat xv6_stat // avoid clash with host struct stat
#include "types.h"
#include "fs.h"
#include "stat.h"
#include "param.h"
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
bigfile.c:
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"
void
help()
{
printf(1, "usage:\nfiles <name> <letter> <num>\n"
"e.g. nfiles foo a 40\n creates a file foo, with 40 times the letter a\n");
}
void
num2str(int i, char str[3])
{
str[2]=i%10+'0';
i=i/10;
str[1]=i%10+'0';
i=i/10;
str[0]=i%10+'0';
i=i/10;
}
#define BUF_SZ 512
int
main(int argc, char *argv[])
{
int i, count, fd, n;
// char *name;
// char c;
char buf[BUF_SZ];
if (argc !=4) {
help();
exit();
}
count = atoi(argv[3]);
if((fd=open(argv[1], O_CREATE|O_RDWR))<0) {
printf(2,"Failed to open file: %s\n", argv[1]);
exit();
}
for (i=0; i<BUF_SZ;i++)
buf[i]=argv[2][0];
for (i=0; i<count/BUF_SZ;i++)
if ((n=write(fd,buf,BUF_SZ)) != BUF_SZ)
{
printf(2,"Failed 1 to Write count=%d\n",i*BUF_SZ);
exit();
}
for (i=0; i<count%BUF_SZ;i++)
if ((n=write(fd,argv[2],1)) != 1)
{
printf(2,"Failed 2 to Write count=%d\n",count-i);
exit();
}
exit();
}
1.The number of nblocks which is defined in mkfs.c is insufficient.
int nblocks = 20985;
int nlog = LOGSIZE;
int ninodes = 200;
int size = 21029;
You have defined:
#define MAXFILE (NDIRECT + NINDIRECT + NINDIRECT*NINDIRECT + 4*NINDIRECT*NINDIRECT
which equals: 10+128+128^2+4*128^2 = 82058.
Just pick a number of nblocks which is greater than 82058, and update size accordingly.
2.In your bmap() function, in the triple indirection code, your first level of indirection is to a four-entry array (as you mentioned in your diagram).
Once you know to which of these four entries you should access, you're back with the double indirection problem, which you already solved.
So, in order to know which of the four entries you should access, you can use this:
if((addr = a[bn/(NINDIRECT*NINDIRECT)]) == 0){
a[bn/(NINDIRECT*NINDIRECT)] = addr = balloc(ip->dev);
log_write(bp);
}
You then could decrease bn like so:
bn -= ((NINDIRECT*NINDIRECT)*(bn/(NINDIRECT*NINDIRECT)));
and solve the double indirection problem again.
I have following code:
framingStatus compressToFrame(char* inputBuffer, size_t inputBufferLength, char* frame, size_t* frameLength)
{
dword crc32 = GetMaskedCrc(inputBuffer,inputBufferLength);
size_t length = snappy_max_compressed_length(inputBufferLength);
char* compressed = (char*)malloc(length);
snappy_status status = snappy_compress(inputBuffer,inputBufferLength,compressed,&length);
if( status!=SNAPPY_OK )
return FS_ERROR;
frame[0] = 0x00; // Typ ramki skompresowany
frame[1] = length&0xff;
frame[2] = (length&0xff00)>>8;
frame[3] = (length&0xff00)>>16;
frame[4] = crc32&0xff;
frame[5] = (crc32&0xff00)>>8;
frame[6] = (crc32&0xff0000)>>16;
frame[7] = (crc32&0xff000000)>>24;
frame[8] = '\0'; // Pomoc dla strcat
strcat(frame,compressed);
*frameLength = length+8;
free(compressed);
return FS_OK;
}
Before calling this function I allocate memory for buffer named frame. All is ok, but assign instructions frame[x] = ... don't seem to write anything to buffer called frame and strcat concatenate compressed data to empty buffer without header I need.
Why assign instructions frame[x] = ... etc. don't give any result?
[EDIT:]
Can you suggest what function I have to use if I want to concatenate frame header with compressed data?
[EDIT2:]
Code presented below works just fine.
framingStatus compressToFrame(char* inputBuffer, size_t inputBufferLength, char* frame, size_t* frameLength)
{
dword crc32 = GetMaskedCrc(inputBuffer,inputBufferLength);
size_t length = snappy_max_compressed_length(inputBufferLength);
char* compressed = (char*)malloc(length);
snappy_status status = snappy_compress(inputBuffer,inputBufferLength,compressed,&length);
if( status!=SNAPPY_OK )
return FS_ERROR;
frame[0] = 0x00; // Typ ramki skompresowany
frame[1] = length;
frame[2] = length >> 8;
frame[3] = length >> 16;
frame[4] = crc32;
frame[5] = crc32 >>8;
frame[6] = crc32 >>16;
frame[7] = crc32 >>24;
memcpy(&frame[8],compressed,length);
*frameLength = length+8;
free(compressed);
return FS_OK;
}
You have
frame[0] = 0x00;
which is the same as
frame[0] = '\0';
No matter what you add after the first character, frame becomes a 0 length string.
strcat is for strings, not general binary bytes. Because frame first byte is zero, strcat will copy compressed starting at frame[0] and will stop copying when it sees a zero in compressed.
Try memcpy instead.
memcpy(&frame[8], compressed, length);
Also, since the length of frame is passed as an argument, you might want to be checking the total length you are copying to frame to make sure there's no illegal overwrite in that case.
As others already pointed out, you use binary data and not text strings. Therefore, strcat function is inappropriate here, use memcpy instead.
Furthermore, you should use unsigned char instead of plain char.
Additionally, you don't need to mask the values before shifting
frame[2] = (length&0xff00)>>8;
could be just
frame[2] = length >> 8;
And in this case, it is even buggy
frame[3] = (length&0xff00)>>16;
Same here
frame[5] = crc32 >> 8;
frame[6] = crc32 >> 16;
frame[7] = crc32 >> 24;
frame[0] = 0x00;
will make the first character as end of string character therefore your string frame is empty.
frame[0] = 0x00;
is same as writing,
frame[0] = '\0';