From bf6e59eb06ae447bd717883f53c0fef5a6d92b28 Mon Sep 17 00:00:00 2001 From: Adrien Bourmault Date: Tue, 15 Jan 2019 12:28:53 +0100 Subject: [PATCH] ATA reading stuff '-' --- boot/loader.asm | 14 ++++- boot/loader64.inc | 125 +++++++++++++++++++++++++++++++++++++- build/bin/disk.img | Bin 18944000 -> 18944000 bytes build/bin/loader.bin | Bin 1221 -> 1944 bytes build/obj/boot/loader.bin | Bin 1221 -> 1944 bytes 5 files changed, 137 insertions(+), 2 deletions(-) diff --git a/boot/loader.asm b/boot/loader.asm index 7d7b9df..43f5fe8 100644 --- a/boot/loader.asm +++ b/boot/loader.asm @@ -264,7 +264,7 @@ main32: Init db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0x09, " Checking CPUID...",0 CPUIDD db 0x09, " Checking CPUID...", 0 EnA20 db 0x09, " Enabling A20 line...", 0 -KernSearch db 0x09, " Loading the Kernel in RAM...", 0 +ReadAttempt db 0x09, " Attempt to read a sector with ATA commands...", 0x0A, 0x0D, 0x0A, 0x0D,0 txt db 0x09, " Switching to Long Mode... ", 0 Reinit db "Booting OS/K !", 0x0D, 0x0A, 0x0D, 0x0A, 0 Pass db " OK", 0x0A, 0x0D, 0 @@ -337,6 +337,18 @@ main64: mov esi, msg call write + mov bl, 0x0F + mov esi, ReadAttempt + call write + + mov rcx, 2 +.looping: + nop + nop + nop + loop .looping ; Temporized because the ATA drive must be ready + + call ata_read jmp Die diff --git a/boot/loader64.inc b/boot/loader64.inc index f6611fb..28d8145 100644 --- a/boot/loader64.inc +++ b/boot/loader64.inc @@ -71,6 +71,129 @@ write: pop rax jmp .pLoop .scroll: - ; XXX ; + ; XXX I don't think I'll implement this, but never know...; jmp .pLoop + +dump: +;-----------------------------------------------------------------------; +; x64/LM Dump Printing Functions ; +; bl : color code ; +; esi : string address ; +;-----------------------------------------------------------------------; + mov edi, [NextTRAM] ; TRAM ADDRESS + push rsi + push rdi + push rcx + mov rcx, 512 +.pLoop: + lodsb + stosb ; text subpixel + mov al, bl + stosb ; color subpixel + add qword [NextTRAM], 0x2 ; Cursor moving + add qword [VGA_X], 0x2 ; coord + 2 because 2 subpixels + loop .pLoop + pop rcx + pop rdi + pop rsi + ret +ata_read: +;-----------------------------------------------------------------------; +; x64/LM ATA Reading function ; +; ; +; ; +;-----------------------------------------------------------------------; + +; Technical infos about the ports (Intel Doc): +; +; Port Access Mode Misc +; +; 1f0 r/w Data register, the bytes of the disk itself +; 1f1 r Error register that can be handled +; 1f2 r/w Sector count, how many sectors to read +; 1f3 r/w Sector number, the actual sector wanted +; 1f4 r/w Cylinder low, cylinders is 0-1024 +; 1f5 r/w Cylinder high, this makes up the rest of the 1024 +; 1f6 r/w Drive/head +; bit 7 = 1 +; bit 6 = 0 +; bit 5 = 1 +; bit 4 = 0 drive 0 select +; = 1 drive 1 select +; bit 3-0 head select bits +; 1f7 r Status register +; bit 7 = 1 controller is executing a command +; bit 6 = 1 drive is ready +; bit 5 = 1 write fault +; bit 4 = 1 seek complete +; bit 3 = 1 sector buffer requires servicing +; bit 2 = 1 disk data read corrected +; bit 1 = 1 index - set to 1 each revolution +; bit 0 = 1 previous command ended in an error +; 1f7 w Command register +; commands: +; 50h format track +; 20h read sectors with retry +; 21h read sectors without retry +; 22h read long with retry +; 23h read long without retry +; 30h write sectors with retry +; 31h write sectors without retry +; 32h write long with retry +; 33h write long without retry +; + + push rax + push rbx + push rdx + push rcx + push rdi + mov dx,1f6h ;Drive and head port + mov al,0a0h ;Drive 0, head 0 + out dx,al + + mov dx,1f2h ;Sector count port + mov al,1 ;Read one sector + out dx,al + + mov dx,1f3h ;Sector number port + mov al,1 ;Read sector one + out dx,al + + mov dx,1f4h ;Cylinder low port + mov al,0 ;Cylinder 0 + out dx,al + + mov dx,1f5h ;Cylinder high port + mov al,0 ;The rest of the cylinder 0 + out dx,al + + mov dx,1f7h ;Command port + mov al,20h ;Read with retry. + out dx,al +still_going: + in al,dx + test al,8 ;This means the sector buffer requires + ;servicing. + jz still_going ;Don't continue until the sector buffer + ;is ready. + + mov cx,512/2 ;One sector /2 + mov rdi,buffer + mov dx,1f0h ;Data port - data comes in and out of here. + rep insw + pop rdi + pop rcx + pop rdx + pop rbx + pop rax + mov bl, 0x0F + mov esi, buffer + call dump + mov bl, 0x0A + mov esi, end + call write + ret + buffer: times 512 db "_" + end: db "[End of Sector]", 0x0 diff --git a/build/bin/disk.img b/build/bin/disk.img index b2b0af2bb481b656002f06cf81335c46f3e9258e..087b3f3ae05ffe22a18c93b8211107f2d59cde34 100644 GIT binary patch delta 30744 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 delta 11044 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 diff --git a/build/bin/loader.bin b/build/bin/loader.bin index 02ebbd014ecf745f40d4f102cbf108e83a42c596..096e80a677dc1a99d6ef20f8c99f89342a5542a8 100644 GIT binary patch literal 1944 zcmeHI-Af!-6hC9NYgV_jwzw^M>50KYUaW>jXs{%jY*|sG?pi-0)o$Fm?pECivv;u{ z4_%OglAt1`gkoq3g_cCit<=~Mg-*|%=|>)H|ABTM z&iUPQe&=`2T;|?6zdX7!ni}>@d&)mwpLPROxQoaFm?oLGZrFZe?2q*aFv*&jf8pi> zN#{mQ5;xds)_yTfvA~Rc-97xotml&MVV$f!%_dnp8(CsU01$|9(F#;7vn8XL4XsM7 znL@9pcnO=MP6_!EdqyI!J{mQ~bf1hpxM`+v!$)f3fkC*=0@Vq?YZx;;^t^WB6M{g^0M`ChckZljny@*Rcg+JZmX{*?!lL(J5$N875{y)i9D6SqFJPIx z+mr#wIzFq;h1EFEqK5F+b93z2n{ zJ75vW%sEJPp7?NOD3ePpfVFMfBL~POEAt6}lziAF(sDVyi;Kt!dX*Q!JfhP;!q1Xl z|CY>S;LGHeekkTl6p%WZ*0$yuNRs|>fGu{VqpLf8uF9gcwoO$5$0{d(yvoI&zC65g z**9cY=Lql>$>e0e?CwhY&gGWgq?J#y(|>v?BW1D+O(HGGzC(8U&@C~Ah=`{>dm;Pg zUoD&GAqQY;?`CV?cTl&cfWNtoE&M7a-`QXbzeq`m+?MU`NJ*g8w(agp^hN&oem>u2 zw12)u=OcDYwy-H}v4QT6)1B?pvM$2LEA$CWJ9TF<;oaX%Gu{3F^Pk>FE=}6HU+6o-8XXgS}(kXz)zG;8h#=AILnc%s42k^1~Fze!@&p-V|7b4_NW5`!DuK(d}`<-`2gj5!a|Fx>Q(X$YDnne z9uopK)=?EcTU}d!fIv%F!Pv_&>WYyVM%6)#MDeA{r*J@MU~LR}*h+9bqXgqT!s7jS zj0&ADuixM3$D`Px#x*h4**I4;TZLmtiA8#&N(h;%S$d5DpnX$m2Ln9VtDslYD039W z0CkEMRr+x-C??=k5|4)H?f$voWF*#yVWRhF!B|+a$aP--DQ`VuP3_BKhupQWpev>0gWZd7INGaDwnW-GDGYKEAeVxOYkKRnq$% D4UD{a delta 491 zcmbQif0UD}=S1I)z5^X%zlA4qxv~BeUc@FcF*HH7T3G$GQO*FiRcL_i?o^^DikobvNa zGV{_E{Dbwq6%=_VYqGk?_~a+1fW%5NQWd;Yi}F%)6f*M^f*gJI^z=5*WA$RJ2ie)r zqACKU_Aq?lWOyKbrUm&|5DBfVB y3JM&?62Z+p`(!~XDuJReoBtrRWI&914$=~XFiPx20Eol8PYtBY1*FRls0#pUtG4g} diff --git a/build/obj/boot/loader.bin b/build/obj/boot/loader.bin index 02ebbd014ecf745f40d4f102cbf108e83a42c596..096e80a677dc1a99d6ef20f8c99f89342a5542a8 100644 GIT binary patch literal 1944 zcmeHI-Af!-6hC9NYgV_jwzw^M>50KYUaW>jXs{%jY*|sG?pi-0)o$Fm?pECivv;u{ z4_%OglAt1`gkoq3g_cCit<=~Mg-*|%=|>)H|ABTM z&iUPQe&=`2T;|?6zdX7!ni}>@d&)mwpLPROxQoaFm?oLGZrFZe?2q*aFv*&jf8pi> zN#{mQ5;xds)_yTfvA~Rc-97xotml&MVV$f!%_dnp8(CsU01$|9(F#;7vn8XL4XsM7 znL@9pcnO=MP6_!EdqyI!J{mQ~bf1hpxM`+v!$)f3fkC*=0@Vq?YZx;;^t^WB6M{g^0M`ChckZljny@*Rcg+JZmX{*?!lL(J5$N875{y)i9D6SqFJPIx z+mr#wIzFq;h1EFEqK5F+b93z2n{ zJ75vW%sEJPp7?NOD3ePpfVFMfBL~POEAt6}lziAF(sDVyi;Kt!dX*Q!JfhP;!q1Xl z|CY>S;LGHeekkTl6p%WZ*0$yuNRs|>fGu{VqpLf8uF9gcwoO$5$0{d(yvoI&zC65g z**9cY=Lql>$>e0e?CwhY&gGWgq?J#y(|>v?BW1D+O(HGGzC(8U&@C~Ah=`{>dm;Pg zUoD&GAqQY;?`CV?cTl&cfWNtoE&M7a-`QXbzeq`m+?MU`NJ*g8w(agp^hN&oem>u2 zw12)u=OcDYwy-H}v4QT6)1B?pvM$2LEA$CWJ9TF<;oaX%Gu{3F^Pk>FE=}6HU+6o-8XXgS}(kXz)zG;8h#=AILnc%s42k^1~Fze!@&p-V|7b4_NW5`!DuK(d}`<-`2gj5!a|Fx>Q(X$YDnne z9uopK)=?EcTU}d!fIv%F!Pv_&>WYyVM%6)#MDeA{r*J@MU~LR}*h+9bqXgqT!s7jS zj0&ADuixM3$D`Px#x*h4**I4;TZLmtiA8#&N(h;%S$d5DpnX$m2Ln9VtDslYD039W z0CkEMRr+x-C??=k5|4)H?f$voWF*#yVWRhF!B|+a$aP--DQ`VuP3_BKhupQWpev>0gWZd7INGaDwnW-GDGYKEAeVxOYkKRnq$% D4UD{a delta 491 zcmbQif0UD}=S1I)z5^X%zlA4qxv~BeUc@FcF*HH7T3G$GQO*FiRcL_i?o^^DikobvNa zGV{_E{Dbwq6%=_VYqGk?_~a+1fW%5NQWd;Yi}F%)6f*M^f*gJI^z=5*WA$RJ2ie)r zqACKU_Aq?lWOyKbrUm&|5DBfVB y3JM&?62Z+p`(!~XDuJReoBtrRWI&914$=~XFiPx20Eol8PYtBY1*FRls0#pUtG4g}