狼、羊、草过河问题(也有叫狼、羊、白菜过河之类的名字)是说:有一人带着一只部分驯化的狼(强调部分驯化是说明,人在场的情况下狼不会吃羊,不然要被指出逻辑漏洞了)、一只山羊和一些草来到河的左岸,欲乘一只很小的船过到河的右岸,每次人只能带其中一个过河,当有人在时,狼、羊、草都不会有事;当无人在时,就不允许狼羊在一起,也不允许羊和草在一起,问应如何过河?
本文引用地址:http://www.eepw.com.cn/article/169871.htm
这个类似智力测试的题可以有多种解法,例如最短路径之类的,甚至在很多场合被作为编程测试的问题。在此我们不讨论他们具体用什么方法过河,只要意识到其中的“山羊”是最关键因素,必须把它和其它二者在人不在场的情况下隔离起来就行了。问题的关键是为了安全可靠地完成工作,我们往往需要采取一些额外的行动。
在嵌入式系统的固件更新中,为了安全地烧写Flash中的内容,我们也需要使用类似的一些手段。更新Flash中的内容的过程本身并不复杂,只要擦除扇区中的内容,将新的代码下载到一个暂存空间,然后调用烧写函数,例如调用一些API,将暂存的代码写入扇区,再重新上电即可;实际的系统中,我们一般用RAM来作为暂存空间。这个过程看似简单,却有一些细节上的困难问题,例如:如果旧代码正在RAM中运行,把新代码存到RAM里将出现难以想象的行为,甚至是灾难(例如控制板用在强电场合)。此外,暂存代码的过程需要RAM空间足够大,从而可以把新代码放在未使用的地址中。但是在实际的系统中我们也可以经常发现,往往旧代码在编译的时候就已经警告RAM里面这段空间不够,那段空间不够了,哪里还有足够的空间去暂存至少和旧代码一样规模的新代码呢?
这时候我们的希望就是使用系统中的缓冲区了,例如在使用TI的CCS软件的时候,为了观测一些变量,我们会在内存中开辟一些缓冲区存储这些变量,从而可以在Graph窗口或者别的地方实时观察它们,这些缓冲区往往包含大量的地址空间(例如4*0x400的地址范围)。既然我们要烧写新代码了,那旧的代码里面待观测的变量自然也即将失去意义,可以将它们使用的空间给占用掉了。在这个装载程序的过程之前,首先要屏蔽使用这些缓冲区地址的中断,不然又要产生各种无法预料的奇怪结果了。
但是在这一过程中,也存在一些异常情况,例如新代码部分损坏(例如OMAP芯片的烧写就可以包含DSP部分的bin和ARM部分的bin,包含的器件越多,文件越多,失败的概率越高)、通信错误(甚至有极端情况,例如不小心把通信电缆给碰掉了)、暂存空间被意外破坏等状况(例如使用U盘去升级BIOS时,U盘被意外拔掉了)。所以在RAM中的暂存代码被烧入FLASH空间之前,还要有代码的校验工作,这样只要新代码存在校验错误,它就不会被用来替代旧代码,我们虽然会看到“烧写失败”的提示,至少对系统本身没有产生任何损坏,只要重新上电,然后系统自动加载旧代码就可以了。
最后说明,这里的一些思路是从O’REILLY出版的《Making Embeded Systems》一书里面提炼的。这是本讲解相当透彻的书,建议大家抽空读一读。