Protected Mode คืออะไร และกินกับอะไร การสลับโปรเซสเซอร์ Intel เป็นโหมดที่ได้รับการป้องกัน การสลับไปยังแอสเซมเบลอร์โหมดที่ได้รับการป้องกัน

rPUME OEDEMSHOPZP RETETSHCHB CHOPCHSH NPZH PVTBPCHBFSH CHBU OPCHSHCHN CHSHCHHRHULPN UCHPEK TBUUSCHMLY

yFBL, LBL CHSH RPNOYFE, H TEBMShOPN TETSYNE TBVPFSCH RTPGEUUPTB OBN DPUFKHREO CHUEZP MYYSH 1 NEZBVBKF BDTEUOPZP RTPUFTBOUFCHB (Yb LPFPTSCHI PVSHCHUOPK RBNSFSHA SCHMSEFUS CHUEZP LYYSH 64) fBL LFP Y VSHMP CHP อ่าน RETCHSHCHI RTPGEUUPTPCH CHTPDE 8086, OP RPUFEREOOP PVYaЈNB PRETBFICHOPK RBNSFY UFBMP OE ICHBFBFSH h FP TSE CHTENS FTEVPCHBMPUSH UPITBOYFSH RPMOHA PVTBFOHA UPCNEUFYNPUFSH, UFPVShch 16-TBTSDOSHCHE PRETBGYPOOSCHE UYUFENSCH CHTPDE DOS UNPZMY OPTNBMSHOP TBVPFBFSH rPFPNKh VSCHM CHCHEDIO OPCHSHCHK TETSYN TBVPFSCH RPGEUUPTB - BEEYEIIOSCHK TETSYN rPUME RETEIPDB CH OEZP DMS BDTEUBGYY YURPMSHHEFUS OE 16, B 32 YMY DBTSE 64 VYFB, B UEZNEOFSHCH UFBTPN RPOINBOY YUYUEBAF fBLCE DPVBCHMSAFUS BEIFOSCHE NEIBOYNSCH (YNEOOP RPFPNH บีอียอชเค TETSYN), UFPVShch SDTP pu VShchMP YЪPMYTPCHBOOP PF RTYMPTSEOIK Y NPZMP YNY UCHPVPDOP HRTBCHMSFSH sFP OEVPVIPDYNP MAVPK RPMOPGEOOPK NOPZPЪBDBYuOPK UYUFENE

оБЮОЈН У ФПЗП, ЮФП ДПВБЧМСЕФУС Ч ТЕБМШОПН ТЕЦЙНЕ ОБ РТПГЕУУПТБИ, ЛПФПТЩЕ РПДДЕТЦЙЧБАФ 32-ВЙФОЩК БДТЕУ (i386 Й ЧЩЫЕ) - ДПВБЧМСАФУС ОПЧЩЕ ТЕЗЙУФТЩ, ЧЕТОЕЕ ТБУЫЙТСАФУС УФБТЩЕ: EAX, EBX, ECX, EDX, ESP, EBP, EIP, ESI, EDI, เอฟแฟลกส์. LBL NPTsOP DPZBDBFSHUS, LFP 32-VYFOSHCHE CHETUYY PVSCHYUOSCHI TEZYUFTCH TEBMSHOPZP TETSYNB (L YNEOY TEZYUFTB DPVBCHMSEFUS RTYUFBCHLB "E") CHUE LFY 32-VYFOSHCHE TEZYUFTSHCH LTPNE EIP DPUFKHROSCH Y CH TEBMSHOPN TETSYNE, OP CH FBLPN UMHYUBE VHDHF OBOYNBFSH OB 1 VBKF VPMSHYE (LEYN DPVBCHMSEFUS UREGYBMSHOSHCHK RTEZHYLU) เกี่ยวกับ RTPGEUUPTE NPMPTS 286 FY LPNBODSCH VHDHF OELPTTELFOSCH nSch NPTSEN, OBRTYNET, OBRYUBFSH mov eax, 0x12345678 Y RPUME LFPZP H AX VKhDEF 0x5678, RPFPNH UFP ON LBL VSCHMSEFUS "PLOPN" H NMBDYHA YUBUFSH TEZYUFTTB EAX (BOBMPZYUOP, AL NMBDY AX) тЕЗЙУФТБ-ПФПВТБЦЕОЙС УФБТЫЕК ЮБУФЙ 32-ВЙФОЩИ ТЕЗЙУФТПЧ ОЕ УХЭЕУФЧХЕФ - НПЦОП ЕЈ ЙЪЧМЕЮШ ФПМШЛП У РПНПЭША БТЙЖНЕФЙЛЙ (ОБРТЙНЕТ, УДЧЙОХФШ EAX ОБ 16 ВЙФ ЧРТБЧП У РПНПЭША shr eax, 16, ФПЗДБ Ч AX ВХДЕФ УФБТЫБС РПМПЧЙОБ, ОП УПДЕТЦЙНПЕ НМБДЫЙИ ВЙФ ВХДЕФ ХФЕТСОП). юФП ИБТБЛФЕТОП, Ч ЪБЭЙЭЈООПН ТЕЦЙНЕ ОБПВПТПФ, ЛПНБОДЩ ТБВПФЩ У 16-ВЙФОЩНЙ ТЕЗЙУФТБНЙ (ОП ОЕ 8-ВЙФОЩНЙ) ФТЕВХАФ РТЕЖЙЛУ, РПЬФПНХ ОЕУНПФТС ОБ ФП, ЮФП ТБЪТСДОПУФШ Ч ДЧБ ТБЪБ ВПМШЫЕ, Ч ЪБЭЙЭЈООПН ТЕЦЙНЕ ВЩУФТЕЕ ЧЩРПМОСАФУС Й ЪБОЙНБАФ НЕОШЫЕ НЕУФБ ЙНЕООП ЛПНБОДЩ 32- VYFOPC BTYZHNEFILY

fBLCE, FERETSCH H OBU OB 2 UEZNEOFOSHCHI TEZYUFTB VPMSHIE - GS TH FS. TBVPFB U ONYY RPMOPUFSHHA BOBMPZYUOB DS Y ES Y CH NPTSEFE YI UCHPPVPDOP YURPMSHЪPCHBFSH CH TEBMSHOPN TETSYNE пФМЙЮЙЕ ФПМШЛП Ч ФПН, ЮФП ОЙЛБЛЙЕ ЛПНБОДЩ ЙИ СЧОП ОЕ РПДТБЪХНЕЧБАФ (DS ЙУРПМШЪХЕФУС РП ХНПМЮБОЙА РТБЛФЙЮЕУЛЙ ЧУЕНЙ ЛПНБОДБНЙ Й ОЕЛПФПТЩНЙ УФТПЛПЧЩНЙ ПРЕТБГЙСНЙ, ES ОЕЛПФПТЩНЙ УФТПЛПЧЩНЙ ПРЕТБГЙСНЙ) Й ОБДП СЧОП ХЛБЪЩЧБФШ, ЮФП ЧЩ ИПФЙФЕ ПВТБЭБФШУС ЮЕТЕЪ ОЙИ. BRIGHTNET, ย้ายขวาน, .

rPNYNP LFPZP TBUYTEOYS TEZYUFTCH, DPVBCHMSAFUS OPCHSHCHE HRTBCHMSAEIE TEZYUFTSHCH (TBOSHIE CHMYSM เกี่ยวกับ TETSYN TBVPFSCH RTPGEUUPTB FPMSHLP FLAGS) - CR0, CR2, CR3 TH CR4 EUFSH Y DTHZYE (OBRTYNET, PFMBDPYUOSCHE TEZYUFTSHCH), OP POY OBU UEKYUBU OE YOFETEUKHAF yNEOOP U RPNPESHA LFYI TEZYUFTCH RTPYJCHPDYFUS RETELMAYUEOYE RTPGEUUPTB H BEEYEIOOOSCHK TETSYN Y OBUFTPKLB OPCHSCHI ZHOLGYK CHTPDE UFTBOYUOPK BDTEUBGYY ร้องเพลง DPUFKHROSCH CH TEBMSHOPN TETSYNE

h ЪBEEIЈOOPN TETSYNE RPOSFIE UEZNEOFB YЪNEOSEFUS FERETSH FP OE RTPUFP VBPCHSHCHK BDTEU, B OPNET LMENEOFB (DEULTYRFPTB UEZNEOFB) CH UREGIBMSHOPK FBVMYGE fBVMYGB DEULTYRFPTPCH UEZNEOPFCH UPDBЈFUS PRETBGYPOOPK UYUFENPK Y NPTCEF UPDETTSBFSH OEPVIPDYNPE LPMYUEUFCHP PRYUBOYK UEZNEOPPCH ЪBEYEIIOOPZP TETSYNB LBCDShCHK LMENEOF FBVMYGSHCH BOINBEF 8 VBKF Y CH UREGIBMSHOPN ZHPTNBFE PRYUSCHCHBEF VBPCHSCHK BDTEU UEZNEOFB, TBNET, RTBCHB DPUFHRB Y F.D.

UEZNEOFSCH BEEIEIIOOPZP TETSYNB DEMSFUS เกี่ยวกับ DCHB FIRB - UEZNEOFSC LPDB Y UEZNEOFSC DBOOSCHI (เกี่ยวกับ UBNPN DEME EUFSH EEI CHUSLYE TSS Y LDT, OP RPLB ร้องเพลง OBNO OE CHBTSOSH FPTS) ชั่วโมง CS NPTsOP ЪBZTHTSBFSH FPMSHLP OPNETB DEULTYRFPTPCH, PRYUBOOSHCHI LBL UEZNEOF LPDB, Ch PUFBMSHOSHCHE UEZNEOFOSHCHE TEZYUFTSH NPTsOP ЪBZTHTSBFSH MAVSHE UEZNEOFSHCH - LBL DBOOSCHI, FBL Y LPDBL CHBTSOBS TBOYGB CH FPN, YuFP UEZNEOF LPDB NPTsOP FPMSHLP YUYFBFSH Y YURPMOSFSH, B UEZNEOF DBOOSCHI FPMSHLP YUYFBFSH และ RYUBFSH L Uyubufsha, ueresenofsh NPZHF RETELTSHCHSHS CH RBNSFY, RPFPNH UPDSOPPSHE DELTRFPTB Dultirfptb, Ushchmbaeus เกี่ยวกับ PDO FPF TEZIPO RBNSPHA, OPEI Oydbfsh yurpynchenshn

oEUNPFTS เกี่ยวกับ RPDDETZLH UEZNEOFBGYY, POB UYUYFBEFUS HUFBTECHYEK โอ้ Windows, โอ้ Linux OE YURPMSHHAF EE H RPMOPC NO, B OB PFMYUOSCHI PF x86 BTIYFELFHTSHCH (OBRTYNET, ARM) PB อะไร FUHFUFFCHHEF DMS TBZTBOYUEOIS DPUFHRB L RBNSFY YURPMSH'HEFUS ZPTBDDP VPMEE ZYVLYK NEIBOYN UFTBOYUOPK BDTEUBGYY, LPFPTSCHK NSC TBUUNPFTYN DBMEE YuFPVSCH YUVBCHIFSHUS PF UEZNEOFBGYY PU RTPUFP PRIUSHCHBEF FBVMIGH YU DULTIRFPPCH, X LBCDPZP YH LPFPSHSHK BDTEU 0, B TBIPHK RBNSTEPHEPHEPHEPHP h FBLPN UMHYUBE ZPCHPTSF, YuFP NSCH CHLMAYUYMY TETSYN MYOEKOSHCHI BDTEUPCH - UNEEEOYE UPPFFCHEFUFCHHEF ZHYYYYUEULPNH BDTEUKH. FP PYUEOSH KDPVOP YS RPKDH RP FPNKh CE RHFY. оЕ УМЕДХЕФ РЩФБФШУС ЙУРПМШЪПЧБФШ УЕЗНЕОФБГЙА Ч УЧПЕК ПРЕТБГЙПООПК УЙУФЕНЕ - ЬФП УЙМШОП ХУМПЦОСЕФ ЛПД СДТБ, СЪЩЛЙ ЧЩУПЛПЗП ХТПЧОС (ОБРТЙНЕТ, у ЙМЙ у++) ОЕ РПДДЕТЦЙЧБАФ УЕЗНЕОФБГЙА (ФП ЕУФШ ЧЩ УНПЦЕФЕ РПМОПГЕООП РТПЗТБННЙТПЧБФШ ФПМШЛП ОБ Assembler) Й, ОБЛПОЕГ, ЧЩ ОЕ УНПЦЕФЕ РЕТЕОЕУФЙ УЙУФЕНХ ОБ ДТХЗХА БТИЙФЕЛФХТХ, РПФПНХ ЮФП x86 ЕДЙОУФЧЕООБС, ЛПФПТБС ХНЕЕФ ЬФПФ НЕИБОЙЪН (Й ФП, Ч 64-ВЙФОПН ТЕЦЙНЕ РПМС ВБЪПЧПЗП БДТЕУБ Й ТБЪНЕТБ УЕЗНЕОФБ ЙЗОПТЙТХАФУС, Б ЙУРПМШЪХЕФУС МЙЫШ ЙОЖПТНБГЙС П РТБЧБИ ДПУФХРБ).

LBL S HCE ULBBM, FBVMYGB DEULTYRFPTPCH UEZNEOPHFCH ZHPTNYTHEFUS UBNPK PRETBGYPOOPK UYUFENPC. uFPVSC HLBBFSH RPGEUUPTH, ZDE POB OBIPDIFUS YURPMSHHEFUUS UREGYBMSHOBS LPNBODB - lgdt (โหลดตารางคำอธิบายส่วนกลาง) POB RTYOYNBEF 6-VBKFPCHHA RETENEOOHA CH RBNSFY. рЕТЧЩЕ ЕЈ 16 ВЙФ УПДЕТЦБФ ТБЪНЕТ ФБВМЙГЩ Ч ВБКФБИ (ФБЛЙН ПВТБЪПН, НБЛУЙНБМШОПЕ ЛПМЙЮЕУФЧП ДЕУЛТЙРФПТПЧ - 65536 / 8 = 8192), РПУМЕДХАЭЙЕ 32 ВЙФБ - ВБЪПЧЩК МЙОЕКОЩК БДТЕУ Ч РБНСФЙ УБНПК ФБВМЙГЩ (ФП ЕУФШ ВЕЪ ХЮЈФБ ЧУЕИ УЕЗНЕОФПЧ). yNEEF UNSCHUM CHSHCHTBCHOSFSH OBYUBMP FBVMYGSHCH OB 16 VBKF, RPFPNKh YUFP LFP HMHYUYBEF ULTPUFSH DPUFHRB L EY EMENEOFBN RETCSHCHK LMENEOF FBVMYGSHCH CHUEZDB DPMTSEO VSHCHFSH TBCHEO OHMA Y MAVPE YURPMSHCHCHCHBOYE OHMECHPZP UEMELFPTB(HLBBFEMSH เกี่ยวกับ MENEOF FBVMYGSCH DEULTYRFPTPCH CH UEZNEOFOPN TEZYUFTE OBSCCHCHBEFUS FBL) RTYCHPDYF L PYYVLE OBYUYF VPMEE-NEOE TBVPFPPURPUPVOBS FBVMYGB DEULTYRFPTPCH DPMTSOB UPDETTSBFSH IPFS VSC FTY DEULTYRFPTTB - RHUFPK, DEULTYRFPT LPDB, DEULTYRFPT DBOOSCHI

OH UFP EEJ UFPYF TBUULBЪBFSH, RTETSDE, YUEN NSCH RPRTPVKHEN RETEKFI CH ЪBEIEIIOOSCHK TETSYN? RPTsBMHK, EEI UFPYF HRPNSOHFSH RTP HTPCHOY DPUFHRB. LPD SDTB UYUFENSCH Y LPD RTYMPTSEOYK PFDEMEOSCH DTHZ PF DTHZB U FPK GEMSHHA YuFPVSHCH SDTP NPZMP RPMOPUFSHA HRTBCHMSFSH RTPGEUUPTPN B RTYMPTSEOIS OE NPZMY CHNEYBFSHUS H TBVPFH SDTB (CHEDSH HOB NOPYuPOS) LPD YURPMOSEFUS U PRTEDEMIOSCHN HTPCHOYEN RTYCHYMEZYK. ชั่วโมง x86 YI GEMSHI 4 YFKHLY - PF 0 DP 3. OHMECHPK HTPCHEOSH UBNSCHK RTYCHYMEZYTPCHBOOSCHK (NPCEF CHSHCHRPMOSFSH MAVSHE LPNBODSCH Y NEOSFSH TETSYNSCH TBVPFSCH RTPGEUUPTB), FTEFYK UBNSCHK "VEURTBCHOSCHK" LBB Comkhuba ที่ Uerezneoofbgyek, TBTBPFULY X86 RETEVPTAMYA ที่ Zholgypobmpn Yurpmshkhaf MYYSHA HTPCHOS YUEFSHTSHIEYA BTIZYEEPHPHTHPHPHTHPHTHPHTHPHTHPHTBB FPPHEUUUUUPTB FPPHEUUUUUUPTB FPPHEUUUPTBF FIPME x LBTsDPZP UEZNEOFB CH EZP DEULTYRFPTE HLBBO DPL (ระดับสิทธิ์ของตัวอธิบาย)- HTPCHEOSH DPUFHRB OEPVIPDYNSCHK DMS DBOOPZP UEZNEOFB oERTYCHYMEZYTPCHBOOSCHK LPD OE NPTCEF RPMHYUYFSH DPUFHR L UEZNEOPH U HTPCHOYEN DPUFHRB 0 B RTYCHYMEZYTPCHBOOSCHK LPD NPTCEF RPMHYUYFSH DPUFHR LP CHUEN UEZNEOFBN

уЕМЕЛФПТ УЕЗНЕОФБ, ЛПФПТЩК УПДЕТЦЙФУС Ч УЕЗНЕОФОПН ТЕЗЙУФТЕ, СЧМСЕФУС ОЕ РТПУФП ОПНЕТПН ЬМЕНЕОФБ Ч ФБВМЙГЕ, ОП Й ХЛБЪБФЕМЕН ХТПЧОС ДПУФХРБ - НМБДЫЙЕ 2 ВЙФБ УПДЕТЦБФ ХТПЧЕОШ РТЙЧЙМЕЗЙК (ПФ 0 ДП 3), Б ХЦЕ УФБТЫЙЕ ОПНЕТ УБНПК ФБВМЙГЩ. fBLYN PVBPN UEMELFPT = (YODELU_DEULTYRFPTB shl 2) + RPL อาร์พีแอล- ระดับสิทธิพิเศษที่ร้องขอ - RTY LFPN RPL DPMCEO VSCFS VPMSHY YMY TBCHEO NBLUINBMSHOPNH Ъ DPL й CPL (ระดับสิทธิ์ปัจจุบัน) CPL TBCHEO RPL UEMELFPTB H CS. fBLYN PVTBBPN LPD OE NPTCEF RPMKHYuYFSH DPUFHRB L UEZNEOFBN, H LPFPTSCHI HTPCHEOSH DPUFHRB CH YUYUMPCHPN CHYDE OYCE, YUEN X OEZP UBNPZP s, CHETPSFOP, PRIUBM DPUFBFPYuOP BRHFBOOP, OP CHRPMOE NPTsOP PVPKFYUSH RPL = DPL, LBL NSCH Y RPUFHRIN.

rPLB NSC RYYEN FPMSHLP SDTP, NSC VKHDEN TBVPFBFSH CH OKHMECHPN LPMShGE BEIFSHCH (FBL EEI OBSCCHBAF HTPCHOY RTYCHYMEZYK), YUFPVSH YNEFSH RPMOSHK DPUFHR L BRRBTBFKhTE

UEZNEOFBGYS OBN O OHTSOB, RPFPNKH S OE VKHDH PUFBOBCHMYCHBFSHUS RPLB UFP เกี่ยวกับ ZHPTNBFE DEULTYRFPTB, B DBN ZPFPCHSHCHE OBBYUEOYS eUMY YOFETEUOP, NPTSEFE RPYUYFBFSH LFH UFBFSHHA tBUUNPFTYN RTPUFEKYYK LPD RETEIPDB CH ЪBEYEIIOOSCHK TETSYN

; bBRHUL 32-TBTSDOPZP SDTB.start32: ; WHCHCHPDYN HCHEDPNMEOYE P BRHULE 32-VYFOPZP SDTB ย้าย si, start32_msg โทร write_str ; bztkhjn bobyueoye h GDTR lgdt ; bBRTEFYN RTETSHCHCHBOYS cli ; RETEKDYN H BEEYEIIOOSCHK TEZYN mov eax, cr0 หรือ eax, 1 mov cr0, eax ; RETEKDIN เกี่ยวกับ 32-VYFOSHK LPD jmp 8: start32 ; fBVMYGB DEULTYRFPTPCH UEZNEOPFC DMS 32-VYFOPZP SDTB จัดตำแหน่ง 16 gdt32: dq 0; โมฆะ - 0 dq 0x00CF9A000000FFFF ; รหัส - 8dq 0x00CF92000000FFFF ; ข้อมูล - 16 gdtr32: dw $ - gdt32 - 1 dd gdt32 ; 32-VYFOSHK LPD use32 start32: ; mov eax, 16 mov ds, ขวาน mov es, ขวาน mov fs, ขวาน mov gs, ขวาน mov ss, ขวาน movzx esp, sp ; WHCHCHPDYN UYNCHPM เกี่ยวกับ LLTBO mov ไบต์ "!" ; jmp$

FFPF LPD UMEDHEF DPRYUBFSH L

рЕТЕД РЕТЕИПДПН Ч ЪБЭЙЭЈООЩК ТЕЦЙН ОЕПВИПДЙНП ЪБРТЕФЙФШ РТЙЈН БРРБТБФОЩИ РТЕТЩЧБОЙК (ЛМБЧЙБФХТБ, НЩЫШ, ФБКНЕТ Й ДТХЗЙЕ ХУФТПКУФЧБ), РПФПНХ ЮФП BIOS РПУМЕ РЕТЕИПДБ ПУФБЈФУС ОЕ Х ДЕМ, Б УЧПЙ ПВТБВПФЮЙЛЙ НЩ ЕЭЈ ОЕ ОБРЙУБМЙ, РПЬФПНХ РЕТЧПЕ ЦЕ РТЕТЩЧБОЙЕ ПВТХЫЙФ УЙУФЕНХ.

oERPUTEDUFCHEOOP RETEIPD H ЪBEYEIIOOSCHK TETSIN PUKHEUFCHMSEF HUFBOPCHLB OHMECHPZP VYFB H CR0. yNEOOP LFP NSCH Y DEMBEN (RTSNPC DPUFKhR L CR0,2,3,4 OECHPЪNPTSEO FBL TSE LBL Y L UEZNEOFOSHCHN TEZYUFTBN, RPFPNKh YURPMSHEKHEN EAX) oEUNPFTS OB FP, UFP NSC HCE RETEYMY CH BEEIEIOOSHCHK TETSIN, LPD RTPDPMTSBEF YURPMOSFSHUS RP-RTETSOENH 16-VYFOSHCHK ดีเอ็มเอส dYTELFYCHB BUUENVMETB ใช้32 ZPCHPTYF ENH, UFP DBMSHOEKYK LPD CHSHCHRPMOSEFUS CH ЪBEEIЈOOPN TETSYNE Y OEVPVIPDYNP RETELMAYUYFSHUS CH TETSYN ZEOETBGYY LPNBOD DMS OEZP, B OE 16-VYFOPHEMPZP (PO YUFOPZP)

lPNBODB movzx TBUYTSEF CHFPTPK BTZHNEOF DP RETCHPZP h UNSHUME, YUFP YЪ 16 VYFOPZP OBBYUEOYS SP RPMHYUBEFUS 32-VYFOPE uFBTYYE VYFSCH PVOHMSAFUS (NBMP MY, UFP FBN VSCHMP DP OBU) rTEDRPUMEDOSS LPNBODB DENPOUFTYTHEF OBN CHPЪNPTSOPUFY ЪBEYEIIOOPZP TETSYNB - NSC PVTBEBENUS RP BVUPMAFOPNKH 32-VYFOPPNKh BDTEUKH L CHYDEP-RBNSFY FELUFPPCHPZP TETSYNB, CHSHCHPPMS UYNHCHPDS "!" CH RTBCHSHCHK OYTSOYK HZPM LTBOB (FELUFPCHSCHK LTBO YNEEF TBTEYOYE 80 x 25 Uinchpmch, LBCDShCHK UINCHPM BOINBEF CH RBNSFY DCHB VBKFB - LPD UINCHPMB Y EZP BFTYVHFSHCH GCHEFB)

NSC VPMSHIE OE NPTSEN PVTBEBFSHUS L UETCHYUBN BIOS, FERETSH RTYYMP CHTENS OBN UFBFSH RPMOPUFSHHA UBNPUFPSFEMSHOSHCHNY Y UBNYN HRTBCHMSFSH CHUEN PVPTKHDPCHBOYEN RETEBZTHTSBFSHUS Y TsDBFSH OBTSBFYS เกี่ยวกับ LMBCHYYH NSC RPLB OE HNEEN, RPFPNKh RTPUFP ЪBCHYUBEN U RPNPESHA LPNBODSCH jmp $ (RETEIPD เกี่ยวกับ FX CE UBNHA LPNBODH - VEULPOEYUOSCHK GILM)

h boot.cfg ทั่วไป LPNBODH S64 RPLB JBNEOIN OB S32 FERETSH, EUMY CHSHCHUY RTBCHYMSHOP UDEMBMY, OBY ЪBZTKHYUYL VKHDEF ЪBCHETYBFSH UCHPA TBVPFKH CHSHCHCHPDPN ChPULMYGBFEMSHOPZP ЪOBLB CH KhZPM LTBOB YЪ ЪBEYEIIOOPZP TETSYNB FP FPMSHLP OBUBMP. NS OBLPOEG-FP RTBLFYUEULY KHYMYY YЪ TEBMSHOPZP TETSYNB (บน UBNPN DEME FBN EEI PUFBMPUSH OENPZP DEM) H BEEYEIIOOSCHK Rpulpmshlh CHABZTHYUILEL CHCHRPMOSEFUS chMECHENEOFE TEBMshopzp Tekinb, Chueeoeeois Uppeffchhaf Zhyuyryotyipda Chuyoshchk Tsin, Oyuyuzp.

ชั่วโมง ЪBCHETEOYE CHSHCHHRULB, RPTsBMHK, DPVBCHMA RPUMEDOYK YFTYI - RTPCHETLKH, UFP RTPGEUUPT RPDDETSYCHBEF ЪBEIEIIOOSCHK TETSYN UHFSH RTPCHETLY CH FPN, UFP OE CHUE VYFSCH ธง NPTsOP YЪNEOYFSH RTPZTBNNOP FP EUFSH TEZYUFT OE อัพชูน 16-VYFOSHCHK เกี่ยวกับ OPCHSCHI RTPGEUPTBI DPUFHROP DMS YNEOEOYS VPMSHIE VYF Y FP NPTsOP PVOBTHTSYFSH TBVETYFE LPD OYCE UBNY, ULBTSH FPMSHLP, UFP LPNBODB pushf RPNEEBEF TEZYUFT ZHMBZPCH H UFEL, B popf CHCHFBMLYCHBEF UPDETSYNPE UFELP PE ธง fBLYN PVTBYPN EZP NPTsOP NEOSFSH GEMILPN, BOE PFDEMSHOSHCHNY LPNBODBNY CHPF RPMOSHCHK LPD OBYEZP ЪBZTKHYULB:

องค์กร 0x7C00 บูต jmp ; bZPMCHPL ListFS จัด 4 fs_magic dd ? fs_version dd ? fs_flags dd ? fs_base dq ? fs_size dq ? fs_map_base dq ? fs_map_size dq ? fs_first_file dq ? fs_uid dq ? fs_block_size dd ? ; bZPMCHPL JBKMB เสมือนที่ 0x800 f_info: f_name rb 256 f_next dq ? f_prev dq ? f_parent dq ? f_flags dq ? f_data dq ? f_size dq ? f_ctime dq ? f_mtime dq ? f_atime dq ? เสมือน ; DBOOSH OBJUBMSHOPZP JBZTHYULB ป้ายกำกับ sector_per_track คำที่ $$ ป้ายกำกับ head_count ไบต์ที่ $$ + 2 ป้ายกำกับ disk_id ไบต์ที่ $$ + 3 reboot_msg db "กดปุ่มใดก็ได้...",13,10,0 boot_file_name db "boot.bin",0 ; hHCHPD UFTPLY DS:SI OB LTLBO write_str: push si mov ah, 0x0E @: lodsb test al, al jz @f int 0x10 jmp @b @: pop si ret ; lTYFYUEULBS ข้อผิดพลาด PYVLB: ป๊อป si โทร write_str ; rete_bzthlb รีบูต: mov si, reboot_msg โทร write_str xor อา, อา int 0x16 jmp 0xFFFF:0 ; bZTHLB UELFPTB DX:AX H WCHET ES:DI load_sector: push dx เพิ่ม ax, word adc dx, word cmp byte, 0xFF je .use_EDD push bx cx si div mov cl, dl inc cl div mov dh, ah mov ch, al mov dl, mov bx, di mov al, 1 mov si, 3 @: mov ah, 2 int 0x13 jnc @f xor ah, ah int 0x13 dec si jnz @b .error: ข้อผิดพลาดในการโทร db "DISK ERROR",13,10 ,0 @: pop si cx bx dx ret .use_EDD: push si mov ไบต์, 0x10 mov ไบต์, 0 mov word, 1 mov , di push es pop word mov , ax mov , dx mov word, 0 mov word, 0 mov ah , 0x42 mov dl, mov si, 0x600 int 0x13 jc .error ป๊อป si dx ret ; rPYUL JBKMB U YNEOEN DS:SI H LBFBMPZE DX:AX find_file: push cx dx di .find: cmp ax, -1 jne @f cmp dx, -1 jne @f .not_found: ข้อผิดพลาดในการโทร db "ไม่พบ", 13, 10,0 @: mov di, f_info โทร load_sector push di mov cx, 0xFFFF xor al, al repne scasb neg cx dec cx pop di push si repe cmpsb pop si je .found mov ax, word mov dx, word jmp .find พบ: pop di dx cx ret ; ъBZTHЪLB FELHEEZP ZhBKMB Ch RBNSFSH RP BDTEUKh BX:0. lPMYUEUFFCHP JBZTHCEOOOSCHI UELFPTPCH CHPCHTBEBEFUS H AX load_file_data: push bx cx dx si di mov ax, word mov dx, word .load_list: cmp ax, -1 jne @f cmp dx, -1 jne @f .file_end: pop di si dx cx mov ax, bx pop bx sub ax, bx shr ax, 9 - 4 ret @: mov di, 0x8000 / 16 call load_sector mov si, di mov cx, 512 / 8 - 1 .load_sector: lodsw mov dx, เพิ่ม si, 6 cmp ax, -1 jne @f cmp dx, -1 je .file_end @: push es mov es, bx xor di, di โทร load_sector เพิ่ม bx, 0x200 / 16 pop es loop .load_sector lodsw mov dx, jmp .load_list ; fPYULB CHIPDB CH OBYUBMSHOSCHHK ЪBZTHYUYL บูต: ; oBUFTPYN WEZNEOFOSHCHE TEZYUFTSH jmp 0:@f @: mov ขวาน, cs mov ds, ขวาน mov es, ขวาน ; oBUFTPYN UFEL mov ss, ขวาน mov sp, $$ ; tbteyyn rtetschchchboys sti ; bRPNOIN OPNET bZTHЪpyuopzp DYULB mov , dl ; mov ah, 0x41 mov bx, 0x55AA int 0x13 jc @f mov ไบต์, 0xFF jmp .disk_detected @: mov ah, 0x08 xor di, di pushmov es int 0x13 pop es jc load_sector.error inc , dh cx, 111111b mov , cx disk_detected: ; bZTHJIN RTPPMTSEOYE OBJUBMSHOPZP bZTKHJULB mov si, boot_file_name mov ax, word mov dx, word call find_file mov bx, 0x7E00 / 16 โทร load_file_data ; RETEIPDYN เกี่ยวกับ RTPDPMCEOJE jmp boot2 ; rHUFPE RTPUFTBOUFCHP Y UYZOBFHTTB rb 510 - ($ - $$) db 0x55,0xAA ; dRPMYFEMSHOSHE DBOOSHE JBZTHYULB load_msg_preffix db "กำลังโหลด "",0 load_msg_suffix db "" ..",0 ok_msg db "ตกลง",13,10,0 config_file_name db "boot.cfg",0 start16_msg db "กำลังเริ่มต้นเคอร์เนล 16 บิต...",13,10,0 start32_msg db "กำลังเริ่มต้นเคอร์เนล 32 บิต ..",13,10,0 ; tBVEOYE UFTPLY DS:SI RP UYNCHPMH UMEYB split_file_name: push si @: lodsb cmp al, "/" je @f test al, al jz @f jmp @b @: mov ไบต์, 0 mov ax, si pop si ret ;bZTHJLB JBKMB U YNEOEN DS:SI N VHZET BX:0.tBNET JBKMB N UELFPTBI PPCHTBEBEFUS N AX load_file: push si mov si, load_msg_preffix call write_str pop si call write_str push si mov si, load_msg_s pop si กด si bp mov dx, word mov ax, word @: push ax call split_file_name mov bp, ax pop ax call find_file ทดสอบไบต์, 1 jz @f mov si, bp mov dx, word mov ax, word jmp @b @ : โทร load_file_data mov si, ok_msg call write_str pop bp si ret ; рТПДПМЦЕОЙЕ ОБЮБМШОПЗП ЪБЗТХЪЮЙЛБ boot2: ; ъБЗТХЪЙН ЛПОЖЙЗХТБГЙПООЩК ЖБКМ ЪБЗТХЪЮЙЛБ mov si, config_file_name mov bx, 0x1000 / 16 call load_file ; чЩРПМОЙН ЪБЗТХЪПЮОЩК ​​​​УЛТЙРФ mov bx, 0x9000 / 16 mov bp, 0x6000 mov dx, 0x1000 .parse_line: mov si, dx .parse_char: lodsb test al, al jz .config_end cmp al, 10 je .run_command cmp al, 13 je .run_command jmp .parse_char .run_command: mov ไบต์, 0 xchg dx, si ไบต์ cmp, 0 je .parse_line ; rHUFBS UFTPLB cmp ไบต์ "#" je .parse_line ; lPNNEOFBTYK ไบต์ cmp, "L" je .load_file ; bZTHJLB JBKMB cmp ไบต์ "S" je .start ; bBRHUL SDTB; oEYCHEUFOBS LPNBODB mov al, mov [.cmd], al call error db "Unknown boot script command "" .cmd db ? db ""!",13,10,0 .config_end: ; rTY RTBCHYMSHOPN LPOZHYZHTBGYPOOPN ZHBKME NSC OE DPMTSOSCH UADB RPRBUFSH; รีบูต jmp ; load_file: push dx inc si โทร load_file push ax mov cx, 512 mul cx mov word, ax mov word, dx mov word, 0 mov word, 0 mov ax, bx mov cx, 16 mul cx mov word, ax mov word, dx mov word, 0 mov word, 0 pop axe shr ax, 9 - 4 เพิ่ม bx, ax เพิ่ม bp, 16 pop dx jmp .parse_line ; bBRHUL SDTB.start: ; rTPCHETYN, UFP ЪBZTKhTSEO IPFS VSH PYO ZHBKM cmp bx, 0x9000 / 16 ja @f ข้อผิดพลาดในการโทร db "ไม่มีเคอร์เนลโหลด",13,10,0 @: ; bBRPMOSEN RPUMEDOIK LMENEOF URYULB JBKMPCH xor axe, axe mov cx, 16 mov di, bp rep stosw ; RETEIPDYN L RTPGEDHTE YOYGYBMYYBGYY SDTB DMS OHTSOPK TBTSDOPUPY inc si cmp word, "16" je .start16 cmp word, "32" je .start32 ;cmp word, "64" ;je start64 ; oEYCHEUFOBS TSTSDOPUFSH ข้อผิดพลาดในการโทร SDTB db "อาร์กิวเมนต์คำสั่งเริ่มต้นไม่ถูกต้อง",13,10,0 ; bBRHUL 16-TBTSDOPZP SDTB.start16: mov si, start16_msg mov bx, 0x6000 mov dl, jmp 0x9000 ; bBRHUL 32-TBTSDOPZP SDTB.start32: ; WHCHCHPDYN HCHEDPNMEOYE P BRHULE 32-VYFOPZP SDTB ย้าย si, start32_msg โทร write_str ; rTPCHETYN, UFP RTPGEUUPT OE IHCE i386 mov ax, 0x7202 push ax popf pushf pop bx cmp ax, bx je @f ข้อผิดพลาดในการโทร db "ต้องการ i386 หรือดีกว่า",13,10,0 @: ; bztkhjn bobyueoye h GDTR lgdt ; bBRTEFYN RTETSHCHCHBOYS cli ; RETEKDYN H BEEYEIIOOSCHK TEZYN mov eax, cr0 หรือ eax, 1 mov cr0, eax ; RETEKDIN เกี่ยวกับ 32-VYFOSHK LPD jmp 8: start32 ; fBVMYGB DEULTYRFPTPCH UEZNEOPFC DMS 32-VYFOPZP SDTB จัดตำแหน่ง 16 gdt32: dq 0; โมฆะ - 0 dq 0x00CF9A000000FFFF ; รหัส - 8dq 0x00CF92000000FFFF ; ข้อมูล - 16 gdtr32: dw $ - gdt32 - 1 dd gdt32 ; 32-VYFOSHK LPD use32 start32: ; mov eax, 16 mov ds, ขวาน mov es, ขวาน mov fs, ขวาน mov gs, ขวาน mov ss, ขวาน movzx esp, sp ; WHCHCHPDYN UYNCHPM เกี่ยวกับ LLTBO mov ไบต์ "! " ; 'สี่' jmp $

ในการเขียน OS คุณต้องเข้าใจรายละเอียดมากมาย ที่นี่ฉันขออธิบายให้คุณฟังเล็กน้อย (แต่ตกลงกันว่าคุณจะอ่านมานาด้วยตัวเอง
พูดตามตรง มีเนื้อหาเกี่ยวกับ PM มากมายบนอินเทอร์เน็ต และ iley และ pehat ได้พูดคุยกันเล็กน้อยเกี่ยวกับโหมดนี้ แต่ฉันถูกขอให้อธิบายในแง่ทั่วไปอยู่ดี ตอนนี้ฉันจะให้ทฤษฎีสั้น ๆ (จริง ๆ แล้ว Intel เขียนมานาเพื่อสิ่งนี้โดยเฉพาะ) จากนั้นเราจะเริ่มเขียนโค้ด

รู้เบื้องต้นเกี่ยวกับโหมดที่ได้รับการป้องกัน
ดังนั้น PM จึงแตกต่างอย่างมากจากทุกสิ่งที่คุ้นเคยตั้งแต่ DOS'a real mode (RM) ตอนนี้คุณต้องชินกับมัน: ไม่มีเซ็กเมนต์คงที่, 64 กิโลไบต์, ตารางขัดจังหวะใน 1 กิโลไบต์, ที่อยู่ฐานเซ็กเมนต์ในการลงทะเบียนเซ็กเมนต์, โดยทั่วไปแล้วเป็นโลกใหม่ที่สมบูรณ์
ขณะนี้มีการอธิบายส่วนต่างๆ ใน ตารางตัวอธิบายส่วนกลาง (GDT). ตารางนี้สามารถอยู่ในอินสแตนซ์เดียวเท่านั้น เธอคือโครงสร้างในความทรงจำ ไม่ใช่เซกเมนต์! สามารถอยู่ที่ใดก็ได้ในหน่วยความจำ แต่ที่อยู่และขีด จำกัด จะถูกเขียนลงในทะเบียน GDTR นี่คือโครงสร้าง:

ตัวตารางประกอบด้วยรายการของโครงสร้างต่อไปนี้ (อย่างไรก็ตาม รายการ null ว่างเปล่า นี่เป็นสิ่งสำคัญ เมื่อเข้าถึงหน่วยความจำ 'อธิบาย' โดยตัวอธิบาย null ให้รับ #GP - General Protection Fault):
ลองมาดูโครงสร้างนี้ให้ละเอียดยิ่งขึ้น

1. ขีดจำกัดของเซ็กเมนต์:
จุดประสงค์ของฟิลด์นี้ชัดเจนจากชื่อ แต่มีความละเอียดอ่อน สุนัขถูกฝังอยู่ในบิต G (ความละเอียด)
หากไม่ได้ตั้งค่าไว้ หน่วยความจำจะถูก 'นับ' เป็นไบต์ ในกรณีเช่นนี้ ขนาดเซ็กเมนต์อาจแตกต่างกันไปตั้งแต่ 1 ไบต์ถึง 1 เมกะไบต์ต่อ 1 ไบต์
หากเราตั้งค่าเป็น 1 การเพจหน่วยความจำจะถูกนำมาใช้ จากนั้นเราจะสามารถระบุ RAM จาก 4 กิโลไบต์เป็น 4 กิกะไบต์โดยปรับขนาด 4 กิโลไบต์ (ขนาดหน้า) โดยทั่วไป ควรใช้การระบุที่อยู่เพจ (เปรียบเทียบ (1Mb+64Kb-16byte) และ 4Gb) เรามาพูดถึงเฉพาะส่วนที่อยู่ในโพสต์นี้ การเพจสมควรได้รับการอภิปรายแยกต่างหาก

2.ที่อยู่พื้นฐาน:
ที่นี่เราระบุที่อยู่ทางกายภาพของฐาน

3. ช่องประเภท:
การผสมบิตกำหนดประเภทของเซ็กเมนต์:

4. S (ประเภทคำอธิบาย):
เอกสารของ Intel ระบุว่าหากไม่ได้ตั้งค่าบิตนี้ แสดงว่าคำอธิบายนี้มีไว้สำหรับส่วนระบบ มิฉะนั้น - รหัสหรือข้อมูล ระบบหมายถึง LDT, TSS, Interrupt Gates และอื่น ๆ ที่คล้ายกัน (เพิ่มเติมในภายหลัง)

5. DPL (ระดับสิทธิ์ของตัวอธิบาย):
สิทธิ์ของส่วนที่อธิบายไว้ ทุกคนรู้จักแหวน

6. P (ส่วนปัจจุบัน):
หากบิตนี้ถูกตั้งค่า โปรเซสเซอร์จะ 'รู้' ว่าเซกเมนต์นั้นอยู่ในหน่วยความจำแล้ว (แม้ว่าจะเป็นการดีกว่าที่จะพูดว่าถูกต้อง) หากคุณโหลดตัวเลือกคำอธิบายโดยไม่ได้ตั้งค่าบิต P ในการลงทะเบียนเซ็กเมนต์ จะเกิดข้อยกเว้น #NP (ไม่มีอยู่) โดยทั่วไปแล้ว ความหมายของวลีที่หรูหรานี้จะอธิบายในภายหลังเล็กน้อย

7.D/B:
สำหรับเซกเมนต์ประเภทต่างๆ นั้น จะถูกตีความแตกต่างกัน
1. สำหรับส่วนของรหัส:
ความยาวแอดเดรสและความยาวของตัวถูกดำเนินการ 32 หรือ 16 บิต
(1-32; 0-16);
2. สำหรับกอง:
ตัวชี้สแต็กคือ 32 หรือ 16 บิต (1-32; 0-16);

8.G:
อิทธิพลในหน่วยใด (ไบต์, หน้า) วัดขีดจำกัดของเซ็กเมนต์ โดยทั่วไป สามารถเปิดใช้งานการเพจได้เมื่อป้อน PM โดยการตั้งค่าบิต 31 ของการลงทะเบียน CR0

ข้อมูลเพิ่มเติม:
เราเดาว่าคำว่า Global นั้นไม่ได้ไร้ประโยชน์ ก็เลยมีวี่แววอีก จริงอยู่เช่นกัน ตารางคำอธิบายท้องถิ่น. อาจมีจำนวนมากของพวกเขา ตัวอย่างเช่นสามารถใช้ในการดำเนินงาน ฯลฯ และที่นี่ แอลดีทีเป็นตัวแทนของกลุ่มแล้ว! เพื่อให้คุ้นเคยกับวลีเช่น

หลังจากที่เราอธิบายตารางแล้ว เราต้องโหลดลงในทะเบียน จีดีทีอาร์. สิ่งนี้ทำได้ไกลจาก mov จีดีทีอาร์เติมเต็มโดยทีม lgdt fword (ค่า). นั่นคือจำเป็นต้องสร้างโครงสร้างนี้ด้วยตัวคุณเองและโหลดลงในทะเบียนดังกล่าว ยังมีทีมที่ทำงานกับการลงทะเบียนนี้ แต่เรากำลังควบม้าไปทั่วยุโรป

อีกสักครู่ ใน PM การลงทะเบียนเซ็กเมนต์จะไม่เก็บที่อยู่พื้นฐานของเซ็กเมนต์ (เหมือนใน RM) แต่เรียกว่าชิ้นส่วนที่ได้รับการฝึกฝนเป็นพิเศษ ตัวเลือก. โครงสร้างของพวกเขาคือ:

นี่ ดัชนี คือเลขลำดับของตัวอธิบายในตาราง
TI แสดงตำแหน่งที่จะค้นหาคำอธิบาย (ใน จีดีทีหรือ แอลดีที).

ตอนนี้เป็นที่ชัดเจนแล้วว่าจะสร้างตารางได้อย่างไร เรามาพูดถึงวิธีเปลี่ยนเป็น PM (ฉันทราบว่าสิ่งนี้สามารถทำได้จาก RM เท่านั้น) โดยทั่วไป... สิ่งที่คุณต้องทำคือตั้งค่าบิต 0 ของรีจิสเตอร์ควบคุม CR0 แม้ว่าฉันจะโกหก ก่อนอื่นคุณต้องปิดการใช้งานการขัดจังหวะทั้งหมด ( สนช (การขัดจังหวะที่ไม่สามารถปิดบังได้) รวมถึง) เปิดบรรทัดที่อยู่ A20(เพื่อให้สามารถระบุที่อยู่แบบ 32 บิตได้) ดาวน์โหลด จีดีทีอาร์และข้ามไปที่เครื่องหมาย - เริ่ม

ลองใช้ตัวโหลด (คุณสามารถใช้ KOLIBRI's ได้) ซึ่งจะโหลดรหัสของเราตามที่อยู่ 1,000h: 0 (ฉันทราบที่อยู่ของ RM)
ที่นี่ทุกอย่างจะไม่ราบรื่นเหมือนในมานาเหล่านั้นเมื่อพวกเขาเปลี่ยนเป็น PM โดยตรงจาก bootloader ทุกอย่างซับซ้อนขึ้นเล็กน้อย แต่ก่อนอื่นให้ดูที่รหัสที่ bootloader จะโหลด (เราเขียนทุกอย่างใน FASM "e) นี่คือ helloworld ชนิดหนึ่ง มาเริ่มกันเลยไปที่ PM แล้วพิมพ์คำทักทาย แค่นั้นแหละ

รูปแบบไบนารี
xorax,ขวาน
cli ; เริ่มต้นการลงทะเบียนเซ็กเมนต์ใหม่
ย้าย ss,ขวาน
ซอร์ส, sp
สตี
มูวอกซ์,3
ภายใน 10 ชม

Jmp 1,000 ชม.:r_start

ย้ายขวาน 1,000 ชม. กำหนดค่ารีจิสเตอร์ใหม่
ย้าย ds,ขวาน
ย้าย es,ขวาน

ใน al, 0x92 เปิดใช้งาน A20
หรืออัล 2
ออก 0x92 อัล

Lgdt fword โหลดการลงทะเบียน GDTR
ย้าย eax,cr0
หรือ al,1;set บิต 0
mov cr0,eax;เปิด PM

jmp fword 08h:Startup32; ข้ามไปที่ PM

Align 8 ; โปรเซสเซอร์จัดการเพลตที่จัดเรียงเร็วขึ้น
จีดีที:
dq 0 ;ว่าง
db 0FFh,0FFh,0,0,0,9Ah,0CFh,0 ;รหัส
db 0FFh,0FFh,0,0,0,92h,0CFh,0;ข้อมูล
db 0FFh,0FFh,0,80h,0Bh,92h,40h,0 ; ส่วนวิดีโอ
ติดป้ายกำกับ GDT_SIZE ที่ $-GDT
GDTR:
dw GDT_SIZE-1
ddGDT+10,000ชม
; คุณต้องเขียนที่อยู่ 32 บิต ตอนนี้เราอยู่ในส่วน 1,000h ซึ่งฐานคือ 1,000h*10h (โดย; ที่อยู่จริง) => ที่อยู่จริงของ GDTR (ป้ายกำกับ!) = 10,000h (ที่อยู่จริงของฐานเซ็กเมนต์)+ออฟเซ็ต

เสมือน อันที่จริง ตอนนี้ เราเติมช่องว่างจนถึงจุดสิ้นสุดของส่วน
rb 10,000h-$;
สิ้นสุดเสมือน
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;
ใช้32
org $+10000h; นี่คือสิ่งที่: ใน PM เราทำงานกับส่วน Flat และถ้าเราทิ้งรหัสไว้ สำหรับ PM ก่อน org ดังนั้น ที่อยู่ภายในส่วนจะไม่ตรงกับที่อยู่ Flat ดังนั้น.

Startup32: ;PM จุดเริ่มต้น
mov ax,10h ;เลื่อนตัวเลือกที่นี่ บ่อยครั้ง (! อย่าลืมเกี่ยวกับหมายเลขซีเรียลใน
mov es,ax ;table) ตัวเลือกส่วนรหัส - 08h ข้อมูล - 10 ชม. ส่วนวิดีโอ - 18 ชม
ย้าย ds,ขวาน
mov fs,ขวาน
ย้าย ss,ขวาน
ย้าย esp, 10,000h สแต็ค
มูแว็กซ์ 18 ชม
mov gs,ขวาน

mov esi,hi_string แสดงว่าเราผ่านสำเร็จแล้ว
โทรพิมพ์
jmp$

;ESI - ที่อยู่สตริง
พิมพ์:
ดัน
xor ebx, ebx
mov ah,07h;แอตทริบิวต์
ใส่:
ย้ายอัล,
ย้ายขวาน
inc ebx
ทดสอบอัลอัล
jnz ใส่
ป๊อปแพด
เกษียณ
hi_string db 'ยินดีต้อนรับสู่ PM เพื่อน',0

เราได้ทำอะไร? ตัวโหลดโหลดเราสำเร็จในเวลา 1,000 ชม.:0 จากที่เราดำเนินการต่อไป เปิดเครื่องครั้งแรก A20, ปิดใช้งานการขัดจังหวะทั้งหมด, โหลดเข้า จีดีทีอาร์ค่าที่เหมาะสม กระโดดไปที่ป้ายกำกับรายการ ฉันทราบว่าเรากระโดดขึ้นไป
jmp fword 08h:Startup32
เช่น 08h - ตัวเลือกคำอธิบายรหัส คุ้นเคยกับมัน

ตอนนี้จะเริ่มปาฏิหาริย์นี้ได้อย่างไร ส่วนตัวฉันใช้ WinImage และ VirtualBox เราผลัก bootloader เข้าไปในฟล็อปปี้บูตเซกเตอร์และวางไฟล์ .bin ไว้ที่รูท เราบันทึกไว้ใน .vfd เขียนเส้นทางไปยังอิมเมจฟล็อปปี้ดิสก์ในคุณสมบัติของเครื่องเสมือน เรียกใช้และดูผลลัพธ์

ในฉบับหน้า เราจะพิจารณาถึงการขัดจังหวะ ข้อบกพร่อง กับดัก การยกเลิก และวิธีการทำงาน ถูกจับและดีบั๊ก เรามาเริ่มพูดถึงสถาปัตยกรรมกันดีกว่า

แหล่งข้อมูล.
1) ฉันแค่ต้องการแสดงความขอบคุณต่อ Phantom_84 หรืออีกชื่อหนึ่งว่าอัตตาที่แสดงเส้นทางที่ถูกต้องและช่วยเหลือฉันตั้งแต่เริ่มต้น หากไม่มีเขาคงยากขึ้นมากสำหรับฉันที่จะเข้าใจ

โปรเซสเซอร์ทั้งหมด อินเทลเริ่มต้นด้วย i80286 และล่าสุด เมื่อเปิดเครื่อง (หลังจาก "รีเซ็ต" เริ่มต้น) จะทำงานในโหมดที่อยู่จริง (โหมดจริง) โดยทั่วไปแล้ว โหมดจริงจะใช้เป็นสื่อกลางสำหรับการสลับไปยังโหมดป้องกันหลังจากการเริ่มต้นระบบไมโครโปรเซสเซอร์ หรือเพื่อการดำเนินการโปรแกรมที่เขียนขึ้นสำหรับไมโครโปรเซสเซอร์เร็วขึ้น 8086 , 80186 แต่เมื่อเทียบกับ 8086 , 80186 ไมโครโปรเซสเซอร์ที่ทันสมัยในโหมดจริงมีชุดคำสั่งปฏิบัติการที่กว้างขึ้นและความสามารถในการประมวลผลตัวถูกดำเนินการแบบ 32 บิต
การสลับโปรเซสเซอร์เป็นโหมดป้องกันจากโหมดจริงทำได้โดยการบูตเข้า CR0(รูปที่ 1) คำที่มีค่าเดียวของบิต PE ( เปิดใช้งานการป้องกัน). สำหรับความเข้ากันได้กับซอฟต์แวร์สำหรับ 80286 ยังสามารถตั้งค่าบิต PE โดยคำสั่ง LMSW ก่อนสลับหน่วยความจำ ต้องเตรียมใช้งานตารางคำอธิบายที่จำเป็น ไอดีทีและ จีดีที. ทันทีที่เปิดใช้งานโหมดป้องกัน โปรเซสเซอร์จะมี ซีพีแอล = 0.

ข้าว. 1

สำหรับโปรเซสเซอร์ 32 บิตทั้งหมด ขอแนะนำให้ทำตามลำดับขั้นตอนต่อไปนี้เพื่อเปลี่ยนเป็นโหมดที่ได้รับการป้องกัน:
1. ปิดใช้งานการขัดจังหวะที่ปิดบังได้โดยการรีเซ็ตแฟล็ก IF และบล็อกการเกิดขึ้นของการขัดจังหวะที่ปิดบังไม่ได้โดยตรรกะภายนอก รหัสโปรแกรมในช่วง “ช่วงเปลี่ยนผ่าน” ต้องรับประกันว่าจะไม่มีข้อยกเว้นและไม่ใช้การขัดจังหวะของซอฟต์แวร์ ข้อกำหนดนี้เกิดจากการเปลี่ยนแปลงกลไกในการเรียกตัวจัดการการขัดจังหวะ
2. อัพโหลดไปที่ จีดีทีอาร์ที่อยู่พื้นฐาน จีดีที(โดยคำสั่ง LGDT)
3. คำแนะนำ MOV CROตั้งค่าสถานะ PE และหากจำเป็นต้องใช้หน่วยความจำเพจ ให้เลือกตั้งค่าสถานะ PG
4. หลังจากนี้ คำสั่งกระโดดระหว่างเซกเมนต์ ( เจเอ็มพีฟาร์) หรือโทร ( โทรไกล) เพื่อล้างคิวของคำสั่งถอดรหัสโหมดจริง และดำเนินการทำให้เป็นอนุกรมของ CPU หากเปิดใช้การเพจ รหัสคำสั่ง MOV CROและ จ.ส.อหรือ เรียกต้องอยู่ในหน้าที่ที่อยู่จริงตรงกับโลจิคัล (สำหรับรหัสที่โอนการควบคุม ข้อกำหนดนี้จะไม่บังคับ)
5. หากคุณวางแผนที่จะใช้ตารางคำอธิบายในเครื่อง คำแนะนำ แอล.แอล.ดีโหลดตัวเลือกส่วนสำหรับ แอลดีทีเพื่อลงทะเบียน แอลดีทีอาร์
6. คำแนะนำ ร.ฟ.ทโหลดลงในตัวเลือกการลงทะเบียนงาน สสสสำหรับงานโหมดป้องกันเริ่มต้น
7. รีโหลดเซ็กเมนต์รีจิสเตอร์ (ยกเว้น CS) ซึ่งเนื้อหายังคงเป็นโหมดจริง หรือทำการเปลี่ยนแปลงหรือเรียกใช้งานอื่น (ในกรณีนี้ รีจิสเตอร์จะถูกรีโหลดโดยอัตโนมัติ) การลงทะเบียนเซกเมนต์ที่ไม่ได้ใช้จะถูกโหลดด้วยตัวเลือกศูนย์
8. คำแนะนำ ลิดอัพโหลดเพื่อลงทะเบียน IDTRที่อยู่และวงเงิน ไอดีที- ตารางคำอธิบายขัดจังหวะโหมดป้องกัน
9. อนุญาตการขัดจังหวะของฮาร์ดแวร์ทั้งแบบสวมหน้ากากและไม่สวมหน้ากาก

บทความนี้ให้ข้อมูลเบื้องต้นเกี่ยวกับการพัฒนาโปรแกรมที่ทำงานในโหมดป้องกันของโปรเซสเซอร์ ที่นี่งานหลักของโปรแกรมใด ๆ ที่ทำงานในโหมดป้องกันและจะได้รับการตั้งค่าและแนวทางแก้ไข โดยพื้นฐานแล้วโปรแกรมจะเขียนด้วยภาษา FASM.

โหมดการทำงานของโปรเซสเซอร์ Intel 80386

ด้วยการกำเนิดของโปรเซสเซอร์ อินเทล 80386สถาปัตยกรรมเกิดขึ้น IA32. ถือว่าการเกิดขึ้นของโหมดการทำงานของโปรเซสเซอร์ใหม่ - ได้รับการป้องกัน (" โหมดป้องกัน") เพื่อความเข้ากันได้กับโปรเซสเซอร์ก่อนหน้าในบรรทัด อินเทล 80x86ซีพียู 80386 ไม่ได้เริ่มทันทีในโหมดป้องกัน แต่ทำงานในโหมดจริงที่เรียกว่า (" โหมดจริง") นอกจากนี้ แต่ละโหมดยังมีโหมดย่อยอย่างน้อย 1 โหมด มาวิเคราะห์กัน

โหมดจริง

ในโหมดนี้ โปรเซสเซอร์จะทำงานทันทีหลังจากกดปุ่ม " พลัง"คอมพิวเตอร์ หน่วยความจำโหมดจริงเข้าถึงได้ด้วยการออกแบบ" ส่วน:ชดเชย" ซึ่งอธิบายที่อยู่แบบลอจิคัล ค่าเซ็กเมนต์ เช่น ออฟเซ็ต มีตั้งแต่ 0 ก่อน 0FFFFh.

เนื่องจากคุณสามารถระบุภายในกลุ่มเดียวเท่านั้น ขนาดกลุ่มสูงสุดคือ 64 กิโลไบต์ ที่อยู่ทางกายภาพที่ตั้งค่าบนแอดเดรสบัสของตัวประมวลผลคำนวณโดยสูตร:

ที่อยู่เชิงเส้น = ส่วน * 16 + ออฟเซ็ต

โปรเซสเซอร์โหมดจริง 80186 และ 8086 ค่าเซกเมนต์อยู่ในช่วงตั้งแต่ 0 ก่อน 0F000h. ดังนั้นแอดเดรสที่เปิดเผยสูงสุดบนแอดเดรสบัสคือ 0FFFFFFhซึ่งสอดคล้องกับ (2^20)-1 , เช่น. 1 เมกะไบต์

แน่นอนว่าในตอนแรกจำนวนหน่วยความจำดังกล่าวดูใหญ่โต แต่เมื่อเวลาผ่านไปหนึ่งเมกะไบต์ก็ไม่เพียงพอ ด้วยการกำเนิดของโปรเซสเซอร์ 80286 บล็อกหน่วยความจำที่เรียกว่าพร้อมใช้งาน ยูเอ็มบีเริ่มต้นด้วยที่อยู่ 0FFFFh:0010ชมและลงท้ายด้วยที่อยู่ 0FFFFh:0FFFFh(65520 ไบต์เกินกว่าหนึ่งเมกะไบต์) ตอนนี้เป็นไปได้ที่จะกำหนดค่าระบบปฏิบัติการใหม่ เอ็มเอส-ดอสเพื่อให้ตรงบริเวณบล็อกนี้ ทำให้ RAM ว่าง 64 กิโลไบต์

โหมดป้องกัน

โหมดนี้มีโครงสร้างที่ซับซ้อนเมื่อเทียบกับของจริง ที่อยู่ตรรกะแสดงโดยโครงสร้าง " ตัวเลือก:ออฟเซ็ต" ตัวเลือกอยู่ระหว่าง 0 ก่อน 0FFFFh(ในความเป็นจริงมีตัวเลือกน้อยกว่า 4 เท่า - ข้อมูลเพิ่มเติมในบทความต่อไปนี้) ออฟเซ็ตซึ่งแตกต่างจากโหมดจริงคือ 32 บิตซึ่งอนุญาตให้ระบุเซกเมนต์ 4 กิกะไบต์ ที่อยู่เชิงตรรกะจะถูกแปลงเป็นที่อยู่เชิงเส้นตามโครงร่างต่อไปนี้:

ที่อยู่เชิงเส้น = ฐานส่วน + ออฟเซ็ต

จากนั้นแอดเดรสเชิงเส้นจะถูกตั้งค่าเป็นแอดเดรสบัส เว้นแต่จะเปิดใช้งานโหมดการเพจ มิฉะนั้นที่อยู่เชิงเส้นจะถูกแปลงเป็นที่อยู่จริงและหลังจากนั้นจะถูกตั้งค่าเป็นบัสที่อยู่ นอกจากนี้ โหมดที่ได้รับการป้องกันยังช่วยให้คุณจัดระเบียบหน่วยความจำเสมือน โดยมีขนาดสูงสุด 64 เทราไบต์ และขึ้นอยู่กับขนาดของฮาร์ดดิสก์เท่านั้น (ตัวอย่างเช่น ไฟล์เพจจิ้งเดียวกันใน หน้าต่างใช้หน่วยความจำเสมือน) ระบบปฏิบัติการสมัยใหม่เกือบทั้งหมดทำงานในโหมดป้องกัน

โหมดย่อยโหมดที่ได้รับการป้องกันแบบมัลติทาสกิ้ง

โหมดนี้ช่วยให้คุณจัดระเบียบการทำงานหลายอย่างพร้อมกัน นั่นคือความสามารถในการทำงานหลายอย่างพร้อมกันหรือระบบที่มีผู้ใช้หลายคน

โหมดเสมือน 8086

นอกจากนี้ยังเป็นโหมดย่อยของโหมดป้องกันที่ช่วยให้คุณสร้างเครื่องเสมือนที่ทำงานราวกับว่าอยู่ในโหมดจริง แต่จริง ๆ แล้วกำลังทำงานในโหมดป้องกัน

โหมดไม่จริง

นี่คือโหมดย่อยพิเศษของโหมดจริง โปรเซสเซอร์อยู่ในโหมดจริง แต่กำลังระบุหน่วยความจำด้วยการสร้าง " ตัวเลือก: ออฟเซ็ต" ดังนั้นจึงมีหน่วยความจำที่สูงกว่า 1 เมกะไบต์ ในอนาคตจะมีการพิจารณาโหมดป้องกันและโหมดย่อย

โปรแกรมแรก: เปลี่ยนเป็นโหมดป้องกัน

การสลับเป็นโหมดป้องกันทำได้โดยการตั้งค่าบิต 0 ลงทะเบียน CR0. การเปลี่ยนไปใช้โหมดจริงนั้นดำเนินการโดยการรีเซ็ตบิตศูนย์เดียวกัน พิจารณาโปรแกรมที่ดำเนินการนี้ (ภาษา - แอสเซมเบลอร์แบบแบน):

การใช้งาน16 ; ใช้คำสั่ง 16 บิต

องค์กร 100 ชม

เริ่ม:

; เราอยู่ในเวลาจริง

ย้าย eax,cr0 ; อ่านค่าของรีจิสเตอร์ CR0
หรืออัล, 1 ; ตั้งค่าศูนย์บิต
ย้าย cr0,eax ; เขียนค่าใหม่เป็น CR0

; เราอยู่ในโหมดปลอดภัย

ย้าย eax,cr0 ; การอ่านค่า CR0
และอัล, 0feh ; รีเซ็ตศูนย์บิตเป็น 0
ย้าย cr0,eax ; เปลี่ยนเป็นโหมดจริง

; เราอยู่ในเวลาจริง

เกษียณ ; ออกจากโปรแกรม

อย่างไรก็ตามโปรแกรมนี้ค่อนข้าง "ดิบ" เนื่องจากไม่สามารถใช้การวนซ้ำได้ หากคุณเขียนคำสั่งเช่น หรือ jmp$จากนั้นเมื่ออินเตอร์รัปต์แรกถูกทริกเกอร์ คอมพิวเตอร์จะรีสตาร์ท

ในกรณีของเรา คำสั่งทำงานค่อนข้างเร็ว แต่เป็นไปได้ว่าในช่วงเวลาระหว่างการดำเนินการของคำสั่งใด ๆ ของโปรแกรมของเรา การขัดจังหวะจะยังคงทำงาน ซึ่งจะนำไปสู่การหยุดทำงานทันทีและรีบูต ดังนั้นคุณควรดูแลการขัดจังหวะ ดังนั้น เรามาดูรายชื่อกันอีกครั้ง สิ่งนี้ไม่สามารถเรียกได้ว่าเป็นโปรแกรมแรก (แต่จะเป็นศูนย์) เนื่องจากไม่ได้ใช้การดำเนินการหลักในการเปลี่ยนเป็นโหมดป้องกัน หากต้องการเปลี่ยนเป็นโหมดป้องกันโดยสมบูรณ์ด้วยการตั้งค่าขั้นต่ำ คุณต้องทำตามขั้นตอนต่อไปนี้:

1. ตรวจสอบว่าสามารถเปลี่ยนเป็นโหมดป้องกันได้หรือไม่

2. เริ่มต้นตารางคำอธิบาย;

3. ปิดใช้งานการขัดจังหวะ (ทั้งแบบสวมหน้ากากได้และไม่ได้สวมหน้ากาก);

4. เปิดสาย A20;

5. โหลดการลงทะเบียนการจัดการหน่วยความจำ

7. ข้ามไปยังส่วนรหัส 32 บิตโดยแทนที่การลงทะเบียน CS

แต่ก็เพียงพอแล้วสำหรับโปรแกรมแรกที่จะทำตามขั้นตอนที่ 3, 4, 5 จากนั้นการวนซ้ำจะไม่รีสตาร์ทคอมพิวเตอร์ มาดูกันทีละขั้นตอน

การปิดใช้งานการขัดจังหวะทำให้เราไม่สามารถรีบูตเครื่องได้ การขัดจังหวะแบ่งออกเป็นแบบสวมหน้ากากได้และไม่สวมหน้ากาก หากต้องการปิดใช้งานการขัดจังหวะที่ปิดบังได้ ให้ล้างค่าสถานะ ถ้าลงทะเบียน เอฟแฟลกส์ทีม คลิในขณะที่การขัดจังหวะเปิดใช้งานโดยคำสั่ง สตี. การขัดจังหวะที่ไม่สามารถปิดบังได้จะถูกปิดใช้งานด้วยวิธีที่แตกต่างกันเล็กน้อย มีสองวิธีในการทำเช่นนี้: การเขียนโปรแกรมควบคุมการขัดจังหวะการลงทะเบียน (วิธีการนี้จะกล่าวถึงในภายหลัง) หรือเปลี่ยนบิตที่เจ็ดของพอร์ต 70 ชม: ถ้าบิตถูกตั้งค่า การขัดจังหวะจะถูกปิดใช้งาน ถ้าบิตนั้นชัดเจน การขัดจังหวะก็สามารถทำได้

ทีนี้ลองถามตัวเองว่าหน้าที่ของเส้นคืออะไร A20แล้วนี่คืออะไร เส้น A20- หนึ่งใน 32 บรรทัดที่อยู่ เมื่อคอมพิวเตอร์บูทขึ้นบรรทัด A20ปิด. สิ่งนี้นำไปสู่การสร้างที่อยู่ 20 บิต (นั่นคือพื้นที่ที่อยู่ทั้งหมดเท่ากับ (2^20)=1 เมกะไบต์) สิ่งนี้ถูกนำมาใช้เพื่อความเข้ากันได้กับโปรเซสเซอร์ 8086 : จึงพยายามเขียนไปยังที่อยู่เชิงเส้น 12345678hจริง ๆ แล้วเราเขียนถึงที่อยู่ 00045678หซึ่งอาจนำไปสู่ผลลัพธ์ที่คาดไม่ถึงโดยสิ้นเชิง ดังนั้นสำหรับการทำงานเต็มรูปแบบของแอปพลิเคชัน 32 บิต บรรทัด A20ต้องเปิด สิ่งนี้ทำได้โดยการตั้งค่าบิต 1 ท่าเรือ 92 ชม, การปิดบรรทัด A20- รีเซ็ตบิตนี้

ผู้อ่านคุ้นเคยกับการกระทำล่าสุดแล้ว และไม่ควรทำให้เขาเกิดคำถามอีกต่อไป

ลองดูรายการโปรแกรมใหม่ของเราก่อนซึ่งมีการติดตั้งลูปขนาดเล็กแล้ว แถวที่เพิ่มไปยังรายการก่อนหน้าจะถูกทำเครื่องหมายด้วยเครื่องหมายดอกจัน (*)

องค์กร 100 ชม

เริ่ม:

; เราอยู่ในเวลาจริง

คลิ ;*

ในอัล, 70h ;*
หรืออัล 80h ;*
ออก 70h,อัล ;*

; เปิดสาย A20

ในอัล, 92h ;*
หรืออัล 2 ;*
ออก 92h, อัล ;*

ย้าย eax,cr0
หรืออัล, 1
ย้าย cr0,eax


; รอบคู่ขนาดเล็ก

ย้าย cx, 20 ;*

รอบ: ;*
ย้ายขวาน, cx ;*
ย้าย cx, 0ffffh ;*
ห่วง $ ;*
ย้าย cx, ขวาน ;*
ห่วงรอบ ;*

ย้าย eax,cr0
และอัล, 0feh
ย้าย cr0,eax

; ปิดบรรทัด A20

ในอัล, 92h ;*
และอัล 0fdh ;*
ออก 92h, อัล ;*

ในอัล, 70h ;*
และอัล 7fh ;*
ออก 70h,อัล ;*

สตี ;*

เกษียณ ; กรอกโปรแกรม

คุณสามารถตรวจสอบให้แน่ใจว่าโปรแกรมทำงานโดยการเรียกใช้ไฟล์ปฏิบัติการจากไฟล์ที่สะอาด เอ็มเอส-ดอส. หากโปรแกรมจบลงอย่างถูกต้องทุกอย่างก็เรียบร้อย

อย่างไรก็ตาม ปัญหาต่อไปนี้อาจเกิดขึ้น:

1. คอมพิวเตอร์ค้าง";

2. คอมพิวเตอร์รีสตาร์ท

สิ่งนี้อาจเกิดขึ้นเนื่องจากสาเหตุต่อไปนี้:

1. โปรแกรมที่กำลังทำงานอยู่ V86(เสมือน 8086 );

2. โปรแกรมกำลังทำงานในโหมดป้องกันหรือภายใต้ระบบปฏิบัติการเฉพาะ

ดังนั้นก่อนที่จะเริ่มโปรแกรมใด ๆ ที่ทำงานในโหมดป้องกัน คุณควรตรวจสอบความเป็นไปได้ของการทำงานเพิ่มเติมของโปรแกรม นี้จะกล่าวถึงต่อไป

ตรวจสอบความสามารถในการเปลี่ยนเป็นโหมดป้องกัน

ในบทที่แล้ว เรามีปัญหาต่อไปนี้: โปรแกรมไม่รู้จักว่าอยู่ในโหมดป้องกันหรือ V86ซึ่งทำให้ระบบค้างหรือรีบูต หากเราลองรันโปรแกรมภายใต้ระบบปฏิบัติการ หน้าต่าง, ที่ หน้าต่างจะตรวจจับความพยายามของโปรแกรมในการเปลี่ยนเป็นโหมดป้องกันและแจ้งให้คุณรีบูตในโหมดจำลอง เอ็มเอส-ดอส(สำหรับแพลตฟอร์ม 9 เท่า) หรือยุติโปรแกรมโดยบังคับ (แพลตฟอร์ม เอ็นที).

ดังนั้นเพื่อตรวจสอบว่าเราอยู่ในโหมดจริงจริง ๆ เราควรดำเนินการดังต่อไปนี้:

1. ตรวจสอบการลงทะเบียนเป็นศูนย์บิต CR0;

2. ตรวจสอบให้แน่ใจว่าไม่ได้โหลดระบบปฏิบัติการ Windows

การดำเนินการแรกทำได้โดยการอ่านทะเบียนโดยตรง CR0ด้วยการตรวจสอบเพิ่มเติมของการลงทะเบียนบิตศูนย์ อีเอเอ็กซ์, ขวานหรือ อัล. หากไม่ได้ตั้งค่าบิตแสดงว่าเราอยู่ในโหมดจริง มิฉะนั้น การดำเนินการต่อไปของโปรแกรมจะไม่มีความหมาย

การดำเนินการที่สองดำเนินการโดยการเรียกใช้ฟังก์ชัน 1600นขัดจังหวะ 2fh. ฟังก์ชันนี้ช่วยให้คุณได้รับระบบปฏิบัติการเวอร์ชันปัจจุบัน หน้าต่าง. หากหลังจากเรียกใช้ฟังก์ชันในรีจิสเตอร์แล้ว อัลมีศูนย์ ไม่ได้โหลดระบบปฏิบัติการ มิฉะนั้น ก็ไม่มีประโยชน์ที่โปรแกรมของเราจะดำเนินการต่อไป

พิจารณาตัวอย่างโปรแกรมต่อไปนี้ เป็นการแก้ไขโปรแกรมก่อนหน้า คำสั่งใหม่ทั้งหมดจะมีเครื่องหมายดอกจัน (*) กำกับไว้

องค์กร 100 ชม

เริ่ม:

; ตั้งค่าการลงทะเบียนส่วน

ย้ายขวาน, cs ;*
ย้าย ds, ขวาน ;*

; การเช็คว่าเราอยู่ในโหมดเรียลลิตี้จริงๆ

ย้าย eax,cr0 ;* ตรวจสอบศูนย์บิต
ทดสอบอัล 1 ;* ลงทะเบียน CR0
จซ no_pm ;*

ย้ายอา 09h ;* ฟังก์ชัน DOS 09h
ย้าย dx, pm_msg ;* เอาต์พุตสตริง
นานาชาติ 21 ชม. ;*
เกษียณ;* และออก

no_pm:
; ตรวจสอบว่าโปรแกรมทำงานภายใต้ Windows หรือไม่

ย้ายขวาน, 1600h ;* ฟังก์ชันมัลติเพล็กเซอร์ 1600 ชม
นานาชาติ 2fh ;* การขัดจังหวะ - รับเวอร์ชัน Windows
ทดสอบอัล อัล ;* ถ้าไม่ใช่ 0 - ข้อผิดพลาด
จซ no_windows

; แสดงข้อความแสดงข้อผิดพลาด

ย้ายอา 09h ;*
ย้าย dx, win_msg ;*
นานาชาติ 21 ชม. ;*
เกษียณ ;*

no_windows:
; เราเรียลไทม์แน่นอน
; ปิดใช้งานการขัดจังหวะที่ปิดบังได้

; ปิดใช้งานการขัดจังหวะที่ไม่มาสก์ (NMI)

ในอัล, 70h
หรืออัล, 80h
ออก 70 ชม

; เปิดสาย A20

ในอัล, 92h
หรืออัล, 2
ออก 92 ชม

; เปลี่ยนเป็นโหมดป้องกัน

ย้าย eax,cr0
หรืออัล, 1
ย้าย cr0,eax

; ตอนนี้เราอยู่ในโหมดป้องกัน
; รอบคู่ขนาดเล็ก

ย้ายซีเอ็กซ์, 20

รอบ:
ย้ายขวาน, cx
ย้าย cx, 0ffh
ห่วง $
ย้าย cx,ขวาน
ห่วงรอบ

; เปลี่ยนเป็นโหมดจริง

ย้าย eax,cr0
และอัล, 0feh
ย้าย cr0,eax

; ปิดบรรทัด A20

ในอัล, 92h ;*
และอัล 0fdh ;*
ออก 92h, อัล ;*

; เปิดใช้งานการขัดจังหวะที่ไม่มาสก์ (NMI)

ในอัล, 70h ;*
และอัล 7fh ;*
ออก 70h,อัล ;*

; เปิดใช้งานการขัดจังหวะที่ปิดบังได้

สตี ;*

; เรากลับมาตามเวลาจริง

เกษียณ ; กรอกโปรแกรม

; ข้อความแสดงข้อผิดพลาด

pm_msg: ;*
ฐานข้อมูล "ข้อผิดพลาด: กำลังทำงานในโหมดป้องกัน!$" ;*
win_msg: ;*
ฐานข้อมูล "ข้อผิดพลาด: ตรวจพบ Microsoft Windows!$" ;*
ตัวอย่างนี้ยังไม่แสดงการใช้งานคำสั่ง 32 บิต ในการทำเช่นนี้ คุณควรทำความคุ้นเคยกับเนื้อหาของบทถัดไปด้วย นอกจากนี้ตัวอย่างยังมีข้อเสียดังต่อไปนี้: ฟังก์ชั่นถูกเรียกใช้ ดอส (ภายใน 21 ชม) ซึ่งเริ่มขัดแย้งกับความเป็นอิสระของโปรแกรมของเราจากระบบปฏิบัติการแล้ว เอ็มเอส-ดอส. ในอนาคตคุณจะต้องเลิกใช้ฟังก์ชันของระบบปฏิบัติการและเปลี่ยนไปใช้ฟังก์ชันต่างๆ ไบออส. แต่สำหรับตอนนี้ การจำกัดตัวเองให้อยู่ในรหัสดังกล่าวก็เพียงพอแล้ว

ฉันกำลังเล่นกับ x86 Assembler เพื่อพัฒนาทักษะการเขียนโปรแกรมระดับต่ำของฉัน ขณะนี้ฉันมีปัญหาเล็กน้อยกับรูปแบบการกำหนดที่อยู่ในโหมดป้องกันแบบ 32 บิต

สถานการณ์คือ:

ฉันมีโปรแกรมที่โหลดที่ 0x7e0 ที่เปลี่ยน CPU เป็นโหมดป้องกันและข้ามไปยังป้ายกำกับที่เหมาะสมในรหัส:

[...] รหัสเพื่อสลับ CPU ในโหมดป้องกัน [...] jmp ProtectedMode [...] บิต 32 ProtectedMode: .halt: hlt jmp .halt

จนถึงตอนนี้ทุกอย่างทำงานได้ดี "Jmp ProtectedMode" ทำงานโดยไม่ต้องกระโดดไกลอย่างชัดเจนเพื่อล้างคิวการดึงข้อมูลล่วงหน้า เนื่องจากโปรแกรมนี้โหลดที่ออฟเซ็ต 0 (org 0 ที่จุดเริ่มต้น) บังคับให้ส่วนของรหัสชี้ไปยังตำแหน่งที่ถูกต้อง

ปัญหาปัจจุบันของฉันคือ ในทางลัด "ProtectedMode" ฉันต้องการนำทางไปยังโปรแกรมอื่นที่โหลดจาก 0x8000 (ฉันตรวจสอบสิ่งนี้ด้วยการดัมพ์หน่วยความจำ ฟังก์ชันโหลดทำงานได้อย่างถูกต้อง และโปรแกรมโหลดอย่างถูกต้องจนถึง 0x8000)

เนื่องจากตอนนี้ CPU อยู่ใน ProtectedMode แทนที่จะเป็น RealMode รูปแบบการกำหนดที่อยู่จึงแตกต่างกัน ProtectedMode ใช้ตัวอธิบายเพื่อค้นหาที่อยู่พื้นฐานและขีด จำกัด ในตารางคำอธิบายเพื่อเพิ่มออฟเซ็ตที่กำหนดและรับที่อยู่จริง (ตามที่ฉันเข้าใจ) ดังนั้นจึงจำเป็นต้องตั้งค่า GDT ก่อนเข้าสู่ ProtectedMode

ของฉันมีลักษณะดังนี้:

%ifndef __GDT_INC_INCLUDED__ %define __GDT_INC_INCLUDED__ ;*********************************** ;* ตารางคำอธิบายส่วนกลาง (GDT) * ; ******************************* NULL_DESC: dd 0 ; ตัวอธิบาย null dd 0 CODE_DESC: dw 0xFFFF ; จำกัด dw ต่ำ 0 ; ฐานต่ำ db 0 ; ฐานกลาง db 10011010b ; เข้าถึงฐานข้อมูล 11001111b ; ความละเอียด db 0 ; ฐานสูง DATA_DESC: dw 0xFFFF ; ตัวอธิบายข้อมูล dw 0 ; จำกัด db ต่ำ 0 ; ฐานต่ำ db 10010010b ; เข้าถึงฐานข้อมูล 11001111b ; ความละเอียด db 0 ; gdtr ฐานสูง: จำกัด dw 24 ; ความยาวของฐาน GDT dd NULL_DESC ; ฐานของ GDT %endif ;__GDT_INC_INCLUDED__

และโหลดลงในทะเบียน GDT ผ่าน

แอลจีดีที

สิ่งที่ฉันยังไม่เข้าใจคือฉันจะเปลี่ยนเป็นที่อยู่จริง 0x8000 ใน ProtectedMode โดยใช้ GDT ได้อย่างไร

ความคิดแรกของฉันคือการเลือกตัวอธิบายรหัส (CODE_DESC) ที่ควรชี้ไปที่ 0x7e00 (โหลดโปรแกรมปัจจุบัน) และใช้ออฟเซ็ตที่จำเป็นเพื่อรับ 0x8000 (512 ไบต์) ส่งผลให้คำสั่งกระโดด:

jmp CODE_DESC:0x200

แต่มันไม่ทำงาน

jmp 0x7e0:0x200

ใช้งานไม่ได้เช่นกัน...

คุณมีความคิดใด ๆ ที่ฉันหายไปที่นี่? บางทีฉันอาจไม่เข้าใจสิ่งที่สำคัญในโครงร่างการกำหนดที่อยู่ ProtectedMode แบบ 32 บิตและการใช้ GDT

รหัสเต็ม:

บิต 16 องค์กร 0 ; เต็มไปด้วย offset 0000 (phys addr: 0x7e00) jmp Start Start: xor ax, axe mov ax, cs mov ds, ax ; อัปเดตกลุ่มข้อมูล cli ; ล้างการขัดจังหวะ lgdt ; โหลด GDT จาก GDTR (ดู gdt_32.inc) โทร OpenA20Gate ; เปิดการเรียกเกต A20 EnablePMode ; ข้ามไปที่โหมดป้องกัน ;****************** ;* เปิดประตู A20 * ;****************** OpenA20Gate: ใน อัล, 0x93 ; สลับเกต A20 ผ่านพอร์ต A20 ที่รวดเร็ว 92 หรือ al, 2 ; ตั้งค่า A20 เกตบิต 1 และ al, ~1 ; ล้าง INIT_NOW บิตออก 0x92 และอื่น ๆ ;****************************** ;* เปิดใช้งานโหมดป้องกัน * ;**** **** ******************** EnablePMode: mov eax, cr0 หรือ eax, 1 mov cr0, eax jmp ProtectedMode ; ใช้งานได้ (ข้ามไปที่ป้ายกำกับและหยุด) ;jmp (CODE_DESC-NULL_DESC):ProtectedMode ; => ใช้งานไม่ได้ ;jmp 08h:ProtectedMode , => ใช้งานไม่ได้ ;*************** ;* ช่องข้อมูล * ;* & รวมถึง * ;******** ******* %include "gdt_32.inc" ;******************* ;* โหมดป้องกัน * ;************ ******* บิต 32 ProtectedMode: ที่นี่ฉันต้องการข้ามไปที่ addr 0x8000 จริง (โปรแกรม elf64 asm) .halt: hlt jmp .halt

11