該設(shè)計(jì)是一個(gè)物理開關(guān),它確定每次打開計(jì)算機(jī)時(shí)要啟動的操作系統(tǒng)。它使用STM32微控制器充當(dāng)USB大容量存儲設(shè)備,并提供一個(gè)動態(tài)文件。該文件可以由系統(tǒng)的引導(dǎo)配置加載,以根據(jù)物理輸入來更改其引導(dǎo)行為:
組件:
撥動開關(guān)
具有USB功能的STM32微控制器
ST-Link編程器
該項(xiàng)目的解決方案是通過代碼編寫的,因此需要一個(gè)撥動開關(guān),一個(gè)具有USB功能的STM32微控制器和一個(gè)ST-Link編程器。
代碼:點(diǎn)擊查看
設(shè)計(jì)過程:
啟動Linux,只需按電源按鈕;另一方面,要引導(dǎo)到Windows,則需要在GRUB短暫顯示自己時(shí)進(jìn)行戰(zhàn)術(shù),精確定時(shí)的敲擊,以更改選擇:
引導(dǎo)加載程序中的腳本
GNU GRUB是一種流行的Linux啟動加載程序-在加載任何操作系統(tǒng)之前運(yùn)行的程序,它決定啟動什么以及如何啟動它。通常,將與上圖所示的菜單進(jìn)行交互,但實(shí)際上,GRUB是由簡化的腳本語言配置的。在它的下面是用C語言編寫的模塊系統(tǒng)。
GRUB必須在操作系統(tǒng)外部運(yùn)行,因此必須提供所有自己的工具,因此可用功能相當(dāng)簡單。
在GRUB中可以任意訪問USB設(shè)備嗎?
創(chuàng)建一個(gè)具有自定義(“特定于供應(yīng)商”)接口的USB設(shè)備,以讀出開關(guān)位置,就非USB而言,它就像是裸露的串行連接??梢詮牟僮飨到y(tǒng)訪問,但是不確定GRUB是否可以處理它。
GRUB實(shí)現(xiàn)在其原生支持USB ehci、uhci、ohci模塊,但有一個(gè)問題-加載任何這些禁用用于訪問磁盤上的常態(tài)機(jī)制通過BIOS來避免沖突,讓你有無人接盤。有一個(gè)nativedisk模塊可以獨(dú)立于BIOS訪問磁盤,但是除了速度慢之外,嚴(yán)重地使用該模塊意味著GRUB無法鏈?zhǔn)郊虞dWindows(說明),從而使這種方法成為注銷。
偽裝成USB大容量存儲設(shè)備
可以利用BIOS已經(jīng)為GRUB提供對所有連接的存儲設(shè)備的訪問的事實(shí),而不是創(chuàng)建自定義USB接口。需要做的就是將設(shè)備顯示為存儲設(shè)備,其中包含一個(gè)文件,其內(nèi)容指示開關(guān)位置。
從概念上講這很簡單,但是有幾層:
提供大容量存儲類描述符,指示要使用的幾種存儲協(xié)議之一(SCSI,ATA)。
實(shí)現(xiàn)所選的存儲協(xié)議。除了用于讀取和寫入扇區(qū)的標(biāo)準(zhǔn)請求外,這是一組用于詢問存儲設(shè)備的功能,容量,布局和其他元數(shù)據(jù)的命令。
讀取時(shí)模擬有效的文件系統(tǒng),而實(shí)際上沒有任何存儲介質(zhì)。
使用USB狀態(tài)指示燈中已有的支持USB的STM32板卡和代碼,將供應(yīng)商類設(shè)備更改為大容量存儲類設(shè)備只需更改現(xiàn)有USB描述符中的幾個(gè)字節(jié)即可。
對于存儲協(xié)議層,發(fā)現(xiàn)它libopencm3具有內(nèi)置的SCSI大容量存儲實(shí)現(xiàn),具有簡單read_block(address)和write_block(address)回調(diào)功能,隱藏了存儲協(xié)議的復(fù)雜性:
由于這個(gè)原因,即使在這個(gè)階段它只能讀出無盡的0x00字節(jié)流,仍然可以使用可識別的存儲設(shè)備快速啟動并運(yùn)行。
熟悉FAT
模擬GRUB可以理解的文件系統(tǒng)。格式化存儲設(shè)備,選擇FAT12,因?yàn)樗奈臋n非常齊全,而且布局簡單:
引導(dǎo)扇區(qū):描述卷名稱和幾何形狀的固定結(jié)構(gòu)
文件分配表:一個(gè)索引,用于說明磁盤的哪些部分被使用以及分配/碎片化了多大的文件
根目錄條目:文件元數(shù)據(jù)。指向?qū)嶋H文件內(nèi)容所在的位置
[其余磁盤上沒有固定的結(jié)構(gòu)]
經(jīng)過閱讀和修改之后,進(jìn)行了一個(gè)設(shè)置,可以定義虛擬文件列表,并在毫不懷疑的主機(jī)要求下即時(shí)生成目錄條目和文件內(nèi)容:
struct VirtualFile {
char* longName;
struct FatDirEntry dir;
void (*read) (uint8_t* output);
};
static void readSwtich(uint8_t* output) { // Output is a zeroed-out 512 byte buffer (one block)
output[0] = gpio_get(GPIOA, GPIO6) ? ‘1’ : ‘0’;
}
static struct VirtualFile _virtualFiles[] = {
{
.longName = “switch_position”,
.dir = { .name = “SWITCH~1”, .ext = “ ”, .size = 1 },
.read = readSwtich
},
// 。..
};
轉(zhuǎn)儲塊設(shè)備看起來像這樣:
0000h是引導(dǎo)扇區(qū),0200h是FAT的第一個(gè)副本,0400h是FAT的第二個(gè)副本,0600h是根目錄條目。一共有三個(gè)32字節(jié)的目錄條目-兩個(gè)長文件名條目,然后是在640h該文件的實(shí)際目錄條目。虛擬文件內(nèi)容在4800h讀出。
在GRUB中讀取文件
GRUB沒有將文件內(nèi)容加載到變量中的任何內(nèi)置支持,也不像典型的Linux shell那樣支持命令替換:
# This is BASH and what I wanted to do
# GRUB script unfortunately doesn‘t support this kind of substitution
pos=$(cat /path/to/switch_position)
echo $pos
使用GRUB的“源” 命令從虛擬文件中加載其他配置。這種方法是開箱即用的,并且理論上適用于任何版本的GRUB:
根據(jù)開關(guān)位置啟動
使用GRUB外殼中的switch位置了,然后修改系統(tǒng)啟動配置,以根據(jù)此信息進(jìn)行啟動選擇。
在 /etc/grub.d/00_header中, 將此添加到了 生成的輸出中(刪除了轉(zhuǎn)義符以使其更易于閱讀):
# Look for hardware switch device by its hard-coded filesystem ID
search --no-floppy --fs-uuid --set hdswitch 55AA-6922
# If found, read dynamic config file and select appropriate entry for each position
if [ “${hdswitch}” ] ; then
source ($hdswitch)/switch_position_grub.cfg
if [ “${os_hw_switch}” == 0 ] ; then
# Boot Linux
set default=“0”
elif [ “${os_hw_switch}” == 1 ] ; then
# Boot Windows
set default=“2”
else
# Fallback to default
set default=“${GRUB_DEFAULT}”
fi
else
set default=“${GRUB_DEFAULT}”
fi
運(yùn)行update-grub生成新的啟動配置后,
硬件安裝
小的鋁制扁桿,幾個(gè)螺絲和一些鉆孔。
責(zé)任編輯:pj
-
微控制器
+關(guān)注
關(guān)注
48文章
7552瀏覽量
151417 -
usb
+關(guān)注
關(guān)注
60文章
7945瀏覽量
264622 -
編程器
+關(guān)注
關(guān)注
9文章
395瀏覽量
42318
發(fā)布評論請先 登錄
相關(guān)推薦
評論