前章我们也大致分析了SD卡的启动过程,在具体进行问题的定位及解决的过程中,发现还是有很多不明确的地方,网上的文章也多是人云亦云让我们来一步一步搞清楚S3C6410 SD卡启动的步骤及过程(我这里的开发板为OK6410,256M+1G的配置,SD卡为2G,MMC)
一、开发板跳线,从SD卡启动
view plain copy to clipboard print ?
- 查看《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)启动
查看《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)启动
view plain copy to clipboard print ?
- 修改UBOOT,让它支持从SD卡读取数据,并将自己自举到内存
- 当我们设置完CPU的跳线,CPU已经清楚要从哪里去取第一条指,S3C6410到底是怎么工作的呢
- 之前找到过一篇参考文章 《S3C2450_IROM_ApplicationNote_Rev003.pdf》
- 这次找到了官方的文档更清楚的说明了这一切《S3C6410_Internal_ROM_Booting.pdf》
- 在文档中我们看到CPU上电之后的启动过程如下
修改UBOOT,让它支持从SD卡读取数据,并将自己自举到内存当我们设置完CPU的跳线,CPU已经清楚要从哪里去取第一条指,S3C6410到底是怎么工作的呢之前找到过一篇参考文章 《S3C2450_IROM_ApplicationNote_Rev003.pdf》这次找到了官方的文档更清楚的说明了这一切《S3C6410_Internal_ROM_Booting.pdf》在文档中我们看到CPU上电之后的启动过程如下
view plain copy to clipboard print ?
- ① 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.
① 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.
view plain copy to clipboard print ?
- 按照这个启动过程,我们必须准备好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的代码
按照这个启动过程,我们必须准备好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代码
view plain copy to clipboard print ?
- 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-
s3c6410的uboot源码见最后的参考资料修改makefile 交叉工具链的绝对路径(嘿嘿,这个交叉工具链当然是俺自己做的交叉工具链了,参考前面篇BLOG)ifeq ($(ARCH),arm)CROSS_COMPILE = arm-none-linux-gnueabi-endifCROSS_COMPILE = /opt/cross_toolchains/arm/4.6.1/bin/arm-none-linux-gnueabi-
view plain copy to clipboard print ?
- 修改 include/configs/smdk6410.h 打开 #define CONFIG_BOOT_MOVINAND 这个宏,并屏蔽其他的启动选项
- 在UBOOT的代码中,将IROM的启动模式称之为MOVINAND
修改 include/configs/smdk6410.h 打开 #define CONFIG_BOOT_MOVINAND 这个宏,并屏蔽其他的启动选项在UBOOT的代码中,将IROM的启动模式称之为MOVINAND
这个UBOOT就已经可以从SD卡启动了,S3C6410具体又是怎么工作的呢?
view plain copy to clipboard print ?
- 在 cpu/s3c64xx/start.S 中我们看到如下这段
-
- #ifdef CONFIG_BOOT_MOVINAND
- ldr sp, _TEXT_PHY_BASE
- bl movi_bl2_copy
- b after_copy
- #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 函数
view plain copy to clipboard print ?
- cpu/s3c64xx/movi.c 中 void movi_bl2_copy(void) 中定义如下
cpu/s3c64xx/movi.c 中 void movi_bl2_copy(void) 中定义如下
view plain copy to clipboard print ?
- #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
#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的值
view plain copy to clipboard print ?
- ./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
./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的值
view plain copy to clipboard print ?
- ./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) || 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
view plain copy to clipboard print ?
- make smdk6410_config
- make -j4
make smdk6410_configmake -j4
三、将修改好的UBOOT烧录到SD卡中
为什么要用到下面的脚本,请参考:http://www.xxlinux.com/linux/article/development/embed/20100225/18059.html
生成的uboot-bin是不是直接可以烧录到SD卡中呢?
有现成的工具IROM_Fusing_Tool.exe(开源的,可以找到源代码),但这个工具烧录的是nb0文件
实际上nb0文件的结构是:256k+8k 这样的一个形式,在Linux系统可以通过下面这个脚本来生成nb0文件
view plain copy to clipboard print ?
- #!/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
#!/bin/shrm -rf temp x* u-boot_256k.bin u-boot_8k.bin u-boot_mmc.nb0cat u-boot.bin >> tempcat u-boot.bin >> tempsplit -b 256k tempmv xaa u-boot_256k.binsplit -b 8k u-boot.binmv xaa u-boot_8k.bincat u-boot_256k.bin > u-boot_mmc.nb0cat u-boot_8k.bin >> u-boot_mmc.nb0
我想直接将uboot-bin烧录到SD卡中,使用脚本太麻烦,于是我打算自己写一个烧录工具,关键代码如下
需要说明的是,我这里使用的是VC6,WINDOWS XP,VC6对磁盘IO的操作本身支持并不是非常好,有很多扩展的定义,功能都无法使用,这里很多都我手工添加进去的
如果使用的是VC2003及以上版本,会简单一些
view plain copy to clipboard print ?
- 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;
- }
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;}
view plain copy to clipboard print ?
- 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;
- }
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时需要用到的函数
view plain copy to clipboard print ?
- 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;
- }
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盘(可移动磁盘,注意下面的判断)的盘符
view plain copy to clipboard print ?
- void CSC6410BootLoaderWriterDlg::OnButtonGetdriverinfo()
- {
-
-
- 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盘检查完成");
- }
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的部分
view plain copy to clipboard print ?
- void CSC6410BootLoaderWriterDlg::OnButtonOp()
- {
-
-
- 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];
-
-
- ULONG nPhysicalDriveNumber = GetPhysicalDriveNumber(cPart);
-
-
- 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);
- }
-
-
-
- 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;
- }
-
-
-
-
-
- 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 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();
-
-
- 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);
- }
- }
void CSC6410BootLoaderWriterDlg::OnButtonOp() {// TODO: Add your control notification handler code hereint 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];// 获得 PhysicalDriveNumberULONG nPhysicalDriveNumber = GetPhysicalDriveNumber(cPart);// 读取 0 扇区 mbrBYTE 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 0x3bchar 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 0x40000BYTE 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)
http://www.rayfile.com/zh-cn/files/7ac4e133-0e58-11de-bd70-0014221b798a/
使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》