
TI AM3358 बूट ROM का रिवर्स इंजीनियरिंग
मुझे पहली बार कुछ Beaglebone Black बोर्ड हाथ लगे हुए शायद अठारह महीने हो गए हैं, जो कूड़ेदान से बचाए गए थे। दुर्भाग्यवश, बोर्ड तुरंत काम नहीं करे। अब, यह मेरा इन बोर्डों में से किसी एक के साथ, या उस मामले के लिए किसी भी सिंगल बोर्ड कंप्यूटर के साथ पहली बार काम करना था, इसलिए मुझे यकीन नहीं था कि समस्या कुछ ऐसी थी जो मैं कर रहा था, या बोर्डों में ही कुछ गड़बड़ थी (शायद यही वजह है कि वे पहली जगह कूड़ेदान के लिए जा रहे थे)। इन बोर्डों को वास्तव में बूट कराना शुरू करने में मुझे काफी लंबा समय और बहुत अधिक प्रयास लगा, लेकिन लानत है, मैंने कर दिखाया। और रास्ते में मैंने यही सीखा।
मैंने इस repo में कुछ उपयोगिताएँ शामिल की हैं, साथ ही Ghidra से निर्यात की गई एक xml फ़ाइल भी है जिसमें वे सभी प्रतीक (symbols) हैं जो मैंने अब तक रिवर्सिंग से प्राप्त किए हैं। मैंने किसी भी कॉपीराइट मुद्दे से बचने के लिए, केवल मामले में, वास्तविक फर्मवेयर के बिना निर्यात करने के लिए इस पोस्ट का उपयोग किया। यदि आप स्वयं बूट ROM को डीबग करना चाहते हैं, तो आपके पास पहले से ही JTAG जुड़ा होगा, इसलिए आप स्वयं बूट ROM (0x20000 से 0x2BFFF तक) डंप कर सकते हैं।
प्रतीकों को लोड करने के लिए:
0x20000 पर सेट करते हैं और आप ब्लॉक का नाम bootrom सेट कर सकते हैं।main() पर, या MMC/SD कार्ड बूट हैंडलर पर कूद सकते हैं।शुरुआत करने के लिए, मुझे पता था कि ये मानक beaglebone black के कस्टम संस्करण थे, इसलिए शुरुआत में मैंने निर्धारित किया कि यह बोर्ड पर ही कुछ गायब हो सकता है, जैसे बोर्ड पहचानकर्ता। जब मैंने balenaEtcher के साथ फॉर्मेट किए गए एक मानक SD कार्ड को बूट किया, तो मुझे कुछ भी नहीं दिखा। मुझे उम्मीद थी कि बोर्ड पर LEDs चमकने लगेंगी, और मुझे उम्मीद थी कि UART से USB केबल जोड़ने से मुझे U-Boot प्रक्रिया देखने को मिलेगी। हालाँकि, UART शांत था। यदि मैं SD कार्ड हटा देता, तो यह बार-बार अक्षर C आउटपुट करता, जो UART/serial बूट के लिए अपेक्षित व्यवहार है। यह निश्चित रूप से बूट करने की कोशिश कर रहा था, और SD कार्ड इस व्यवहार को बदल रहा था, लेकिन मेरे पास इससे अधिक कोई दृश्यता नहीं थी। वेब पर अधिकांश समस्या निवारण U-Boot आउटपुट को समस्याओं के निदान के लिए शुरुआती बिंदु के रूप में लेता था। मुझे लगता है कि मुझे वह विलासिता नहीं मिलने वाली थी।
इस बिंदु पर मैंने सोचा कि एक डीबग प्रोब कनेक्ट करना उचित होगा। दुर्भाग्य से, मौजूदा फुटप्रिंट के लिए मेरे पास मेल खाता हेडर नहीं था, इसलिए मैंने अपना खुद का बना लिया।
beaglebone बोर्ड में P2 पदनाम वाला एक हेडर है जो JTAG कनेक्शन को बाहर निकालता है। मैंने इस पर कुछ तारों को एक फीमेल हेडर से जोड़ा ताकि मैं अपने J-Link के माध्यम से उससे बात कर सकूँ।



Ozone (Segger डीबगर) में लॉन्च करते हुए मैंने J-Link कॉन्फ़िगर किया और केवल एंट्री पॉइंट खोजने की कोशिश करके शुरू किया। मैंने सोचा था कि रीसेट-हॉल्ट मुझे वहाँ पहुँचा देगा जहाँ मुझे होना चाहिए, और इसी तरह मैं इस (गलत) धारणा पर पहुँचा कि एंट्री पॉइंट 0x2148a है, हालाँकि मैंने निश्चित रूप से देखा कि यह सुसंगत नहीं था। बाद में, मुझे एहसास हुआ कि AM335x बोर्ड J-Link के रीसेट-हॉल्ट के साथ अच्छी तरह से काम नहीं करते हैं, इसलिए वास्तव में कुछ सौ क्लॉक साइकिलों की देरी होती थी, जो मुझे अनिश्चित रूप से किसी बूट हैंडलर के अंदर पहुँचा देती थी। (मैंने आखिरकार TI के Code Composer Studio के लिए एक GEL फ़ाइल लिखकर इसे हल किया, जो J-Link डीबगिंग का समर्थन करता है - रीसेट पर, PC रजिस्टर रीसेट हैंडलर पर सेट होता है, रजिस्टर साफ़ हो जाते हैं, और इंस्ट्रक्शन मोड को ARM पर बाध्य किया जाता है।)
TI फ़ोरम पर एक थ्रेड (AM335x: TI employees, where can I get the ROM Bootloader source code/symbols?) से मुझे कुछ डीबगिंग प्रतीक मिले: SPI Initialize at 0x231e0, SPI ReadSectors at 0x23230, और 0x24bfa एक रूटीन है जो UART रीड करता है। मुझे लगता है कि यह थोड़ी मदद है। मैंने देखा कि बूट 0x402f0440 पर एक अनंत लूप में समाप्त होकर विफल हो गया, जो एक डेड लूप है। हम्म, बाकी बूट ROM से काफी दूर, शायद RAM या किसी चीज़ में होना चाहिए। शायद अब तकनीकी संदर्भ मैनुअल (TRM) पर जाने का समय है!
TRM का अध्याय 26 बूटिंग पर बहुत सारी जानकारी रखता है। हमें बूट ROM का निम्नलिखित दृश्य मिलता है:

विवरण:
सार्वजनिक ROM कोड की वास्तुकला चित्र 26-1 में दिखाई गई है। इसे शीर्ष-डाउन दृष्टिकोण के साथ तीन मुख्य परतों में विभाजित किया गया है: उच्च-स्तरीय, ड्राइवर, और हार्डवेयर अमूर्त परत (HAL)। एक परत एकीकृत इंटरफ़ेस के माध्यम से निचले स्तर की परत के साथ संचार करती है। उच्च स्तरीय परत सार्वजनिक ROM कोड के मुख्य कार्यों के लिए जिम्मेदार है: वॉचडॉग और क्लॉक कॉन्फ़िगरेशन और मुख्य बूटिंग रूटीन। ड्राइवर परत किसी भी बूटिंग डिवाइस के लिए इंटरफ़ेस विनिर्देश के अनुसार तार्किक और संचार प्रोटोकॉल लागू करती है। अंत में HAL हार्डवेयर इन्फ्रास्ट्रक्चर IPs के साथ बातचीत करने के लिए निम्नतम स्तर के कोड को लागू करता है। बूटिंग डिवाइस डिवाइस IO पैड से जुड़े होते हैं।

चित्र 26-2 सार्वजनिक ROM कोड बूटिंग प्रक्रिया के लिए उच्च स्तरीय प्रवाह को दर्शाता है। इस डिवाइस पर सार्वजनिक ROM कोड सुरक्षित स्टार्टअप (Secure ROM कोड द्वारा निष्पादित) के पूरा होने पर शुरू होता है। ROM कोड फिर सार्वजनिक स्टार्ट-अप प्रक्रिया के भाग के रूप में प्लेटफ़ॉर्म कॉन्फ़िगरेशन और प्रारंभिकरण करता है। बूटिंग डिवाइस सूची SYSBOOT पिन के आधार पर बनाई जाती है। एक बूटिंग डिवाइस एक मेमोरी बूटिंग डिवाइस हो सकता है (सोल्डरेड फ्लैश मेमोरी या अस्थायी रूप से बूटिंग डिवाइस जैसे मेमोरी कार्ड) या किसी होस्ट से जुड़ा एक परिधीय इंटरफ़ेस। बूटिंग प्रक्रिया का मुख्य लूप बूटिंग डिवाइस सूची से गुजरता है और वर्तमान में चयनित बूटिंग डिवाइस से एक छवि खोजने की कोशिश करता है। यह लूप तब बाहर निकलता है जब एक मान्य बूटिंग छवि मिलती है और सफलतापूर्वक निष्पादित होती है या वॉचडॉग समाप्ति पर। छवि प्रमाणीकरण प्रक्रिया HS डिवाइस पर छवि निष्पादन से पहले की जाती है। प्रमाणीकरण प्रक्रिया में विफलता सुरक्षित ROM में एक "डेड लूप" (वॉचडॉग रीसेट की प्रतीक्षा) में शाखा करने की ओर ले जाती है।
मेमोरी मैप! अपवाद वेक्टर! फ्लो-चार्ट! इस अनुभाग में बहुत सारी जानकारी है। मेरा काम बहुत आसान हो गया।
इस बिंदु पर मैंने JTAG प्रोब का उपयोग फर्मवेयर को कुछ अलग फ़ाइलों में डाउनलोड करने के लिए किया, और Ghidra में चीज़ें लोड करना शुरू कर दिया। ऐसा लगता था कि कोई SVD फ़ाइलें या अन्य रजिस्टर मैपिंग सुविधाजनक प्रारूप में उपलब्ध नहीं थीं, जो वास्तव में दुर्भाग्यपूर्ण है, क्योंकि इसका मतलब है कि मुझे मेमोरी क्षेत्रों और रजिस्टरों और सब कुछ मैन्युअल रूप से परिभाषित करने की आवश्यकता है। यह एक थकाऊ प्रक्रिया थी, लेकिन थोड़ी देर बाद मेरे पास एक पायथन स्क्रिप्ट थी जिसका उपयोग मैं AM3358 के लिए Ghidra में प्रतीकों को लोड करने के लिए कर सकता था। चिंता करने के लिए एक कम चीज़!
ऐसा लगता है कि मेरे पास जो फ़ाइलें हैं उन्हें इस प्रकार मैप किया जा सकता है:
यह दिलचस्प है कि 0x402f_0440 पर अनंत लूप आंतरिक SRAM में "डाउनलोड की गई छवि" के शीर्ष पर है, जबकि अपवाद वेक्टर कहीं और संग्रहीत हैं। शायद यह बाद में एक महत्वपूर्ण संकेत होगा...
रीसेट पर, निजी बूट ROM सुरक्षा संबंधी काम संभालता है, और 0x2 0000 पर शाखा करता है जिसमें रीसेट वेक्टर होते हैं। पहला निर्देश 0x2 08d0 पर एक शाखा है जो एंट्री पॉइंट होना चाहिए। यह एक BX निर्देश नहीं है, इसलिए संभवतः, हम उस बिंदु पर अभी भी Arm मोड में हैं।
यह पहला कोड है जो चलता है, जिसका अर्थ है कि यह वास्तव में मापदंडों वाला कोई "फ़ंक्शन" नहीं है, बल्कि एक संकलित-जनरेटेड स्टार्टअप स्क्रिप्ट है। पहला बेसिक ब्लॉक:```arm ldr r4,[->Peripherals::CM_PER] mov r0,#0x2c ldr r6,[r4,r0]=>CM_PER.CM_PER_OCMCRAM_CLKCTRL mov r6,#0x2 str r6,[r4,r0]=>CM_PER.CM_PER_OCMCRAM_CLKCTRL mov r0,#0x2c poll: ldr r6,[r4,r0]=>CM_PER.CM_PER_OCMCRAM_CLKCTRL cmp r6,#0x2 bne poll
यह ब्लॉक OCMC RAM क्लॉक को सक्षम पर सेट करता है:
1. `CM_PER_OCMCRAM_CLKCTRL=0x2` सेट करें
2. जाँचें कि रजिस्टर सेट हुआ या नहीं; यदि नहीं, तो पोलिंग करते रहें
`CM_PER_OCMCRAM_CLKCTRL` रजिस्टर `MODULEMODE` फ़ील्ड के लिए बिट 0 और 1 का उपयोग करता है, इसे `=0x2` पर सेट करने से OCMC RAM को क्लॉक सक्षम हो जाती है।
अगला मूल ब्लॉक:```arm
ldr r0,[PTR_control_status]
ldr r0,[r0,#0x0]=>control_status
and r0,r0,#0x700
mov r0,r0, lsr #0x8
cmp r0,#0x3
bne skip
ldr r0,[PTR_control_status]
ldr r0,[r0,#0x0]=>control_status
cpy r6,r0
and r0,r0,#0x1f
cmp r0,#0x1f
bleq GPMIC_init
skip: ...
यह ब्लॉक निम्न कार्य करता है:
(control_status & 0x700) >> 8 == 0x3 है या नहीं, यदि नहीं तो छोड़ देंcontrol_status & 0x1f == 0x1f है या नहीं, यदि हाँ, तो control_status को r6 में लोड करने के बाद GPMC_init फ़ंक्शन को कॉल करेंअगला ब्लॉक कॉप्रोसेसर को सेटअप करता है:```arm msr cpsr_c,#0xd3 ldr r4,[->Exceptions::ROM_RESET_VECTOR] mcr p15,0x0,r4,cr12,cr0,0x0 bl LAB_00020934 bl LAB_00020938 bl LAB_0002093c bl LAB_00020940 bl LAB_00020944 bl LAB_00020948 bl LAB_0002094c bl LAB_00020950 mrc p15,0x0,r0,cr1,cr0,0x0 orr r0,r0,#0x800 mcr p15,0x0,r0,cr1,cr0,0x0 b LAB_000207f0
Operations in this block:
1. `11010011b` को CPSR नियंत्रण फ़ील्ड में ले जाएँ (`I=1`,`F=1`,`T=0`,`MODE=10011`)
1. `I` इंटरप्ट डिसेबल है, `F` फास्ट इंटरप्ट डिसेबल है (इसलिए `I=F=1` का अर्थ है इंटरप्ट डिसेबल हैं)
2. `T` थंब मोड है, जो `0` पर सेट है
3. `MODE=10011` प्रोसेसर मोड को Supervisor मोड पर सेट करता है ([ref](https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/The-System-Level-Programmers--Model/ARM-processor-modes-and-core-registers/ARM-processor-modes?lang=en#CIHGHDGI))
4. अधिक जानकारी के लिए [यहाँ](https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/The-System-Level-Programmers--Model/ARM-processor-modes-and-core-registers/Program-Status-Registers--PSRs-) देखें
2. ROM रीसेट वेक्टर का पता लोड करें
3. [coprocessor 15](https://developer.arm.com/documentation/den0013/d/ARM-Processor-Modes-and-Registers/Registers/Coprocessor-15) (सिस्टम कंट्रोल कॉप्रोक) Security Extensions रजिस्टर `c12` एक्सेस करें और ROM रीसेट वेक्टर को `VBAR` (वेक्टर बेस एड्रेस रजिस्टर) में लोड करें

4. क्या ये `nop` जंप जैसे दिखते हैं? `b` के बजाय `bl` क्यों?
5. ब्रांच प्रेडिक्शन सक्षम करें (सिस्टम कंट्रोल रजिस्टर `SCTLR` का बिट 11 सेट करें)

*VMSA इंप्लीमेंटेशन में CP15 `c1` रजिस्टर (सिस्टम कंट्रोल रजिस्टर)*
`SCTLR` रजिस्टर का विवरण:
> SCTLR सिस्टम का टॉप-लेवल नियंत्रण प्रदान करता है, जिसमें इसकी मेमोरी प्रणाली भी शामिल है।
> यह रजिस्टर वर्चुअल मेमोरी कंट्रोल रजिस्टर कार्यात्मक समूह का हिस्सा है।
TRM पृष्ठ B4-1687 देखें। बिट 11 *ब्रांच प्रेडिक्शन एनेबल* बिट है, इसे सक्षम पर सेट करने का अर्थ है [ब्रांच प्रेडिक्शन](https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/Common-Memory-System-Architecture-Features/Caches/Branch-predictors) सक्षम है।
6. एक फ़ंक्शन को कॉल करें (कॉल निर्देश पर ब्रांच के माध्यम से)
### `0x20894` पर फ़ंक्शन (`__main`)
एक अन्य प्रारंभिक रूटीन इस फ़ंक्शन पर ब्रांच करता है। मुझे लगता है कि यह `FUN_0002889c` (जिसे बाद में `main()` होना पता चला!) को कॉल करने से पहले स्टैक, और संभवतः टाइमर या वॉचडॉग को इनिशियलाइज़ करता है।```arm
ldr sp,[->RESERVED_EXCEPTION_BRANCH] ; 0x4030ce00
blx load_stack_1
ldr r12,[DWORD_1]
add r12,r12,pc
tst r12,#0x1
adrne lr,0x208bd
cpyeq lr,pc
bx r12 ;=>init_timers_maybe
adr r12,0x208bd
bx r12 ;=>LAB_000208bc
000208bc bl FUN_0002889c
000208c0 ddw 0x109
000208c4 addr RESERVED_EXCEPTION_BRANCH
...
RESERVED_EXCEPTION_BRANCH:
ldr pc=>LAB_00020090,[PTR_LAB_4030ce20]
; 20090 is a dead loop
यहाँ किए जाने वाले ऑपरेशन हैं:
r0,r1,r2,r3,r4,lr को स्टैक पर पुश करता है (मेमोरी मैप में पब्लिक स्टैक)
load_stack_1 एक खाली फ़ंक्शन bx lr पर ब्रांच करता है, फिर r0,r1,r2,r3,r4,pc को स्टैक से पॉप करता है (मूल रूप से उस डेटा को वापस रजिस्टरों में डालता है और जो कुछ भी lr में है उसे pc में डालकर वापस लौटता है)pc + 0x109 विषम है, यदि सम है तो 0x208bd को lr में लोड करें, अन्यथा pc को lr में कॉपी करेंFUN_0002889c को कॉल करेंयह बूट फ़्लो चार्ट में संदर्भित __main() फ़ंक्शन होना चाहिए:

इससे अगला फ़ंक्शन main फ़ंक्शन बन जाएगा।
जैसा कि चित्र 26-8 के शीर्ष पर दिखाया गया है, CPU सुरक्षित बूट प्रारंभिकरण पूरा करने के बाद पब्लिक ROM कोड रीसेट वेक्टर पर कूदता है। एक बार पब्लिक मोड में, सिस्टम स्टार्टअप पर, CPU पब्लिक-साइड प्रारंभिकरण और स्टैक सेटअप करता है (कंपाइलर द्वारा स्वतः उत्पन्न C- प्रारंभिकरण या "स्कैटर लोडिंग")। फिर यह वॉचडॉग टाइमर 1 को कॉन्फ़िगर करता है (तीन मिनट पर सेट), सिस्टम क्लॉक कॉन्फ़िगरेशन करता है। अंत में यह बूटिंग रूटीन पर कूदता है।
0x209b0)जब main कॉल किया जाता है, SP रजिस्टर 0x4030ce00 की ओर इंगित करता है। यहीं से स्टैक शुरू होता है, और यह 0x4030 b800 की ओर नीचे की ओर बढ़ता है; और चूँकि हम 4 रजिस्टरों को पुश करने के बाद 0x4030 cdf0 पते की ओर इंगित कर रहे हैं (16 बाइट्स या 4 शब्दों का अंतर), हम AAPCS के अनुसार पूर्ण अवरोही स्टैक का उपयोग कर रहे हैं। अर्थात, SP स्टैक पर सबसे हाल के शब्द की ओर इंगित करता है और नीचे की ओर बढ़ता है।
यह रहा डीकंपाइल किया गया main() फ़ंक्शन:```c
int main()
{
uint local_10;
uint local_c;
local_c = 0; local_10 = 0; check_stack_prm(&local_10); update_coldreset_tracing_vector(local_10); update_current_tracing_vector(1); main_clock_init(6,0); watchdog_softreset(); watchdog_write_disable_seq_data2(); set_watchdog(300000); if ((local_10 & 1) != 0) { update_current_tracing_vector(2); local_c = local_c & 0xffff | 1; } timer_func_1(); clock_init_func_4(&local_c); run_booting_loop(&local_c,local_10 & 0xff); return 0; }
मेरे उद्देश्यों के लिए सबसे दिलचस्प `run_booting_loop` फ़ंक्शन है, जो `0x20a10` पर है।
### X-Loader नोट्स
स्टार्टअप से गुजरने और "ISSW", "CHSETTINGS" और "X-LOADER" जैसी स्ट्रिंग्स के साथ इस हिस्से तक पहुँचने के बाद, मैंने अन्य जगहों की तलाश शुरू की जहाँ ये स्ट्रिंग्स U-Boot से संबंधित संदर्भों में दिख सकती हैं। मुझे [यह थ्रेड](https://forum.xda-developers.com/t/discussion-on-the-boot-loader-cracked.1378886/) मिला, जिसमें लोग Nook फ़र्मवेयर को रिवर्स या क्रैक कर रहे हैं, और [x-loader स्रोत](https://github.com/joelagnel/x-loader/blob/f3c74bc9b01dac58e553393d6ec1041353f2f1f7/scripts/signGP.c) में `CHSETTINGS` जैसी चीज़ों के संदर्भ हैं। चारों ओर देखने पर, "ISSW" [गैर-मेमोरी डिवाइसों से बूटिंग](https://github.com/u-boot/u-boot/blob/master/doc/README.ti-secure) को संदर्भित करता प्रतीत होता है।
इनिशियलाइज़ेशन दस्तावेज़ से याद करें, उच्च-स्तरीय कोड:

रुचि की बातें:
- RNDIS
- FAR
- XMODEM
- BOOTP
- TFTP
- DFT
शायद अब फिर से लाइव डिबगिंग आज़माने का समय है। उन सभी structs को रिवर्स करने की कोशिश करना शायद दर्दनाक होगा, क्योंकि इसमें बड़ी मात्रा में डेटा है जिसे मैं समझ नहीं सकता...
वाह! लाइव डिबगिंग तब काम करती है जब PC और SP को मैन्युअल रूप से उन वेक्टरों का उपयोग करके सेट किया जाता है जो मुझे मिले हैं:

स्रोत और ट्रेसिंग वेक्टरों से, मैं विभिन्न बूट विकल्पों और उन्हें सौंपे गए डिवाइस नंबरों का नक्शा बनाने में सक्षम था। यह बाद में बहुत उपयोगी साबित हुआ, क्योंकि SD/MMC बूट हैंडलर में ब्रेकपॉइंट सेट करते समय मुझे MMC0 (8) और MMCSD1 (9) के बीच अंतर करना था।
| प्रकार | डिवाइस | डिवाइस आईडी |
| ---------- | ----------------- | ----------- |
| मेमोरी | XIP (MUX2) | 1 |
| मेमोरी | XIP w/WAIT (MUX2) | 2 |
| मेमोरी | XIP (MUX1) | 3 |
| मेमोरी | XIP w/WAIT (MUX1) | 4 |
| मेमोरी | NAND | 5 |
| मेमोरी | MMCSD1 | 7, 9 (eMMC) |
| मेमोरी | NAND_I2C | 10 |
| मेमोरी | MMC0 | 8, 12 (SD) |
| पेरिफेरल | UART0 | 16 |
| पेरिफेरल | USB | 20 |
| पेरिफेरल | GPGMAC0 | 22 |
प्रोसेसर कैसे बूट होता है, इसकी जानकारी के लिए TRM और [स्टैक एक्सचेंज पर यह उत्तर](https://stackoverflow.com/a/31252989/8565545) देखें। संक्षेप में:
1. बूट ROM ने SD कार्ड पर MLO (Mmc LOader) फ़ाइल की पहचान कर ली है और उसे SRAM में कॉपी कर दिया है
2. यह द्वितीयक प्रोग्राम लोडर है, एक छोटा बूटलोडर जो पूर्ण RAM को इनिशियलाइज़ करता है और निष्पादन के लिए पूर्ण U-Boot बाइनरी को वहाँ कॉपी करता है
3. U-Boot बाइनरी चलने के बाद, हम (या बल्कि U-Boot) अंततः कर्नेल को बूट करते हैं
### `run_booting_loop()`
यह मुख्य बूट लूप है। यह अनंत काल तक चलता है, या जब तक निष्पादन किसी अन्य बूटलोडर पर शाखा नहीं करता जो RAM में लोड किया जाएगा।
प्रक्रिया की शुरुआत, बिना ट्रेसिंग वेक्टर अपडेट के:
- डिवाइस प्रकार देखें
- यदि डिवाइस प्रकार 5 (सुरक्षित डिवाइस) है तो कुछ अन्य इनिशियलाइज़ेशन करें
- `build_boot_list(int,buffer[],data[],int)` चलाएँ
- `buffer[]` को `0xff` से इनिशियलाइज़ किया गया है और `data[]` में डिवाइस प्रकार शामिल है (शायद)```c
void run_booting_loop(uint32_t *r0_config,undefined4 param_2,undefined4 param_3,
undefined4 default_list)
{
int iVar1;
uint j;
uint i;
int device_type;
byte alt_list [12];
undefined4 boot_status;
byte boot_list [8];
uint8_t local_buffer [8];
update_current_tracing_vector(3);
/* Device type is 3 */
lookup_device_type(&device_type);
if ((device_type == AM335X_HIGH_SECURITY) && (iVar1 = return_zero_4(), iVar1 != 0)) {
init_something_1_small(&STATIC_DATA_1);
}
/* param1 = 1
param2 = 4030 ebc4
param3 = 4030 ebb4 */
build_boot_list(*(ushort *)r0_config,boot_list,alt_list,default_list);
do {
i = 0;
local_buffer[0] = 0xff;
local_buffer[1] = 0xff;
local_buffer[2] = 0xff;
local_buffer[3] = 0xff;
do {
if (boot_list[i] - 1 < 12) {
update_current_tracing_vector(4);
/* No return unless there is an error */
boot_device_1(r0_config,boot_list[i],local_buffer);
}
else if (boot_list[i] - 65 < 8) {
update_current_tracing_vector(5);
watchdog_write_disable_seq_data2();
boot_status = 0xffffffff;
boot_device_2((uint32_t)r0_config,boot_list[i],&boot_status,local_buffer);
watchdog_write_enable_seq_data2();
if (boot_status != 0xffffffff) {
local_buffer[0] = (undefined)boot_status;
local_buffer[1] = boot_status._1_1_;
local_buffer[2] = boot_status._2_1_;
local_buffer[3] = boot_status._3_1_;
if ((boot_status & 0xffff00ff) == 0xf0030006) {
update_current_tracing_vector(9);
boot_list[i + 1] = (byte)(boot_status >> 8);
}
else if (boot_status != 0xf0030002) {
update_current_tracing_vector(8);
j = 0;
do {
if (63 < boot_list[j]) {
boot_list[j] = 0;
}
j = j + 1 & 0xff;
} while (j < 8);
}
}
}
i = i + 1 & 0xff;
} while (i < 8);
update_current_tracing_vector(6);
} while( true );
}
मुझे पता चला कि 0x23d7a पर एक फ़ंक्शन था, जिसे मैंने boot_into_SRAM() नाम दिया है, जो SRAM में शाखा (branch) लेने से पहले कॉल किया जाने वाला अंतिम फ़ंक्शन था, और फिर वहाँ से exception handler में जाता था। पहले, मेरे पास RAM की एक अलग स्थिति सहेजी हुई थी, लेकिन एक बार फिर लाइव डिबगिंग करते समय (अब एक साल से अधिक बाद, जुलाई 2024), मुझे समझ आया कि वास्तव में क्या हो रहा होगा। बोर्ड SD कार्ड से डेटा सफलतापूर्वक पढ़ रहा था, और वह कोड चला रहा था जिसे उसने कार्ड से लोड किया था! इसे सत्यापित करने के लिए, मुझे SRAM में उन बाइट्स को खोजना था जो SD कार्ड पर मौजूद डेटा के समान थे। पता चला कि am335x-evm-linux-sdk-bin-.../board-support/prebuilt-images/ के भीतर u-boot-spl.bin-am335x-evm नामक एक बाइनरी फ़ाइल है, और इस बाइनरी का कोड SRAM में दिखाई देने वाले कोड से मेल खाता है। हम uboot SPL तक पहुँच गए हैं!
हमने सफलतापूर्वक SRAM में बूट कर लिया है, अब मैं UART टर्मिनल के बारे में सोच रहा हूँ, जिसे uboot के बारे में जानकारी दिखानी चाहिए। हार्डवेयर कनेक्शन नीचे दिया गया है।

डिवाइस को CuteCom से कनेक्ट करने पर, 115200 @ 8-N-1, बिना SD कार्ड डाले यह केवल बार-बार C आउटपुट करता है।

लेकिन जब SD कार्ड डाला जाता है, तो UART कुछ भी आउटपुट नहीं करता। कोई संदेश नहीं, कोई अक्षर नहीं। गड़बड़ी बूट प्रक्रिया में बहुत जल्दी आ रही होगी? लेकिन अब जब मुझे यह भी पता है कि यह कौन सा कोड निष्पादित कर रहा है (और मेरे पास उसका स्रोत है), तो मुझे इसके लिए कुछ डिबगिंग सिंबल बनाने और एक उचित डिबग सत्र शुरू करने में सक्षम होना चाहिए। यह आसान नहीं हो सकता है, मुझे यह सुनिश्चित करना होगा कि मैं कोड को उसी तरह कंपाइल कर रहा हूँ, मुझे यह सीखने में कुछ समय लग सकता है कि SDK ने मेरे SD कार्ड पर वास्तव में क्या लोड किया है और इसे कैसे बनाना है।
चूँकि U-Boot UART पर टेक्स्ट आउटपुट कर रहा होता, और मुझे कुछ दिखाई नहीं दे रहा है, मैं अनुमान लगा रहा हूँ कि हम SPL में कहीं एक exception पकड़ रहे हैं।
इस बिंदु पर, मैंने Ghidra में boot ROM के डीकंपाइल किए गए स्रोत को रिवर्स करने और साफ करने में कई-कई घंटे बिताए, structs को देखते हुए और यह देखते हुए कि प्रत्येक डेटा सदस्य का उपयोग फ़ंक्शनों में कैसे किया जाता है, कभी-कभी नेस्टेड होने के कारण, मेरे लिए तरह-तरह की परेशानियाँ पैदा होती थीं। जब यह काम पीछे छूटा हुआ था, मैंने सोचा कि अब अपना खुद का कोड डिबग करना और कंपाइल करना शुरू करने का भी समय है। हम आखिरकार RAM में हैं, क्यों न SPL सिंबल लोड करके देखें कि क्या चल रहा है?
आप Ozone से डिबग कर सकते हैं, जो J-Link के लिए Segger डिबगर है। आप TI का अपना Code Composer Studio (CCS) या शायद उसका VSCode-शैली वाला "हल्का" संस्करण CCS Theia भी उपयोग कर सकते हैं। मैं इस वीडियो का अनुसरण करके SDK में सब कुछ बनाने में सक्षम था: Sitara Linux Board Porting Series: Module 6। बनाने के लिए तीन घटक हैं:
मैंने उपरोक्त श्रृंखला के Module 7 video का अनुसरण किया और कुछ नोट्स के साथ चीजों को काम करने में सफल रहा:
s_init() अब मौजूद नहीं हैसिंबल होने चाहिए? बहुत बढ़िया। अब मैं देख सकता हूँ कि निष्पादन में क्या हो रहा है, जिसकी शुरुआत रीसेट हैंडलर reset() से होती है, और मैं देख सकता हूँ कि हम अपने exception के साथ कहाँ पहुँचते हैं। इसका पता लगाने के लिए, मैंने 0x402f 0440 पर exception handler पर एक ब्रेकपॉइंट सेट किया, और link register की जाँच की, जिसमें अभी भी सबसे हालिया फ़ंक्शन का पता संग्रहीत था। यह पता 0x402f 76ce निकला, हालाँकि यह सुसंगत नहीं लगता। त्रुटि किस कारण से हो रही है?
नोट: डिबगिंग के लिए, Module 7 वीडियो का अनुसरण करते हुए, 0x402f 0400 तक चलाएँ, फिर Load Memory() वाला हिस्सा करें। यह हर पुनःआरंभ पर किया जाना चाहिए।
हम device_probe() फ़ंक्शन (0x402f 74c4) में जाते हैं, फिर कुछ अन्य फ़ंक्शन? फिर 0x402f 07fc पर शाखित do_setup_dpll() से, हम बाहर नहीं निकलते हैं, तो चलिए उसमें आगे बढ़ते हैं। आगे बढ़ते हुए, हम crt0.S में _main() पर लौटते हैं, जो 0x402f 14e0 पर स्थित है। ऐसा लगता है कि हम board_init_f() से बाहर आ रहे हैं, और spl_relocate_stack_gd() की ओर बढ़ रहे हैं। यह कॉल बाहर नहीं निकलती। हम dm_fixup_for_gd_move() तक पहुँचते हैं। इसमें एक निर्देश है जो 0x402f 76c2 पर विफल होता है। मुझे लगता है कि यही है: यह 0x81ff ff20 तक पहुँचने की कोशिश कर रहा है। जाहिर तौर पर यह काम नहीं करता। मुझे एक अंदेशा है कि SDRAM कॉन्फ़िगरेशन में समस्या है। मैंने TI फ़ोरम पर समान समस्याओं से संबंधित सभी थ्रेड्स खोजे, और आधा दर्जन ऐसे मिले जिनमें मेरी मदद के लिए कुछ संकेत थे। मैंने निष्कर्ष निकाला कि यह संभवतः (a) EMIF ट्यूनिंग या (b) सॉफ्टवेयर लेवलिंग से संबंधित था।
मेरा बोर्ड नीचे दिखाया गया है।

मेमोरी Micron की है, जबकि मेरे पास मौजूद BeagleBone Black (rev C3) की स्कीमैटिक Kingston DDR3 मेमोरी का उपयोग करती है, विशेष रूप से D2516EC4BXGGB। DDR3 U12 है, हम पार्ट को खोजने के लिए Micron marking decoder page का उपयोग कर सकते हैं:
चलिए सुनिश्चित करें कि चीज़ चालू है, मैंने केवल यह जाँच करके शुरू किया कि बिजली आपूर्ति हो रही है या नहीं। डेटाशीट निर्दिष्ट करती है कि यह 1.5V +/- 0.075V होना चाहिए। मैं बोर्ड के नीचे की ओर R6 के आर-पार 1.506V मापता हूँ। हमारे पास दो टेस्ट पॉइंट हैं, TP1 और TP2।
यदि यह कभी उपयोगी हो, तो यहाँ कुछ टेस्ट पॉइंट दिए गए हैं।
मेमोरी सर्किटरी हार्डवेयर डिज़ाइन पृष्ठ पर विस्तार से वर्णित है।
आइए क्लॉक इनेबल लाइन की जाँच करें। हम R96 के दोनों किनारों की जाँच कर सकते हैं, एक तरफ ग्राउंड होना चाहिए, दूसरी तरफ हाई रखी जानी चाहिए।

पुष्टि हुई, CKE पर 1.5V।
अगला कदम क्लॉक सिग्नल की जाँच करना है। मैंने यहाँ जो कर सकता था किया, tinySA का उपयोग करते हुए एंटीना को लगभग RAM चिप की दिशा में इंगित करके। इस तरह की "सूँघने" (sniffing) करते हुए मुझे काफी विश्वास है कि क्लॉक मौजूद है, कम से कम अभी के लिए पर्याप्त है।
आगे बढ़ते हुए, बाहरी मेमोरी इंटरफेसिंग को देखने का समय है। एक चीज़ जो अक्सर सामने आती है वह है GEL file की अवधारणा। यह Texas Instruments द्वारा Code Composer Studio के लिए विकसित एक व्याख्यायित भाषा है, इसका पूरा नाम General Extension Language है।
एक GEL फ़ाइल DDR memory config tool में शामिल है।
ठीक है! मैंने ट्यूनिंग प्रक्रिया का पालन किया (जहाँ तक हो सका) और GEL फ़ाइल के लिए इष्टतम मान खोजने में सफल रहा।```
The Slave Ratio Search Program Values are...
PARAMETER MAX | MIN | OPTIMUM | RANGE
DATA_PHY_RD_DQS_SLAVE_RATIO 0x071 | 0x005 | 0x03b | 0x06c DATA_PHY_FIFO_WE_SLAVE_RATIO 0x1b3 | 0x046 | 0x0fc | 0x16d DATA_PHY_WR_DQS_SLAVE_RATIO 0x0f7 | 0x01a | 0x088 | 0x0dd DATA_PHY_WR_DATA_SLAVE_RATIO 0x137 | 0x05a | 0x0c8 | 0x0dd
तो मेमोरी निश्चित रूप से काम कर रही लगती है, लेकिन SPL अभी भी विफल हो रहा है, तो शायद यहाँ कुछ हो रहा है जिस तरह से SPL SDRAM को इनिशियलाइज़ करने की कोशिश कर रहा है? आह, सही है, ट्यूनिंग प्रक्रिया में और भी कुछ है, बिल्कुल! आपको वास्तव में SPL को अपडेट करना होगा...
अब हम और करीब पहुँच रहे हैं। फ़ाइल `board.c` यह जाँच करके DDR को इनिशियलाइज़ करती है कि हमारे पास किस प्रकार का बोर्ड है। लेकिन इस बोर्ड के लिए, सभी फ़ंक्शन (`board_is_evm_sk()`, `board_is_icev2()`, `board_is_bone_lt()`, आदि) false लौटाते हैं, इसलिए यह `config_ddr(266, ...)` पर डिफ़ॉल्ट हो जाता है जहाँ 266 क्लॉक फ़्रीक्वेंसी MHz में है, और इसे 400 MHz *होना चाहिए*। यह निश्चित रूप से एक समस्या होगी।
`board_is_bone_lt` को बायपास करके हमेशा true लौटाना चाहिए। मैंने ऐसा किया, और मैं थोड़ा और आगे बढ़ गया, लेकिन कुछ मुझे परेशान कर रहा है। SD कार्ड पर नई फ़ाइल MLO लोड करना काम नहीं करता, भले ही प्रोग्राम को सीधे लोड करना ठीक काम करता है। यहाँ क्या हो रहा है? मैं बता सकता हूँ कि SRAM में लोड किया जा रहा कोड वह नहीं है जो मैंने संकलित किया है। वास्तव में, मैंने SD कार्ड को फ़ॉर्मेट भी कर दिया, और एक डिफ़ॉल्ट SPL वैसे भी sram में लोड हो रहा लगता है! मैंने सत्यापित किया कि बूट प्रक्रिया किसी अन्य SD कार्ड का उपयोग करते समय आगे बढ़ने की कोशिश नहीं करती। इसलिए, बूटलोडर निश्चित रूप से SD कार्ड पर बूट पार्टीशन की तलाश कर रहा है, फिर यह निष्पादन को SRAM में स्थानांतरित करता है, लेकिन उसने अभी तक डेटा कॉपी नहीं किया है? उफ़। यह कहाँ से आ रहा है??
इस समस्या ने मुझे कम परेशानी नहीं दी। मैंने सभी पार्टीशन हटा दिए, MBR को शून्य कर दिया, बूट पार्टीशन को शून्य कर दिया, और अलग-अलग SD कार्ड आज़माए, और केवल मेरा कार्ड ही बूट कर पा रहा था, इसलिए उस पर कहीं न कहीं *कुछ* बूट करने योग्य डेटा बचा हुआ होना चाहिए। अंत में, मैं *पूरे* कार्ड को शून्य करके इस पागलपन को समाप्त करने में सक्षम हुआ।
इस बिंदु पर मैंने **tracing vectors** के बारे में भी सीखा जिन्हें आप बूट ROM का समस्या निवारण करते समय एक्सेस कर सकते हैं। यह रिवर्सिंग के लिए भी अत्यंत सहायक साबित होगा, क्योंकि मुझे पता था कि ये सारे ट्रेसिंग कॉल कहाँ से आ रहे हैं, और फिर उन कॉलों के आधार पर फ़ंक्शन नाम आदि निर्दिष्ट कर सकता था। मैंने इन ट्रेसिंग वेक्टरों की व्याख्या करने के लिए एक स्प्रेडशीट बनाई, और इसका उपयोग यह जल्दी समझने के लिए किया कि जब मैंने कार्ड पैरामीटर बदले तो बूट प्रक्रिया कैसे बदली। निश्चित रूप से, यह बार-बार CHSETTINGS को खोजने का दावा कर रहा था जब मैं SD कार्ड को फ़ॉर्मेट और रीफ़ॉर्मेट करने की कोशिश कर रहा था, इससे पहले कि मैंने पूरी चीज़ को बेतहाशा शून्य कर दिया।
TI प्रोसेसर की तरह कार्ड को पढ़ने की कोशिश करने के लिए, आप `dd` का उपयोग कर सकते हैं। block size=512 का उपयोग करें, और पहले `n` सेक्टरों को स्किप करके पहला सेक्टर निर्दिष्ट करें (कौन सा है यह जाँचने के लिए GParted का उपयोग करने का प्रयास करें)। उदाहरण: पहला सेक्टर 2048 है, डिवाइस `sda` है, हम केवल पहला सेक्टर पढ़ेंगे:```
sudo dd if=/dev/sda1 of=/home/sam/sector2048 bs=512 skip=2048 count=1
मैंने इसका उपयोग MBR और बूट पार्टीशन की शुरुआत की छवियाँ सीधे SD कार्ड से डाउनलोड करने के लिए किया, जिनमें से दोनों बाद में काम आने वाले थे।
Ghidra में मेरे रिवर्स इंजीनियरिंग प्रयासों ने मुझे SD कार्ड बूट हैंडलर फ़ंक्शन तक पहुँचाया था, और अब मैं कार्ड को SD कमांड भेजने वाले फ़ंक्शन देख सकता था, और मैं कदम-दर-कदम आगे बढ़कर देख सकता था कि कार्ड क्या जवाब दे रहा है। मैंने सोचा कि मैं सही जगह देख रहा हूँ, और कार्ड सभी शून्य लौटा रहा है। बाद में मुझे पता चला कि शायद मैं eMMC हैंडलर (वही हैंडलर लेकिन एक अलग डिवाइस ID के साथ) को स्टेप कर रहा था, या कुछ और गड़बड़ थी, क्योंकि SD कार्ड में कोई समस्या नहीं थी। फिर भी, मैंने सोचा कि यह सीखने का समय है कि ये कार्ड कैसे काम करते हैं।
मैं यह देखने के लिए उत्सुक था कि प्रत्येक ब्लॉक अनुरोध के दौरान कार्ड बार-बार सभी शून्य क्यों लौटा रहा था। स्पष्टतः, कार्ड फ़ंक्शन और सॉफ़्टवेयर उससे पढ़ सकते हैं क्योंकि यह पहले भी हो चुका है। फिर भी, अब चीज़ों को तारों से जोड़ने और लॉजिक एनालाइज़र से देखने का समय था। थोड़ी माइक्रोसोल्डरिंग, UV-क्योर इपॉक्सी से 30awg तारों को दबाए रखना, और अपने Saleae से क्लिप करना, और हमारे पास कुछ ऐसा है जो काम करता है।

मैंने डेटा का विश्लेषण करने के लिए इस विश्लेषक का उपयोग किया। पहले मैंने इसे बिना कार्ड डाले आज़माया।

पहले कुछ कमांड के लिए क्लॉक दर 120 kHz है। जाहिर है, कार्ड जवाब नहीं देता (वह वहाँ नहीं है)।``` CMD0, arg=\0 GO_IDLE_STATE CMD8, arg=\x01\xAA SEND_EXT_CSD CMD55, arg=\0 APP_CMD CMD1, arg=\0 SEND_OP_COND ... CMD0, arg=\0 GO_IDLE_STATE CMD8, arg=\x01\xAA SEND_EXT_CSD CMD55, arg=\0 APP_CMD CMD1, arg=\0 SEND_OP_COND
जब कार्ड वास्तव में डाला जाता है, तो कॉन्फ़िगरेशन के बाद आवृत्ति लगभग 6 MHz तक बढ़ जाती है।

SD मोड का उपयोग करने से हुई कुछ क्रैश से उबरने के बाद (टिप: इस SD कार्ड के लिए भी आपको MMC मोड का उपयोग करना चाहिए) और मैं सत्यापित कर सका कि कार्ड उचित डेटा प्रदान कर रहा था। इसके बाद मैंने इसे विराम दिया, क्योंकि मैंने SD कार्ड बूट हैंडलर को समझने के अपने प्रयास दोगुने कर दिए और महसूस किया कि सही डेटा *पढ़ा* जा रहा था, और वह वही डेटा था जो मैंने मैन्युअल रूप से कार्ड को `dd` करके प्राप्त किया था! खैर, यह एक मजेदार चक्कर था और इसने मुझे विश्वास दिलाने में मदद की कि कार्ड काम कर रहा था।
### समस्या का पता लगाना
डेटा `0x4030c928` पते से आता है (एक स्टैक वेरिएबल, 512 बाइट ऐरे) `0x25c2e` पर शाखा को पते `0x0000` और डिवाइस `8` के लिए चलाने के बाद (स्थिर डेटा `0x4030d00c` पर देखें)। उस विधि में कूदते हुए जिसे मैंने `MBR_detection` कहा है, प्रोग्राम मैजिक बाइट्स `0xaa55` की जाँच करता है। पहले यह दूसरे दो बाइट्स `0xaa` लोड करता है, फिर पहले `0xaa` को।```
r0 = data[0x1ff]
r1 = data[0x1fe]
orr r0,r1,r0,lsl #8
sub r1,r0,#0xaa00
subs r1,#0x55
bne <return FAIL>
यह सफल होता है। अगली जाँच, हालाँकि, विफल हो जाती है:``` r0 = data[0xc] => 0 r1 = data[0xb] => 0 orr r0,r1,r0, lsl #8 cmp r0,#0x200 bne
डीकंपाइलर स्यूडोकोड:```c
if (
data[0x1fe] != 0x55aa ||
data[0xb] != 0x200 ||
(data[0xd] != 1 && // bit 0
data[0xd] != 2 && // bit 1
data[0xd] != 4 && // bit 2
data[0xd] != 8 && // bit 3
data[0xd] != 0x10 && // bit 4
data[0xd] != 0x20 && // bit 5
data[0xd] != 0x40 && // bit 6
data[0xd] != 0x80) // bit 7
)
{
return 1;
}
यह जाँचता है कि 0xb = 11 पर स्थित बाइट 0x200 के बराबर है, और जाँचता है कि 0xd पर स्थित बाइट एक single-bit मान के बराबर है या नहीं। दोनों शर्तें पूरी होनी चाहिए, अन्यथा यह विफलता लौटाता है।
detection फ़ंक्शन के 1 लौटाने के बाद, boot handler अगले चरण में इसे MBR के रूप में पढ़ने की कोशिश करता है और पहले partition का offset लोड करता है ताकि यह देख सके कि वह bootable partition है या नहीं। प्रक्रिया इस प्रकार है:```C
// Call block read function
// mmc_block_read_something(boot_device *dev,blk_read_struct blk)
ret = ((code *)blockread_struct->block_read_func)(blockread_struct->device_ptr,&block_read_info);
if (ret != 0) {
return 1;
}
// Check if device doesn't use MBR
ret = MBR_check_bootable_partition((partition_struct *)block_data,blockread_struct);
if (ret != 0) {
// It uses MBR, try each partition in the partition entries for a bootable
// partition
ret = MBR_check_entries(block_data,blockread_struct);
if (ret != 0) {
return 1;
}
ret = MBR_parse_entries(block_data,&blockread_struct->part_entry);
if (ret != 0) {
return 1;
}
// Get bootable partition offset
block_read_info = (blk_read_struct *)(blockread_struct->part_entry).first_sect_pos;
uStack_220 = 1;
pbStack_21c = block_data;
// Call block read function
// mmc_block_read_something(boot_device *dev,blk_read_struct blk)
ret = ((code *)blockread_struct->block_read_func)
(blockread_struct->device_ptr,&block_read_info);
if (ret != 0) {
return 1;
}
// Try and verify bootable partition again
ret = MBR_check_bootable_partition((partition_struct *)block_data,blockread_struct);
if (ret != 0) {
return 1;
}
}
तो अब मैं उस बिंदु पर जाता हूँ जहाँ यह `0x800` पर डेटा पढ़ता है और मुझे सही डंप मिलता है। लेकिन MBR पहचान विधि अभी भी 1 लौटाती है, सही डेटा के साथ भी (और वहाँ अप्रत्यक्षता की कुछ परतें हैं जिनका मुझे अनुसरण करना पड़ा, grrr) इसलिए समस्या वहीं होनी चाहिए।
अब अंतिम चरण है। SD कार्ड से पहला मेमोरी रीड MBR है, जिसमें अधिकतम चार पार्टीशन टेबल प्रविष्टियाँ होती हैं, TRM तालिकाएँ 26-20, 26-21 देखें। बूट पार्टीशन के लिए पार्टीशन टेबल प्रविष्टि कहती है कि पार्टीशन में `0x40000` सेक्टर हैं। लेकिन पार्टीशन फाइल सिस्टम (TRM तालिका 26-23 देखें) कहता है कि केवल `0x3fff8` हैं, किसी कारण से, और बूट ROM इसे पहचान कर विफल हो जाता है।
एक प्रयोग के तौर पर, मैंने उस जंप को कूद दिया जो समस्याएँ पैदा कर रहा था (जो बुरा भी हो सकता है... उंगलियाँ क्रॉस...), और प्रोग्राम निश्चित रूप से जारी रहा, हालाँकि मुझे यकीन नहीं है कि मैं कहाँ पहुँचा, कचरा जैसा लगता है। लेकिन उसे अनदेखा करते हुए, डिवाइस वास्तव में बूट हो जाता है! `0x402f0400` (लोड की गई छवि की शुरुआत) पर ब्रेकपॉइंट सेट करना और सब कुछ ठीक चल रहा है। शायद UART को जोड़ने का समय आ गया है? UART अच्छा है!
रही SD कार्ड समस्या? मैंने [Unix SE पर एक सवाल](https://unix.stackexchange.com/questions/781715/why-do-the-mbr-partition-entry-and-partition-filesystem-disagree-on-the-number-o/781755) पूछा, लेकिन इस मुद्दे में ज्यादा मदद नहीं मिली (हालाँकि कुछ अच्छी जानकारी ज़रूर मिली)। वहाँ से: आखिरकार मैंने इसे ठीक कर लिया! FAT16 फाइल सिस्टम बनाने के लिए `mkfs` कमांड की समीक्षा करते हुए, मैंने देखा कि [एक अन्य संदर्भ](https://blog.billvanleeuwen.ca/porting-u-boot-onto-the-beaglebone) -a फ्लैग का उपयोग करता है, जो अलाइनमेंट को अक्षम करता है। यही कुंजी थी। उस फ्लैग को जोड़कर और पुनर्निर्माण करके, सेक्टर गणनाएँ मेल खाती हैं (`0x40000`) और सिस्टम बूट हो जाता है। मुझे लगता है कि बूट ROM उस प्रकार के अलाइनमेंट का समर्थन नहीं करता।
अब कार्ड लगाए जाने पर मुझे नीचे दिए संदेश बूट लूप में मिल रहे हैं। हुर्रे! बस यह पता लगाना बाकी है कि कर्नेल क्यों शुरू नहीं हो रहा, और फिर सब कुछ ठीक हो जाएगा! वह सारी मेहनत आखिरकार कुछ उपयोगी beaglebone बोर्डों के रूप में रंग ला सकती है। क्या यह इसके लायक था? कौन जाने।```
U-Boot SPL 2021.01-00001-gc59bf25a382-dirty (Jul 24 2024 - 20:38:49 -0400)
Trying to boot from MMC1
U-Boot 2021.01-00001-gc59bf25a382-dirty (Jul 28 2024 - 20:36:46 -0400)
CPU : AM335X-GP rev 2.1
Model: TI AM335x BeagleBone Black
DRAM: 512 MiB
WDT: Started with servicing (60s timeout)
NAND: 0 MiB
MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1
Loading Environment from FAT... *** Warning - bad CRC, using default environment
<ethaddr> not set. Validating first E-fuse MAC
Net: eth2: ethernet@4a100000, eth3: usb_ether
Hit any key to stop autoboot: 2 <0x08><0x08><0x08> 1 <0x08><0x08><0x08> 0
WARNING: Could not determine device tree to use
switch to partitions #0, OK
mmc0 is current device
SD/MMC found on device 0
Failed to load 'boot.scr'
Failed to load 'uEnv.txt'
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
<0x1b>7<0x1b>[r<0x1b>[999;999H<0x1b>[6n<0x1b>8Scanning disk [email protected]...
Scanning disk [email protected]...
** Unrecognized filesystem type **
Found 4 disks
No EFI system partition
BootOrder not defined
EFI boot manager: Cannot load any image
switch to partitions #0, OK
mmc0 is current device
SD/MMC found on device 0
4997632 bytes read in 353 ms (13.5 MiB/s)
Failed to load '/boot/undefined'
Starting kernel ...
तो डिवाइस ट्री के साथ एक समस्या है ("WARNING: Could not determine device tree to use"). यह कर्नेल और कर्नेल बूटिंग के साथ मेरा पहला अनुभव है, इसलिए मुझे नहीं पता कि इसका क्या मतलब है।
"कर्नेल बूट करना" में निम्नलिखित शामिल हैं, जैसा कि मैं इसे समझता हूँ:
कर्नेल बूट प्रक्रिया का एक महत्वपूर्ण पहलू डिवाइस ट्री है। यह बोर्ड के लिए .dtb फ़ाइल (डिवाइस ट्री बाइनरी; .dts डिवाइस ट्री सोर्स फ़ाइलों से तुलना करें) में संग्रहीत होता है।
मेरी समस्या अब यह है कि U-Boot बोर्ड का डिवाइस ट्री लोड नहीं कर रहा है, क्योंकि लॉग में reading /am335x-boneblack.dtb जैसा कोई संदेश नहीं है। इसके बजाय, हमें WARNING: Could not determine device tree to use मिलता है। तो यह अच्छा सबूत है! अनुमान है कि यह लापता EEPROM बोर्ड आईडी के कारण है।
यह बोर्ड का पता कैसे लगाता है, इसके कुछ विवरण TI फ़ोरम पर इस थ्रेड में मिलते हैं।
तो, U-Boot को कैसे पता चलता है कि खुद को कैसे कॉन्फ़िगर करना है और ठीक से बूट करना है? हमारे द्वारा बनाए गए U-Boot स्रोत में configs/ नामक एक फ़ोल्डर है, जो विभिन्न बोर्डों के लिए defconfig फ़ाइलें संग्रहीत करता है। ये फ़ाइलें U-Boot के लिए विभिन्न कॉन्फ़िगरेशन पैरामीटर परिभाषित करती हैं, जिसमें बूट कमांड भी शामिल है, जो कुछ इस तरह दिख सकता है:```
if test ${boot_fit} -eq 1;
then run update_to_fit;
fi;
run findfdt;
run init_console;
run envboot;
run finduuid;
run distro_bootcmd
हम परिभाषित करते हैं कि जब हम `make <boardname>_config` टारगेट चलाते हैं, तो किस config का उपयोग करना है। `findfdt` फ़ंक्शन का उपयोग यह पहचानने के लिए किया जाता है कि हम किस बोर्ड पर चल रहे हैं, और डिवाइस ट्री को सही ढंग से कॉन्फ़िगर करता है। यह ऐसा दिखता है (`am335x_evm.h` में परिभाषित):```
"findfdt="\
"if test $board_name = A335BONE; then " \
"setenv fdtfile am335x-bone.dtb; fi; " \
"if test $board_name = A335BNLT; then " \
"setenv fdtfile am335x-boneblack.dtb; fi; " \
"if test $board_name = A335PBGL; then " \
"setenv fdtfile am335x-pocketbeagle.dtb; fi; " \
"if test $board_name = BBBW; then " \
"setenv fdtfile am335x-boneblack-wireless.dtb; fi; " \
"if test $board_name = BBG1; then " \
"setenv fdtfile am335x-bonegreen.dtb; fi; " \
"if test $board_name = BBGW; then " \
"setenv fdtfile am335x-bonegreen-wireless.dtb; fi; " \
"if test $board_name = BBBL; then " \
"setenv fdtfile am335x-boneblue.dtb; fi; " \
"if test $board_name = BBEN; then " \
"setenv fdtfile am335x-sancloud-bbe.dtb; fi; " \
"if test $board_name = A33515BB; then " \
"setenv fdtfile am335x-evm.dtb; fi; " \
"if test $board_name = A335X_SK; then " \
"setenv fdtfile am335x-evmsk.dtb; fi; " \
"if test $board_name = A335_ICE && test $ice_mii = rmii; then " \
"setenv fdtfile am335x-icev2.dtb; fi; " \
"if test $board_name = A335_ICE && test $ice_mii = mii; then " \
"setenv fdtfile am335x-icev2-prueth.dtb; fi; " \
"if test $fdtfile = undefined; then " \
"echo WARNING: Could not determine device tree to use; fi; \0" \
अगर हम डिफ़ॉल्ट व्यवहार चाहते हैं, तो हम सीधे board_name वेरिएबल बदल सकते हैं, है ना? खैर शायद नहीं, या कम से कम मुझे नहीं पता कि इसे बदलने की सबसे अच्छी जगह कहाँ है। लेकिन जबकि board_name सेट करना अपने आप में काम नहीं आया, मैंने वास्तव में डिफ़ॉल्ट .dtb फ़ाइल भी अपडेट की और वह काम कर गई!```
_____ _____ _ _
| _ |___ ___ ___ ___ | _ |___ ___ ||__ | |
| | _| .'| . | . | | | | . | | | -| _| _|
|||| |__,| || || || ||| ||||
|| |___|
Arago Project http://arago-project.org am335x-evm ttyS0
Arago 2021.09 am335x-evm ttyS0
am335x-evm login: root
root@am335x-evm:~#
आख़िरकार, हम एक टर्मिनल पर हैं। मेरे कबाड़ बोर्ड जीवित हैं!
### गायब EEPROM ID को ठीक करना
अंतिम चरण के रूप में, मैं EEPROM में सही बोर्ड ID लिखूँगा, जो Linux यूज़र स्पेस से करना आसान है। SPL स्रोत के अनुसार, विभिन्न बोर्ड ID ये हैं:
- `A335BONE` - Beaglebone बोर्ड
- `A335BNLT` - Beaglebone Black बोर्ड
- `A335PBGL`
- `A335X_SK`
- `A33515BB`
- `A335_ICE`
और एक वैकल्पिक बोर्ड रिवीज़न भी होता है। स्कीमैटिक के आधार पर, EEPROM I2C0 पर है, और चिप स्वयं (मेरे स्कीमैटिक पर 24LC32A, हालाँकि इस पर '256Kx8 लिखा है) I2C डिवाइस पता `0x50` प्रदान करती है (बाइनरी `b1010` के बाद `000` चिप पता, क्योंकि 5-पिन पैकेज में अतिरिक्त एड्रेस पिन नहीं होते)। एक अंतिम ध्यान देने योग्य बात: WP पिन को 10k पुल-अप के साथ HIGH पर खींचा गया है, इसलिए राइट प्रोटेक्ट डिफ़ॉल्ट रूप से सक्षम है; कोई भी लेखन होने से पहले इसे LOW से जोड़ना आवश्यक है, अन्यथा यह स्वीकार करेगा लेकिन कुछ भी नहीं लिखेगा।
EEPROM को कर्नेल के माध्यम से `/sys/bus/i2c/devices/0-0050` पर एक्सेस किया जा सकता है, जिसके भीतर `eeprom` नाम की एक फ़ाइल है। इसलिए, WP पिन को LOW से बाँधकर (ऊपर DC जैक के पास TP4 को ग्राउंड से जोड़ें) कुछ `echo` कॉल ही पर्याप्त हैं। Beaglebone Black System Reference Manual में प्रारूप मौजूद है। मैंने इसे [यहाँ से](https://groups.google.com/g/beagleboard/c/di5O5JCl4yw) अनुकूलित किया है।```sh
root@am335x-evm:~# cat fix_eeprom.sh
#!/bin/bash
# Fix board ID EEPROM
EEPROM_FILE=/tmp/eeprom.tmp
EEPROM=/sys/bus/i2c/devices/0-0050/eeprom
# header bytes
echo -ne "\xaa\x55\x33\xee" > ${EEPROM_FILE}
# Board ID
echo -n "A335BNLT" >> ${EEPROM_FILE}
# serial number (I left this basically as the template)
echo -n "000C24wwBBoxxxx" >> ${EEPROM_FILE}
dd if=${EEPROM_FILE} of=${EEPROM}
Using less का उपयोग करके पुष्टि करने पर, अब से हमें डिफ़ॉल्ट SD कार्ड चलाने में कोई समस्या नहीं होनी चाहिए। एक बार सभी बोर्डों पर उनके EEPROM लिख दिए जाने के बाद, SPL और U-Boot कॉन्फ़िगरेशन में किए गए परिवर्तनों को वापस लाया जा सकता है।
| Region | Start Address | Length |
|---|
| Boot ROM (Public) | 0x4002_0000 | 0xBFFF |
| Boot ROM (Public, alias) | 0x0002_0000 | 0xBFFF |
| SRAM Internal | 0x402F_0400 | 0xFC00 |
| L3 OCM0 | 0x4030_0000 | 0x10000 |
| टेस्ट पॉइंट | कनेक्शन | स्कीमैटिक शीट | बोर्ड की ओर |
|---|
| TP1 | DGND | 2 (D1) | ऊपर |
| TP2 | VDD_MPUON (VDD_MPU_MON) | 5 (C4) | ऊपर |
| TP3 | TESTOUT | 5 (B2) | ऊपर |
| TP4 | Board ID WP | 11 (B1) | ऊपर |