Chinaunix首页 | 论坛 | 博客
  • 博客访问: 106715
  • 博文数量: 39
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 18
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-20 13:23
文章分类

全部博文(39)

文章存档

2013年(39)

分类: LINUX

2013-08-20 14:29:18

前章我们也大致分析了SD卡的启动过程,在具体进行问题的定位及解决的过程中,发现还是有很多不明确的地方,网上的文章也多是人云亦云让我们来一步一步搞清楚S3C6410 SD卡启动的步骤及过程(我这里的开发板为OK6410,256M+1G的配置,SD卡为2G,MMC)

一、开发板跳线,从SD卡启动

[cpp]
  1. 查看《OK6410开发板LINUX2.6用户手册.pdf》 将跳线设置为 11111000 (从左到右为 pin8 到 pin1的设置,别搞反了)  
  2. 这些设置可以在s3c6410的datasheet中查到,打开《s3c6410_rev12.pdf》125页  
  3. Table 3-1. Device operating mode selection at boot-up   
  4. 从这里可以看到,最后3个位为0,表示从SD/MMC(CH0)启动  
查看《OK6410开发板LINUX2.6用户手册.pdf》 将跳线设置为 11111000 (从左到右为 pin8 到 pin1的设置,别搞反了) 这些设置可以在s3c6410的datasheet中查到,打开《s3c6410_rev12.pdf》125页 Table 3-1. Device operating mode selection at boot-up 从这里可以看到,最后3个位为0,表示从SD/MMC(CH0)启动
[cpp]
  1. 修改UBOOT,让它支持从SD卡读取数据,并将自己自举到内存  
  2. 当我们设置完CPU的跳线,CPU已经清楚要从哪里去取第一条指,S3C6410到底是怎么工作的呢  
  3. 之前找到过一篇参考文章 《S3C2450_IROM_ApplicationNote_Rev003.pdf》  
  4. 这次找到了官方的文档更清楚的说明了这一切《S3C6410_Internal_ROM_Booting.pdf》  
  5. 在文档中我们看到CPU上电之后的启动过程如下  
修改UBOOT,让它支持从SD卡读取数据,并将自己自举到内存 当我们设置完CPU的跳线,CPU已经清楚要从哪里去取第一条指,S3C6410到底是怎么工作的呢 之前找到过一篇参考文章 《S3C2450_IROM_ApplicationNote_Rev003.pdf》 这次找到了官方的文档更清楚的说明了这一切《S3C6410_Internal_ROM_Booting.pdf》 在文档中我们看到CPU上电之后的启动过程如下
[cpp]
  1. ①  iROM supports initial boot up,initialize system clock,D-TCM,device specific controller and bootin device.   
  2. ②  iROM boot codes can load 4KB of bootloader to stepping stone. The 8KB boot loader is called BL1  
  3. ③  BL1: BL1 can initialize system clock, UART, and SDRAM for user. After initializing, BL1 will load remaining boot loader which is called BL2 on the SDRAM   
  4. ④  Finally, jump to start address of BL2. That will make good environment to use system.   
① iROM supports initial boot up,initialize system clock,D-TCM,device specific controller and bootin device. ② iROM boot codes can load 4KB of bootloader to stepping stone. The 8KB boot loader is called BL1 ③ BL1: BL1 can initialize system clock, UART, and SDRAM for user. After initializing, BL1 will load remaining boot loader which is called BL2 on the SDRAM ④ Finally, jump to start address of BL2. That will make good environment to use system.
[cpp]
  1. 按照这个启动过程,我们必须准备好8K的引导代码在BL1,  
  2. 用来初始化系统,始终,串口,SDRAM等,并且将完整的BootLoader放在BL2上  
  3.   
  4. 2.7 Boot Block Assignment Guide 中有详细的描述  
  5.   
  6. 2G以下 SD/MMC 的卡的存储结构  
  7. SD/MMC 1Block = 512 Byte  
  8. =========================================================================================  
  9. |                                    SD/MMC Device                                      |  
  10. =========================================================================================  
  11. |                  | Recommendation |                    Mandatory                      |  
  12. | User File System |=====================================================================  
  13. |                  | Kernel |  BL2  | BL1(8K)  | Signature(512Byte) | Reserved(512Byte) |  
  14. |                  |        |       | 16 Block |       1 Block      |     1 Block       |  
  15. =========================================================================================  
  16.   
  17. 有了这个大致的印象,我们先放一下,下面我们来修改UBOOT的代码  
按照这个启动过程,我们必须准备好8K的引导代码在BL1, 用来初始化系统,始终,串口,SDRAM等,并且将完整的BootLoader放在BL2上 2.7 Boot Block Assignment Guide 中有详细的描述 2G以下 SD/MMC 的卡的存储结构 SD/MMC 1Block = 512 Byte ========================================================================================= | SD/MMC Device | ========================================================================================= | | Recommendation | Mandatory | | User File System |===================================================================== | | Kernel | BL2 | BL1(8K) | Signature(512Byte) | Reserved(512Byte) | | | | | 16 Block | 1 Block | 1 Block | ========================================================================================= 有了这个大致的印象,我们先放一下,下面我们来修改UBOOT的代码

二、修改UBOOT代码

[cpp]
  1. s3c6410的uboot源码见最后的参考资料  
  2. 修改makefile 交叉工具链的绝对路径(嘿嘿,这个交叉工具链当然是俺自己做的交叉工具链了,参考前面篇BLOG)  
  3.   
  4. ifeq ($(ARCH),arm)  
  5. CROSS_COMPILE = arm-none-linux-gnueabi-  
  6. endif  
  7.   
  8. CROSS_COMPILE = /opt/cross_toolchains/arm/4.6.1/bin/arm-none-linux-gnueabi-  
s3c6410的uboot源码见最后的参考资料 修改makefile 交叉工具链的绝对路径(嘿嘿,这个交叉工具链当然是俺自己做的交叉工具链了,参考前面篇BLOG) ifeq ($(ARCH),arm) CROSS_COMPILE = arm-none-linux-gnueabi- endif CROSS_COMPILE = /opt/cross_toolchains/arm/4.6.1/bin/arm-none-linux-gnueabi-
[cpp]
  1. 修改 include/configs/smdk6410.h 打开 #define CONFIG_BOOT_MOVINAND 这个宏,并屏蔽其他的启动选项  
  2. 在UBOOT的代码中,将IROM的启动模式称之为MOVINAND  
修改 include/configs/smdk6410.h 打开 #define CONFIG_BOOT_MOVINAND 这个宏,并屏蔽其他的启动选项 在UBOOT的代码中,将IROM的启动模式称之为MOVINAND

这个UBOOT就已经可以从SD卡启动了,S3C6410具体又是怎么工作的呢?

[cpp]
  1. 在 cpu/s3c64xx/start.S 中我们看到如下这段  
  2.   
  3. #ifdef CONFIG_BOOT_MOVINAND   
  4.         ldr     sp, _TEXT_PHY_BASE  
  5.         bl      movi_bl2_copy  
  6.         b       after_copy  
  7. #endif  
在 cpu/s3c64xx/start.S 中我们看到如下这段 #ifdef CONFIG_BOOT_MOVINAND ldr sp, _TEXT_PHY_BASE bl movi_bl2_copy b after_copy #endif

分析 movi_bl2_copy 函数

[cpp]
  1. cpu/s3c64xx/movi.c 中 void movi_bl2_copy(void) 中定义如下  
cpu/s3c64xx/movi.c 中 void movi_bl2_copy(void) 中定义如下

[cpp]
  1. #if defined(CONFIG_S3C6400)   
  2.         CopyMovitoMem(MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, CONFIG_SYS_CLK_FREQ, MOVI_INIT_REQUIRED);  
  3. #else   
  4.         writel(readl(HM_CONTROL4) | (0x3 << 16), HM_CONTROL4);  
  5.         CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, MOVI_INIT_REQUIRED);  
  6. #endif  
#if defined(CONFIG_S3C6400) CopyMovitoMem(MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, CONFIG_SYS_CLK_FREQ, MOVI_INIT_REQUIRED); #else writel(readl(HM_CONTROL4) | (0x3 << 16), HM_CONTROL4); CopyMovitoMem(HSMMC_CHANNEL, MOVI_BL2_POS, MOVI_BL2_BLKCNT, (uint *)BL2_BASE, MOVI_INIT_REQUIRED); #endif

确定MOVI_BL2_POS的值

[cpp]
  1. ./include/movi.h:#define MOVI_BL2_POS     (MOVI_LAST_BLKPOS - MOVI_BL1_BLKCNT - MOVI_BL2_BLKCNT - MOVI_ENV_BLKCNT)  
  2.   
  3. ./include/movi.h:#define MOVI_LAST_BLKPOS (MOVI_TOTAL_BLKCNT - (eFUSE_SIZE / MOVI_BLKSIZE))  
  4.   
  5. ./include/movi.h:#define MOVI_BL1_BLKCNT  (SS_SIZE / MOVI_BLKSIZE)  
  6.   
  7. ./include/movi.h:#define MOVI_BL2_BLKCNT  (((PART_ZIMAGE_OFFSET - PART_UBOOT_OFFSET) / MOVI_BLKSIZE) - MOVI_ENV_BLKCNT)  
  8.   
  9. ./include/movi.h:#define MOVI_ENV_BLKCNT  (CFG_ENV_SIZE / MOVI_BLKSIZE)  
  10.   
  11. ./include/movi.h  
  12. #ifdef CONFIG_BOOT_MOVINAND   
  13. #define MOVI_TOTAL_BLKCNT       *((volatile unsigned int*)(TCM_BASE - 0x4))   
  14. #define MOVI_HIGH_CAPACITY      *((volatile unsigned int*)(TCM_BASE - 0x8))   
  15. #else   
  16. #define MOVI_TOTAL_BLKCNT       7864320 // 7864320 // 3995648 // 1003520 /* static movinand total block count: for writing to movinand when nand boot */   
  17. #define MOVI_HIGH_CAPACITY      0   
  18. #endif   
  19.   
  20. ./include/movi.h:#define MOVI_BLKSIZE           512  
  21.   
  22. ./include/movi.h  
  23. #if defined(CONFIG_S3C6400) || defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)   
  24. #define TCM_BASE                0x0C004000   
  25. #define BL2_BASE                0x57E00000   
  26. #elif defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416)   
  27. #define TCM_BASE                0x40004000   
  28. #define BL2_BASE                0x33E00000   
  29. #else   
  30. # error TCM_BASE or BL2_BASE is not defined   
  31. #endif   
  32.   
  33. ./include/movi.h  
  34. #if defined(CONFIG_S3C6400)   
  35. #define SS_SIZE                 (4 * 1024)   
  36. #define eFUSE_SIZE              (2 * 1024)      // 1.5k eFuse, 0.5k reserved   
  37. #else   
  38. #define SS_SIZE                 (8 * 1024)   
  39. #define eFUSE_SIZE              (1 * 1024)      // 0.5k eFuse, 0.5k reserved`   
  40. #endif   
  41.   
  42. ./include/movi.h:#define PART_ZIMAGE_OFFSET     0x40000  
  43.   
  44. ./include/movi.h:#define PART_UBOOT_OFFSET      0x0  
  45.   
  46. ./include/configs/smdk6410.h:#define CFG_ENV_SIZE               0x4000  /* Total Size of Environment Sector */  
./include/movi.h:#define MOVI_BL2_POS (MOVI_LAST_BLKPOS - MOVI_BL1_BLKCNT - MOVI_BL2_BLKCNT - MOVI_ENV_BLKCNT) ./include/movi.h:#define MOVI_LAST_BLKPOS (MOVI_TOTAL_BLKCNT - (eFUSE_SIZE / MOVI_BLKSIZE)) ./include/movi.h:#define MOVI_BL1_BLKCNT (SS_SIZE / MOVI_BLKSIZE) ./include/movi.h:#define MOVI_BL2_BLKCNT (((PART_ZIMAGE_OFFSET - PART_UBOOT_OFFSET) / MOVI_BLKSIZE) - MOVI_ENV_BLKCNT) ./include/movi.h:#define MOVI_ENV_BLKCNT (CFG_ENV_SIZE / MOVI_BLKSIZE) ./include/movi.h #ifdef CONFIG_BOOT_MOVINAND #define MOVI_TOTAL_BLKCNT *((volatile unsigned int*)(TCM_BASE - 0x4)) #define MOVI_HIGH_CAPACITY *((volatile unsigned int*)(TCM_BASE - 0x8)) #else #define MOVI_TOTAL_BLKCNT 7864320 // 7864320 // 3995648 // 1003520 /* static movinand total block count: for writing to movinand when nand boot */ #define MOVI_HIGH_CAPACITY 0 #endif ./include/movi.h:#define MOVI_BLKSIZE 512 ./include/movi.h #if defined(CONFIG_S3C6400) || defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430) #define TCM_BASE 0x0C004000 #define BL2_BASE 0x57E00000 #elif defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416) #define TCM_BASE 0x40004000 #define BL2_BASE 0x33E00000 #else # error TCM_BASE or BL2_BASE is not defined #endif ./include/movi.h #if defined(CONFIG_S3C6400) #define SS_SIZE (4 * 1024) #define eFUSE_SIZE (2 * 1024) // 1.5k eFuse, 0.5k reserved #else #define SS_SIZE (8 * 1024) #define eFUSE_SIZE (1 * 1024) // 0.5k eFuse, 0.5k reserved` #endif ./include/movi.h:#define PART_ZIMAGE_OFFSET 0x40000 ./include/movi.h:#define PART_UBOOT_OFFSET 0x0 ./include/configs/smdk6410.h:#define CFG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */

确定BL2_BASE的值

[cpp]
  1. ./include/movi.h  
  2. #if defined(CONFIG_S3C6400) || defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430)   
  3. #define TCM_BASE                0x0C004000   
  4. #define BL2_BASE                0x57E00000   
  5. #elif defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416)   
  6. #define TCM_BASE                0x40004000   
  7. #define BL2_BASE                0x33E00000   
  8. #else   
  9. # error TCM_BASE or BL2_BASE is not defined   
  10. #endif  
./include/movi.h #if defined(CONFIG_S3C6400) || defined(CONFIG_S3C6410) || defined(CONFIG_S3C6430) #define TCM_BASE 0x0C004000 #define BL2_BASE 0x57E00000 #elif defined(CONFIG_S3C2450) || defined(CONFIG_S3C2416) #define TCM_BASE 0x40004000 #define BL2_BASE 0x33E00000 #else # error TCM_BASE or BL2_BASE is not defined #endif

经过计算我们可以看出,这里决定CopyMovitoMem的功能,是TCM_BASE - 0x4,这个地址的寄存器的值(隐含的也告诉我们UBOOT编译出来之后不得大于256k)

《S3C6410_Internal_ROM_Booting.pdf》中看到

0x0C003FFC globalBlockSizeHide Total block count of the MMC device

这个值,具体的为,256K(根据打印可以得出,没找到具体的说明)

MOVI_BL2_BLKCNT 的值为 ( (0x40000-0)/512 - (0x4000/512) ) = 512 -32 (个扇区)

网上大多数资料写到CopyMovitoMem是将256k的数据搬运到内存中,从这个计算上我们可以看出实际这个结论是错的

在这里只搬运了 256k-16k的数据到内存

在MOVI_BL2_POS的定义中做了相应的处理,以保证位置的正确性

编译uboot,生成u-boot.bin

[cpp]
  1. make smdk6410_config  
  2. make -j4  
make smdk6410_config make -j4

三、将修改好的UBOOT烧录到SD卡中

生成的uboot-bin是不是直接可以烧录到SD卡中呢?

有现成的工具IROM_Fusing_Tool.exe(开源的,可以找到源代码),但这个工具烧录的是nb0文件

实际上nb0文件的结构是:256k+8k 这样的一个形式,在Linux系统可以通过下面这个脚本来生成nb0文件

[cpp]
  1. #!/bin/sh   
  2. rm -rf temp x* u-boot_256k.bin u-boot_8k.bin u-boot_mmc.nb0  
  3. cat u-boot.bin >> temp  
  4. cat u-boot.bin >> temp  
  5. split -b 256k temp  
  6. mv xaa u-boot_256k.bin  
  7. split -b 8k u-boot.bin  
  8. mv xaa u-boot_8k.bin  
  9. cat u-boot_256k.bin > u-boot_mmc.nb0  
  10. cat u-boot_8k.bin >> u-boot_mmc.nb0  
#!/bin/sh rm -rf temp x* u-boot_256k.bin u-boot_8k.bin u-boot_mmc.nb0 cat u-boot.bin >> temp cat u-boot.bin >> temp split -b 256k temp mv xaa u-boot_256k.bin split -b 8k u-boot.bin mv xaa u-boot_8k.bin cat u-boot_256k.bin > u-boot_mmc.nb0 cat u-boot_8k.bin >> u-boot_mmc.nb0

我想直接将uboot-bin烧录到SD卡中,使用脚本太麻烦,于是我打算自己写一个烧录工具,关键代码如下

需要说明的是,我这里使用的是VC6,WINDOWS XP,VC6对磁盘IO的操作本身支持并不是非常好,有很多扩展的定义,功能都无法使用,这里很多都我手工添加进去的

如果使用的是VC2003及以上版本,会简单一些

[cpp]
  1. DWORD CSC6410BootLoaderWriterDlg::BlockDataRead(char cPart,DWORD dwBlockIndex,DWORD dwReadCount,BYTE* pBuffer)  
  2. {  
  3.     CString devName;  
  4.     devName.Format("\\\\.\\%c:",cPart);  
  5.     HANDLE hDevice = CreateFile(devName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);  
  6.     DWORD dwFilePointer = SetFilePointer(hDevice,dwBlockIndex*512, 0,FILE_BEGIN);  
  7.     DWORD dwBytesRead = 0;  
  8.     BOOL bRead = ReadFile(hDevice,pBuffer,dwReadCount,&dwBytesRead,NULL);  
  9.     if(bRead == FALSE)  
  10.     {  
  11.         DWORD dwError = GetLastError();  
  12.     }  
  13.     CloseHandle(hDevice);  
  14.     return dwBytesRead;  
  15. }   
DWORD CSC6410BootLoaderWriterDlg::BlockDataRead(char cPart,DWORD dwBlockIndex,DWORD dwReadCount,BYTE* pBuffer) { CString devName; devName.Format("\\\\.\\%c:",cPart); HANDLE hDevice = CreateFile(devName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); DWORD dwFilePointer = SetFilePointer(hDevice,dwBlockIndex*512, 0,FILE_BEGIN); DWORD dwBytesRead = 0; BOOL bRead = ReadFile(hDevice,pBuffer,dwReadCount,&dwBytesRead,NULL); if(bRead == FALSE) { DWORD dwError = GetLastError(); } CloseHandle(hDevice); return dwBytesRead; }
[cpp]
  1. DWORD CSC6410BootLoaderWriterDlg::BlockDataWrite(ULONG nPhysicalDriveNumber,DWORD dwBlockIndex,BYTE* pData,DWORD dwDataLen)  
  2. {  
  3.     if( (dwDataLen % 512) != 0 ) dwDataLen = ( (dwDataLen / 512) + 1 ) * 512;  
  4.     CString devName;  
  5.     devName.Format("\\\\.\\PhysicalDrive%d",nPhysicalDriveNumber);  
  6.     HANDLE hDevice = CreateFile(devName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);  
  7.     DWORD dwFilePointer = SetFilePointer(hDevice,dwBlockIndex*512, 0,FILE_BEGIN);  
  8.   
  9.     DWORD dwBytesWrite = 0;  
  10.     BOOL bWrite = WriteFile(hDevice,pData,dwDataLen,&dwBytesWrite,NULL);      
  11.     if(bWrite == FALSE)  
  12.     {  
  13.         DWORD dwError = GetLastError();  
  14.     }  
  15.   
  16.     CloseHandle(hDevice);  
  17.     return dwBytesWrite;  
  18. }  
DWORD CSC6410BootLoaderWriterDlg::BlockDataWrite(ULONG nPhysicalDriveNumber,DWORD dwBlockIndex,BYTE* pData,DWORD dwDataLen) { if( (dwDataLen % 512) != 0 ) dwDataLen = ( (dwDataLen / 512) + 1 ) * 512; CString devName; devName.Format("\\\\.\\PhysicalDrive%d",nPhysicalDriveNumber); HANDLE hDevice = CreateFile(devName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); DWORD dwFilePointer = SetFilePointer(hDevice,dwBlockIndex*512, 0,FILE_BEGIN); DWORD dwBytesWrite = 0; BOOL bWrite = WriteFile(hDevice,pData,dwDataLen,&dwBytesWrite,NULL); if(bWrite == FALSE) { DWORD dwError = GetLastError(); } CloseHandle(hDevice); return dwBytesWrite; }

看到区别了吗?这里要非常非常注意!

Write函数中devName的构建形式与Read函数中的不一样,这个问题让我调试了很久,如果在Write函数中使用Read函数的构建形式,则会遇到WriteFile工作不正常的现象

具体为:在操作最后若干个扇区时,bWrite 等于 TRUE,dwBytesWrite却为0(为什么?还没能深究下去)

另外,如果要写入的数据长度不是512的整数倍,一定要进行处理,否则会引起GetLastError是87,参数错误

因为所有的FLASH,最小的扇区时512字节,则最少要以512个字节作为一次操作单位

(文件系统帮我们解决了这些问题,我们现在是对磁盘裸的操作,所以不能按照有文件系统的想法来考虑这个问题)

下面是Write函数构造devName时需要用到的函数

[cpp]
  1. ULONG CSC6410BootLoaderWriterDlg::GetPhysicalDriveNumber(char cPart)  
  2. {  
  3.     typedef struct _DISK_EXTENT {  
  4.       ULONG         DiskNumber;  
  5.       LARGE_INTEGER StartingOffset;  
  6.       LARGE_INTEGER ExtentLength;  
  7.     } DISK_EXTENT, *PDISK_EXTENT;  
  8.   
  9.   
  10.     typedef struct _VOLUME_DISK_EXTENTS {  
  11.       ULONG       NumberOfDiskExtents;  
  12.       DISK_EXTENT Extents[ANYSIZE_ARRAY];  
  13.     } VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;  
  14.   
  15.     #define VOLUMEDISKSIZE (sizeof(VOLUME_DISK_EXTENTS))   
  16.   
  17.     #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096   
  18.   
  19.     CString devName;  
  20.     devName.Format("\\\\.\\%c:",cPart);  
  21.     HANDLE hDevice = CreateFile(devName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );  
  22.   
  23.     VOLUME_DISK_EXTENTS volumeData;  
  24.     DWORD dwOut = 0;  
  25.     DeviceIoControl( hDevice, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,NULL, 0, &volumeData, VOLUMEDISKSIZE, &dwOut, NULL );  
  26.     CloseHandle( hDevice );   
  27.   
  28.     return volumeData.Extents[0].DiskNumber;  
  29. }  
ULONG CSC6410BootLoaderWriterDlg::GetPhysicalDriveNumber(char cPart) { typedef struct _DISK_EXTENT { ULONG DiskNumber; LARGE_INTEGER StartingOffset; LARGE_INTEGER ExtentLength; } DISK_EXTENT, *PDISK_EXTENT; typedef struct _VOLUME_DISK_EXTENTS { ULONG NumberOfDiskExtents; DISK_EXTENT Extents[ANYSIZE_ARRAY]; } VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS; #define VOLUMEDISKSIZE (sizeof(VOLUME_DISK_EXTENTS)) #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096 CString devName; devName.Format("\\\\.\\%c:",cPart); HANDLE hDevice = CreateFile(devName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); VOLUME_DISK_EXTENTS volumeData; DWORD dwOut = 0; DeviceIoControl( hDevice, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,NULL, 0, &volumeData, VOLUMEDISKSIZE, &dwOut, NULL ); CloseHandle( hDevice ); return volumeData.Extents[0].DiskNumber; }

下面这段代码是用来获得,所有插入的U盘(可移动磁盘,注意下面的判断)的盘符

[cpp]
  1. void CSC6410BootLoaderWriterDlg::OnButtonGetdriverinfo()   
  2. {  
  3.     // TODO: Add your control notification handler code here   
  4.     // 获取所有的盘符   
  5.     m_cbList.ResetContent();  
  6.     DWORD dwStrLen = GetLogicalDriveStrings(0,NULL);    
  7.     char* pString = new char[dwStrLen+1];  
  8.     memset(pString,0,dwStrLen+1);  
  9.     GetLogicalDriveStrings(dwStrLen+1,pString);   
  10.   
  11.     char *pNow = pString;  
  12.     while(TRUE)  
  13.     {  
  14.         if(pNow >= (pString+dwStrLen-1)) break;  
  15.         DWORD dwRet = GetDriveType(pNow);  
  16.         if(dwRet == DRIVE_REMOVABLE)   
  17.         {  
  18.             m_cbList.InsertString(0,pNow);  
  19.         }  
  20.         pNow += strlen(pNow);  
  21.         pNow ++;  
  22.     }  
  23.   
  24.     delete[] pString;  
  25.   
  26.     m_cbList.SetCurSel(0);  
  27.     m_cbList.SetFocus();  
  28.   
  29.     WriteLog("U盘检查完成");  
  30. }  
void CSC6410BootLoaderWriterDlg::OnButtonGetdriverinfo() { // TODO: Add your control notification handler code here // 获取所有的盘符 m_cbList.ResetContent(); DWORD dwStrLen = GetLogicalDriveStrings(0,NULL); char* pString = new char[dwStrLen+1]; memset(pString,0,dwStrLen+1); GetLogicalDriveStrings(dwStrLen+1,pString); char *pNow = pString; while(TRUE) { if(pNow >= (pString+dwStrLen-1)) break; DWORD dwRet = GetDriveType(pNow); if(dwRet == DRIVE_REMOVABLE) { m_cbList.InsertString(0,pNow); } pNow += strlen(pNow); pNow ++; } delete[] pString; m_cbList.SetCurSel(0); m_cbList.SetFocus(); WriteLog("U盘检查完成"); }

最后是写入代码,在这里我们会要求SD卡首先会被各式化成FAT32各式,以便我们能去读取FTA32文件分配表中MBR的部分

[cpp]
  1. void CSC6410BootLoaderWriterDlg::OnButtonOp()   
  2. {  
  3.     // TODO: Add your control notification handler code here   
  4.   
  5.     int nCurSel = m_cbList.GetCurSel();  
  6.     if(nCurSel == -1)   
  7.     {  
  8.         MessageBox("探测磁盘信息");     
  9.         return;  
  10.     }  
  11.   
  12.     CString strBootFilePath;  
  13.     m_eBootFilePath.GetWindowText(strBootFilePath);  
  14.     if(strBootFilePath == "")  
  15.     {  
  16.         MessageBox("请先选择需要烧录的引导文件");      
  17.         return;   
  18.     }  
  19.   
  20.     // 获得驱动器盘符   
  21.     CString strText;  
  22.     m_cbList.GetLBText(m_cbList.GetCurSel(),strText);  
  23.     char cPart = strText[0];  
  24.   
  25.     // 获得 PhysicalDriveNumber   
  26.     ULONG nPhysicalDriveNumber = GetPhysicalDriveNumber(cPart);  
  27.   
  28.     // 读取 0 扇区 mbr   
  29.     BYTE szMbr[512];  
  30.     memset(szMbr,0,sizeof(szMbr));  
  31.     DWORD dwReturn = BlockDataRead(cPart,0,sizeof(szMbr),szMbr);  
  32.     if(dwReturn != sizeof(szMbr))  
  33.     {  
  34.         MessageBox("Read MBR error.","错误",MB_OK|MB_ICONERROR);  
  35.         return;  
  36.     }  
  37.     {  
  38.         CString strLog;  
  39.         strLog.Format("读取MBR成功");  
  40.         WriteLog(strLog);     
  41.     }  
  42.   
  43.     // 判断是否为 fat32   
  44.     // FAT16 为 0x36 0x37 0x38 0x39 0x3a 0x3b   
  45.     char szFs[6];  
  46.     szFs[0] = szMbr[0x52];     
  47.     szFs[1] = szMbr[0x53];     
  48.     szFs[2] = szMbr[0x54];     
  49.     szFs[3] = szMbr[0x55];     
  50.     szFs[4] = szMbr[0x56];     
  51.     szFs[5] = '\0';     
  52.   
  53.     if ( strcmp(szFs,"FAT32") != 0)  
  54.     {     
  55.         MessageBox("请将SD卡格式化为FAT32文件系统","错误",MB_OK|MB_ICONINFORMATION);     
  56.         return;  
  57.     }  
  58.       
  59.     // 获得磁盘的扇区总数   
  60.     //1CH-1FH   4  本分区隐含扇区数    
  61.     //20H-23H   4  该盘实际使用扇区数(不包括隐含扇区)      
  62.   
  63.     DWORD count_block_hidden = 0;  
  64.     memcpy(&count_block_hidden,&szMbr[0x1c],sizeof(count_block_hidden));  
  65.   
  66.     DWORD count_block = 0;  
  67.     memcpy(&count_block,&szMbr[0x20],sizeof(count_block));  
  68.   
  69.     DWORD count_block_total = count_block_hidden + count_block;  
  70.   
  71.     // 另一种方法 获得 扇区总数   
  72.     // #define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX 458912   
  73.     //  struct _DISK_GEOMETRY_EX    
  74.     // {    DISK_GEOMETRY  Geometry;     
  75.     //  LARGE_INTEGER  DiskSize;     
  76.     //  UCHAR  Data[1];   
  77.     // } DiskEX;   
  78.     // DeviceIoControl(hDevice,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,NULL,0,(LPVOID)&DiskEX,sizeof(DiskEX),(LPDWORD)&bytesReturned,NULL);   
  79.   
  80.     // 读取 u-boot.bin 文件   
  81.     // 最大 256k   
  82.     #define MOVI_TOTAL_BLKCNT 0x40000   
  83.     BYTE buffer_utoot[MOVI_TOTAL_BLKCNT];  
  84.     memset(buffer_utoot,0,sizeof(buffer_utoot));  
  85.       
  86.     CFile cf;  
  87.     cf.Open(strBootFilePath,CFile::modeRead);  
  88.   
  89.     DWORD uboot_size = min(MOVI_TOTAL_BLKCNT,cf.GetLength());  
  90.       
  91.     cf.Read(buffer_utoot,uboot_size);  
  92.     cf.Close();  
  93.       
  94.     // 将引导程序 uboot-bin 写入相应的位置   
  95.     DWORD bl2_begin = count_block_total-1-1-16-512;  
  96.     DWORD bl1_begin = count_block_total-1-1-16;  
  97.   
  98.     dwReturn = BlockDataWrite(nPhysicalDriveNumber,bl1_begin,buffer_utoot,8192);  
  99.     if(dwReturn != 8192)  
  100.     {  
  101.         MessageBox("写入引导8k字节失败");  
  102.         return;  
  103.     }  
  104.     {  
  105.         CString strLog;  
  106.         strLog.Format("写入引导8k字节成功");  
  107.         WriteLog(strLog);     
  108.     }  
  109.     dwReturn = BlockDataWrite(nPhysicalDriveNumber,bl2_begin,buffer_utoot,uboot_size);  
  110.   
  111.     if(dwReturn < uboot_size)  
  112.     {  
  113.         MessageBox("写入引导失败");  
  114.         return;  
  115.     }  
  116.     {  
  117.         CString strLog;  
  118.         strLog.Format("引导文件写入完成,磁盘总扇区数:%d",count_block_total);  
  119.         WriteLog(strLog);     
  120.     }  
  121. }  
void CSC6410BootLoaderWriterDlg::OnButtonOp() { // TODO: Add your control notification handler code here int nCurSel = m_cbList.GetCurSel(); if(nCurSel == -1) { MessageBox("探测磁盘信息"); return; } CString strBootFilePath; m_eBootFilePath.GetWindowText(strBootFilePath); if(strBootFilePath == "") { MessageBox("请先选择需要烧录的引导文件"); return; } // 获得驱动器盘符 CString strText; m_cbList.GetLBText(m_cbList.GetCurSel(),strText); char cPart = strText[0]; // 获得 PhysicalDriveNumber ULONG nPhysicalDriveNumber = GetPhysicalDriveNumber(cPart); // 读取 0 扇区 mbr BYTE szMbr[512]; memset(szMbr,0,sizeof(szMbr)); DWORD dwReturn = BlockDataRead(cPart,0,sizeof(szMbr),szMbr); if(dwReturn != sizeof(szMbr)) { MessageBox("Read MBR error.","错误",MB_OK|MB_ICONERROR); return; } { CString strLog; strLog.Format("读取MBR成功"); WriteLog(strLog); } // 判断是否为 fat32 // FAT16 为 0x36 0x37 0x38 0x39 0x3a 0x3b char szFs[6]; szFs[0] = szMbr[0x52]; szFs[1] = szMbr[0x53]; szFs[2] = szMbr[0x54]; szFs[3] = szMbr[0x55]; szFs[4] = szMbr[0x56]; szFs[5] = '\0'; if ( strcmp(szFs,"FAT32") != 0) { MessageBox("请将SD卡格式化为FAT32文件系统","错误",MB_OK|MB_ICONINFORMATION); return; } // 获得磁盘的扇区总数 //1CH-1FH 4 本分区隐含扇区数 //20H-23H 4 该盘实际使用扇区数(不包括隐含扇区) DWORD count_block_hidden = 0; memcpy(&count_block_hidden,&szMbr[0x1c],sizeof(count_block_hidden)); DWORD count_block = 0; memcpy(&count_block,&szMbr[0x20],sizeof(count_block)); DWORD count_block_total = count_block_hidden + count_block; // 另一种方法 获得 扇区总数 // #define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX 458912 // struct _DISK_GEOMETRY_EX // { DISK_GEOMETRY Geometry; // LARGE_INTEGER DiskSize; // UCHAR Data[1]; // } DiskEX; // DeviceIoControl(hDevice,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,NULL,0,(LPVOID)&DiskEX,sizeof(DiskEX),(LPDWORD)&bytesReturned,NULL); // 读取 u-boot.bin 文件 // 最大 256k #define MOVI_TOTAL_BLKCNT 0x40000 BYTE buffer_utoot[MOVI_TOTAL_BLKCNT]; memset(buffer_utoot,0,sizeof(buffer_utoot)); CFile cf; cf.Open(strBootFilePath,CFile::modeRead); DWORD uboot_size = min(MOVI_TOTAL_BLKCNT,cf.GetLength()); cf.Read(buffer_utoot,uboot_size); cf.Close(); // 将引导程序 uboot-bin 写入相应的位置 DWORD bl2_begin = count_block_total-1-1-16-512; DWORD bl1_begin = count_block_total-1-1-16; dwReturn = BlockDataWrite(nPhysicalDriveNumber,bl1_begin,buffer_utoot,8192); if(dwReturn != 8192) { MessageBox("写入引导8k字节失败"); return; } { CString strLog; strLog.Format("写入引导8k字节成功"); WriteLog(strLog); } dwReturn = BlockDataWrite(nPhysicalDriveNumber,bl2_begin,buffer_utoot,uboot_size); if(dwReturn < uboot_size) { MessageBox("写入引导失败"); return; } { CString strLog; strLog.Format("引导文件写入完成,磁盘总扇区数:%d",count_block_total); WriteLog(strLog); } }

到这里,我们就可以完全分析清楚,并可以自主的制作一个S3C6410的启动SD卡了,附后为一些参考资料,这里没办法贴附件,问题给我留言吧

后面的内容中,我们将进入UBOOT,对UBOOT进行修改,请关注下一节《如何计算内存大小,并在UBOOT中调整内存大小》

四、参考资料

下载 uboot1.1.6 (支持 movinand)

使uboot支持S3C6410的SD启动

http://blog.csdn.net/zwj0403/article/details/6420245

《S3C6410_Internal_ROM_Booting.pdf》

《s3c6410_rev12.pdf》

《smdk6410_users_manual_rev1.0.pdf》

《K4X51163PC.pdf》

《OK6410开发板LINUX2.6用户手册.pdf》

《OK6410开发板硬件手册2.1.pdf》

阅读(1448) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~