From b9a33685bdd5184d2dc383212aa976cedfa0e5e2 Mon Sep 17 00:00:00 2001 From: "github-classroom[bot]" <66690702+github-classroom[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 08:17:37 +0000 Subject: [PATCH 001/176] Setting up GitHub Classroom Feedback From bbe07bc2321f21d401a78384ded87284e5c618b9 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Mon, 20 Feb 2023 18:21:20 +0700 Subject: [PATCH 002/176] Currently at build script --- other/grub1 | Bin 105522 -> 0 bytes src/linker.ld | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+) delete mode 100644 other/grub1 create mode 100644 src/linker.ld diff --git a/other/grub1 b/other/grub1 deleted file mode 100644 index 3748c94bf5e8a9a58a07a6ddcfe94b87a4f0b95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105522 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

=@`W}JzxL05DwJ>B(%|Y|ahQb1znV;B zZ-95Q*{d}}Zv4ks=D)dSH-`JoM=8j<8CI?6z8*}@Z1iPO;u|m3+FDT`zZh@>Q%q9y zjn$~w>$m{eL`V`IP$9?iz_NpfiNo2{v!kY98m;ZupqenxXkg zjs2~}#))m-q~A~T8`K(e6FJh8tx{TXi>pV12zBadrj;Yj#^)!$CN?!$-Ts3P2F-lI z-yj}y6p!=&TLdis977PDvyr4@b5hzRHB_7VXJcuR>aW)1CZ-DB+_CuJC(6?hAquHM zMQJXO^*NTo)*lA*Fc1X}8gULWf4(jH{kHfpWQXYRS6Cwux+GTQC069ltKc|cP578b zRI*G&m*f>#Gu6NJ?^VvB=9@L1)H^cIS&=&G{C-zHe)nZk1!@Wn%_0A z=#1l1sh~|SbCPo|U*I+i9Nv=YMY&?ZAz5LHB>9ICQZ9--+_h;`x8mQwzP#XKEf*@36hw_flHT0MYOIB47Q92 z_MVE|!$aKXdeu2zvt)`th;fvdC)jy_svh2hMOKa^4DAOkEMD0K=46^)6S3ZA<)B4t zv}LTqJ~`iM)gB~7sZ#}fWM=vuT953i0IQaF59ahI6eDI=d)gRJOuUaq1w+A8XN=IR zbg|U$k8TAI&^K(7tejjDycAzY}bR(A%dj_kp z@@t4NJKd_zs%YzflEnKCQ?QGio5n1X(T+djfEa|2(N|`N&V!EW;2JXXK0OyQGBho) z=)g@S&69sdNUWa3iNXVaNA{(XOVz!s@Nlzc{1XZE%rZ3_5ORtepKo zENt19DL{v9Sj{@4#hvHY#LF_RZPqG-zBMI&_X2klH}hG#l+X*DRQUKEv?==eKy+u@Ew0WZ$VLW@7bbW{Q@ zUp%u~au;JF#zn2YDa|s0oK*eIhQ90x|0u5g?lVZf3K+xdohKRKKxVkS}WNUHo;l+>@Ew ztcVzh4Q__wV4ap)F zbXD$omnsYBULRCFy>E0*oo|E7ZF_rOP19|OzrU%r!3j8GBo<360{+$ z|4Ly53(EHkqgURaxFryo<3BJAN@{`rtz@xT>SqFmVPaeIfgZJgLa$q|sTgi}Y<8Vdvf|dBFHf z!+_j=nSuT0>K^=T%gjlN!Y=1SMPb*6^mJ*2FCc~jrNlcPT3xZ&5gH>rcZQg}cep0+ z=V&Q4dGAnfaJ`Y$eeHN&u)obcgt?1tN>m0NUk1Z<+z}{IKos2XW<5FFJ;#4vptpckLZ^Z++KZU0(5H2*nV;7bv#r#&;D6hra|m>##sbCOESev{{O~u_#6@f#e{x{jYQOh8)|~xA8;+SHw?K38uWidU=3=HU zb((Fr`-^y4(OS~WE05+9+X2FxRe3b3DberpP-7A2-VfClh%Mvx-MG&9~C^sZ}T1 zp;6Hpf-lMpybMay@-1Ou6;?)dQaR0SGA0pK#R=zlmn~aE-1Z z#O~QuGcr<+$9k{A8o6*$;1$;U(vpiTe+Iul3v|@4{(GkXJXcIEkDZ9rUl<7#2wD)R zJo#qe&0ud@sKp42778)J-b~&ASf!y{4t?1*30ssML~V475`pGYx~LA6*>`K4omZRj zJ%smo+2S(pL7LHgE7`2_51SQTf)+c-KJNJ7W#M`3hjgrx7n9BoGMTEV@i~$Z02yHs z>cqYykttfoxmrgGo)N>JB^IAK^#4K4P1HG(`z!oJrHxha#A1#0mjB|0l8w8;El~zPrbn+nYHb$hU9bqY;HSCZw9pOfP<)69!9{m=kN76gOtK6I&VV@f^ z)_FKRSYd%=-5P%U26O#G1g9IJE(YC-2!zy#V8^M=jC_-@@!)Sjk`!@U1sW6QMc29$W7tL@4Xnb?$h#?*D1Q(C@au>#Tx|Pve%sMCx=;@XlX;S z@fDsOi!F$)sn~MboSGhDcGDg~V6%iRO%1jn)*8=QkP}+fcq<~w)_TEz$8|y~JjgFK zqZwK+qfqUywjwh3BW1ZwzpE!;>Sv=a2-s68?-bC5F-37|9ygy}FN542M~79e!>x!c z8*9CQGV^-On|jh5^m|BW$e72QG`>4tyg|@+@8>M12kW(6iU%|8fO+eIwA2kUluou~2OOZ+ z>)P!;57m%>;6Kgg9TdeS(y_NLHH*N1YSx+ zWGV%B$S;b^SF!gcoO!M*$eGW^gC649BzDMZhjS0^km>C8r)wQa7S0+`T%LRHrOt~; zKW_PB?&P+m)`&*M+EP=;iUl0&1l3dU7%*pCQ{Ht>DxL(ET4~ec2gE}hPGT(P$()H? zl*p&2Lna}osU+7wF1mHM?3PdSE5ed`rkWhXaWRnpTjI9XkAwbh$-}}2-$$DyZ%!k5 zj4f#uurt=w2c$rGZ?NQ>mr?StfgR-Kl4qsArH2OFZk!fAV=8J@KemOY6 zGh0_kfz7vg3;q&}=XQVlaM5eV{p%!d3(l^o_7bG23(_Lf+MH4=UXaY>BmV%-?#jp- z9KiA16arFq)UdL~mIY~)Z#+=&S|m+?7f+SOBg`=F7aVA_dZSN%O0#}U@+X^hx5WLc zW)=L!?LdL%oRx+rl7hBjMGD&R#$DAX&3`SCF33uvEF^OKhP(R2+L~+7B0Mjxd4)mR z?x`0eDv_rYy|^O9JV4@<^1cE-@%?B7<&30k%0v~q*iHA>1NFw~jScemIv5!06In+u z?>q=Bf0Y>i1|Cl2NcCE|5~hu#&4l?ucWppf6kMh0t^Jisr26&T&&lXo^IUa?$V<2bM(DzUPy*@00cJ+jt&7cgm0Wb@WZ-C!%#%bfilz z0chVuYlFMTqp4T!)&t|_DGi>QQ2V}5)~rt!sc#|#!Pg5cgg6%tLXmXIZf7`9X4kqm z=7O_5yE=5C5%eS!qw&5ZcbH8nhj<0gq**0O($;)HDf1LwKZ3{7)1}F+@28WD)fp7p zShH0B#gKrPEdAI(!`!QK(A@23Wjr8;@o&(j#RWq%D0j9oDf%`3?U7djT4NrLoo zxjlq?5p~s^Q*%y4Q-|aGFh_R9w;A?O5O1Co#Uh=Cq-t->@P~x0_3|54LcS&B5qey- zUJ97uQzUeRKjv3zz4z-$a(@e}%33d}lTJGXKM#Vx$SXwH*s>_C`+a7pnJ>d>tQCo; zr7bXjs%<+7S_AyZqLFgmywE|&jl;$iCw4AM0&foC zJSG<`_O8DV(WMTl=)L%Q@%?qZ)Hh_MK-}kwO)Z zq36GRo>Y-KyowaOG$p(A=wKB%SRm|FW389*z0rKw8SbHu^~Q3fJ0CL0Nis`!ywvrm z{rd1om&Cps`;m~}-NTcl-|xkCAZ50Hdv<&(@n4tthtG~rBmN4BU-ggiCmE?>BwXyM zg$I{^4kh>BYxdt5?Dg)0o_m|`ycFtv6GXi?wH04g@sw~&b2V`eopy+}|1w@DB+l#4 zcLFK?G;zDa|FLgToxKR;#E;r-xKxPmx8LbMi?9naer~_)MndX$W%~QK3)zj`%lx6O zuG~N#VwGK5{u$wo{JL9sU~I5N+DWV^|Jf5L7L^8xuWnb^Ad4a?e^>@VUgnmyrV2>^ zmmAIqk5YGqeLW2^k2eNow~xx+HG3vqmVkeZn~Aq_RBO@yvZ_lo@(!NRAc_ z=@pcdZCB7?e*@7cqPH%4#4!-Dr%I&*=37`ROD_JYq^BcYwpRJqkuJ2`32FZ{F1f?+ ziM70^=s_e<;T-nGy`JVtzAk1zO%|0Rai;<&sWlnvHj*iPqIPi-A@icrf}->p{I33v zrJ^RZh9^kuWzw&LZe@BLf2Nfc3$Ss2V;SrZHWX4uA6>%hN$ntJem_jUausbzV(e4i zEU_uNGdM7kg*1?3gqMPcp?c!~olq$8A4a8W1i4MK znKGiLBUHvgmj4od zmZb+zr})Q49|uLvf+sj=ei3El=PG_}6@n z{s5s%&3mR7;Kt6zF8*}4&GeoQo-sJ2Ea}7Fkojuuu0nZV4K@d-^5RmqZxV0VB5UMI z4M+;7K}jZ%CZ4a5_76fT?}zak4sE+a6ISm_RegmA{|THs9XLJ1;G~`nr&ZwqMq8ED z2DET2Tk$FeSJ|OW51fEU4vHYq5+0Bfynz z3m|<`%5Fu)72^$p@=wztRP&+|Bkqqng6~`l2>Fbp6$ejU%S{JI*t&Bo=SS9h{=|B> zYXOmDWVV(9rQlS>VB*(F^hrKjY-Tahl7mNS!71*Mf&;T& z^EIU7OO0RoXMYdyg)IwV?o(?|Z&k!`IgC7)4E7Qd<>?ORYv9`gGdKQJa@I~n{S%zn z7n1;DaAX@P7X)hO6z4kBQwa{~)66jrI ze;0%-5RKAC0+<^0+Omo@Ml4BeFRQO6w*udMV&`t3r_H(atkFv)P6`Z-pj}MS$jsD= zN?TkC!Da^&x#obePS!!C0y>}gh2exbP+dF0alu;Sg$DRjFn8NGV4nsF)!{>n>W*l8 zsJ`$JDma0j$eg2d?f;?!XEmXo2qu>UXs8`V$WMjZnO^~Lp`2V$@afTKIKnTZF-`I| zIera`n?#%g$axU4CRZEmlNK#1v-|nmFd+1oMi~!^o*}oQkyRO9ab3|997v1II0rL9 zu~<-_h*ue#XN<~#c4oC3o6|oP4qi2NHNc|r)oreqiXfLa6)>reqfd#CZ z)?*oX0>j4ZRZci*wNY+)jm_1gC`=Qzu>Y&(flm~?PzuJ~f`_DrKq?BZ#?JF%AJBB2 z6|r{+$r~3^U9k7srnKC~5wqfdg07t%r7n@EHrSG`&jSl8V;?Ydiqk6C#)Z|fm-yD1 zQ_eTcM4aB zT|s-=xtGSO$o){&QY$C(0%-GFk-6!8Z`Z?ja@jM|e1R}(e#v(ehv%x?zHyD$qj@KC zMU-=+e{Ax@f4m9nfESLvUGJzs3WxA^eR5|*VkM5O99jgCMv4(YDKs+ITi8O8$lTOT z_54NIWFjppy1LB>{eDGR8TC1=Z2zU(=g-w%G2TKmdUD_`QlOwq039)G5gzU9Z`JDX;N4?ZT;EczWn_r=Ko{qu-wM-6=@D!U%SYSi zvnUrwB|=!~-Ao>o?b=qJqfw0yNqwaXr|=NZUv!l<3>cq-q3>{kEZ-Y{PDnmlGCuZ-hoN&~A9$W@3T^=R2m)1nO1=2gY%NhSU27KXtQ%10(!-u%!Mk1WRTE z_~yE?iF64hm5e@Ooz>*n>u3XtUofwO%Yk!rrR{c92u>bHHlgq9F$7}!ma^O63o zyRc#4dHK$67--?I;~a1M6oN`i8V1C@iT_x`z(M}Td$)f%sTK%EZH_qV-eq=OcLN0cxUqScLuP6w`gU4y`$App zJ$K2rmA&mATFD`0+jr&f$Ybn-9qHeK`tYx`sWc_nE4SJgL~r{H-Kwv5M#`g~mVTZE z00K2w+T*)v03(H!^IbE8B>FHo#ksVx`Cf0ud|$m}sUk~LWoly=RFx)C-$Gnd8_PKo zS5U3sG5BUm=;gpw(Q3ZUzc)T~Cn(z}AB}77Y)9OrXK4tMKO>PY(JtOQ$}?N2!TE~4 zR|TtAo_Pwwqf*HEm2>B^XlpVeGgB%eOZqGAr@64JY%f2-<-<&Gg)c=~w}nze!zfw` ziF;AZ#K|K+Wa^bnKOj?6S*msbgavZldQ|Z);M6PVh#wQ00X;YSZw|Kzu-fss21m2O z|0RBEFG3XH9|McHE0grPqi)4`)L}+e$KOUG@Mfhg3M;`~+3{nQ_Eh5IZwpX%iOi;% zqo$3pZcj7T%88MUV6{9M0V~u49a_{-Tv0ZsVxj+nip26X-^7n;_rY5SjX;!a3;d?C zjIYkj^5?RzRrv0dTu+lL-m}yyo4k|^xEYLhp#feYuzB~YLV3!Rvd>ds5n2fT*DHJ* zDHiVl5#7FCfv`*<{74~A{6CU@ON(K%*$O}bc+9fCpGIXQ*|W%6X@8!6F&D&!Yb2Ad z{`+XUnJ1VE+wwtU@cZKEv4>A<)}_rdHxpCkcb;#ffJg&`GesW~K|{j}GKWkJTltdD znts(~lA<*<%OvCNOo29UV(Yu(f^Qm)`7*=W@0ZEt)D{*wGB1CVm&NPxw49+l#ZL1Z z&E>Pz9>=-LNg}J~v1cK*n)28-LU*_2gnn$`QojKp$rm|7fIH=3Sl?BF2 zd;Ctr7b%Q@M-tQg-d606or*}!9J$*7c67iii8NQ1_ubxy4F1hw1qSQ_Jn!|Yj^6_LQv`S#u9smYGa%4J>cXGQgS>}sMo>0AYz_VQkj zeaAf3)q=~7Ewe5T?!GiO7XS|W^(@Z~kzm@>dnP6hZ?@e`u~<4G-(o`c#S~Ub?#}$| z`OG66e9Gu&kR}6r!k^nve8-%MJN#pUyK;laa>Y5ZyP)d7pXm+6n#!`KdHreA(gLs5 zav7HubIHQiS=7D);tj{ngK}3D^(@EA zmwsI56Mk^MZGaqxN8AEKXY$q@F&`1*_XHLQDb+u=mz>{1P5lV7s!PqNv-tU0K? zVtSihN*hI*f`DPkxQd!N_Ht@i7(RiKo>*bmjI;lf26UudDuV$&61H46GI!8>HFvGP z3U}7H)NUzSZFASkQ&I9lG^zExo|93=Z{T$O_t78lmd%dyrSvTDm~Jo12(Ez5;QR#f_KWDb|vCvVp8qJdQhl0a6v zKxl=Cw34m(I?;^VBK}mz|L~6^ZiF|HdjTxw6|~nUtdso(GH;(vh$?-%CFU~%{Pz3) z?h^*g&XIJP;R_>I7tg2Yae;(vBDV_31;hZQ< zOACy~l)pCXmPGkp0(B>YB@f9qWHkPJrtAU_>qqD)$M@t%_!2(s*{9AVRAI#bp}Icde^UH)lKhN)J*z(f@A-~rU=QOq8!9UoW3%v<1V5i0cMIXZxe9La7!wNRG( zeMqpiMfW{2R4QCaDZ7CT#^!!EeP#Jjdgv0;Vb1R(N43v`_LY6`CKq|q>5g;(saQ#G zbVK;(KE!SpJcG7Jg9Z@xtkeL{#r_?#6g;!s2*oro0yhyFNX7Z61VleQG#VNZJTuY= z-3kVSXL5|tjT+$H+36A}d4Re+ft=`MG(u&=7s*KQ%w0UJcjg;LSaedw3OUc7E{keW zYylC4Cj>Sx8p^0So3K^Bx5kSE$6Aty-nD(f0LP;8PNpS_;AqG4Xi#J7^s-P3D(Zp0 znM$}a>ZgtL1YU1X$C5nX-#|gb zF8Pg4;{w03`6!L|RWe@D%=?kGALbK&UOau!Li^jWfUaKsBS1u~+ds2@+Bi?(B)4p} zSK*Z)6({ypc?E6rSoWP>v@|C(ujjL(JM9YzO$qGw2J!$AtET);5awx5o!HKcVR0n7 zduw?6gl1JZO%h4TfRKSR_ZVS6`OWrWvtS2heRs;}AHD&E)=Wf-$R=%PQw=xPpRc*7 z(szeUysfZNJXK-r#0UBecyxHXKqf}X^0xQ8sB$N!UQI6(Q)S%reaeq>F!}}K;g;>^ zfdqfPZ=+Nbpc?yK04$9C_s2|5f%hQ@5q=#|?*lRb<0R8SC`D{JnVK>hQ)e<-0iJBp z`9Z?qc90Jp`ON}|LUrtGOjrAP!bJU*Kh@5hi;&$#iz?q|eXCNKAr)h%(9CBmZMCoUm9GD!X{)VPskP>Pf4_6@%uPrDU;B9jC+FOA&-y#R^V`nv-YbU|ubjpA z3kq*Klj-bwrETDsfFQ7BlXOQU3vYT_=Cx6l`|t8j*#3od!MtdOjx1Lbvzssjd2^5y zIaNmS;H}|V*ozgNeh8S(+jwxOVdlJzf>BF$%)BntxNFBDJmDBVpEz3-p1EWEP{X0z z2r}n(y-UV_?@Gp(3kvctb^v%XHbf5!{MM*d+gR|IFa(Z3(kncbk5vj;vyGx@$w z;d9fszn84Wfp_zF_t5o4!8XqH+py4C!e!&&`(&95Z*Q0JG#t`L^Q8xbuMKQ=h^u_F zVe@NQx>a1WzkbXbU(t0$w(;lcw8Z<#(Gv40F?4~j30`@0V$7CCna4$zt zpwM&*<=VVD^O`HV?h>s1E4+XGhJkB9#vpP&{8wpm*1!t#yOxJAJl)^5X&lkl6n9@{ z2mqv)O8wV9n`7(!<)|0SGgJG|Bwl(J-^jL%c>C}AS5ZnB{Ld|e|8btd!}*~EhxyJQ z_5!;2n6mPXjBCTygP+YqC_qd;4n_tp_i$+?G9Hx3@-neX`3eg#v$pt^@|Xl~cX;zw zk9b|g6A4RaWPY`DYGxbnwVc8$APO>Vl|zz!Rc4KRE-rfs27)&%Eyzqm9NTfe1JlCs}#3q(%>ERE97qQ?Mn-?Z&NG%?xF1GzN2}c z*!{Ep;pd#|-?M7)-I5sG#h{x$@@3X){KWhC+t={&fr(G4X&8`HJ$s<)Wtqf*s-rfN zPrY#UhvgiN^xrT!|Bh-t(A8DS;|cv!2VOy4UA_l#YyIAa=lkE!0(A+y!C)+v`xoPm zQTak8MBMrrNhWXS+{^%_yu6-*$Bw;+NSeBS4iE1#Z=<^p2;oqh!%ZT)+RQ(<2>BHE z6ZNGae_dwZtu<3Vg?wYOE6|o+_jRdV$NA$er}7N!o|#oc;b*Z{{b}%Sz9^J=x3&X& znoUca$2ASLOhC5HH>ZzlthqjHpP(HI_wN_h_3ZLn(Lus^0rTZ6ny3C#Al!z&2ksX@ zue&vTM0)#!_Vx$qZJ>mSaR4JnzkJ#3;WdS~e~psCW*HatsHI)V1G_v?YrEt12FvAn zK+#}0Yr7ZCmqFl|$t5sZbox!~^S(21G;sjpV-HcNX`SMec?oI>3{&PS={8x8B zoSDNRO5fq33#5=}Mm*K@o96!P^LFE1Okq?wo?+_(H0-r9GCn3{2l+UgH<1B^2Yr`0 z<|1D2fSUjHO$YdB8m}|?Zq2TvS7qkyI(l{H)IFzGE&BV`felyRCwDm*xP=!lR4qMo z+r*kZp~2tm4_!U@i(5|HTYb1@>C|m+s(gXkyZS58;cq!@>VBKOb+GT*J)u=qgJ0E~ zrMr%<+;;EKIlHHf#}X7eYw$z+L#2c7-5=UHc<27m;=w!ihprmDMH=3{KQv`<=l;<2 z0hr3r{!qa{kH$0ft@ryw&VV@C><>*HSVzo;5W8PX|Ic}s8RoOT3FoxvJ0*M*zHegw z#-@YJa~dDAVV*m-EoCUB6Bx?4tE%^pbE|m_dOF%W3bHT-rxCE1sG*~@d;hVL}= zFZQzM<+2ZwLq}bkq}Cf5iETu(HIIA!lQmmy8GFOiRn`$y)RJmj%m8N4@@Jq8FP;!~ z!7nqbrN0f8c*(?4y6y|#wEp_Q_XjthgD??(h_@je2;at}A+o}lO#d@hi(Znwsqd#d zX75~7j5;(0yW}F&|Ej)&^PXA~zUjLDU9U{#^ibS)D<5By-P8B%j`6pK_wbP3S-Y;g zi%)>_j8k9jT@UftK=t4+G=1mbUv}--gQ{Q-+3{sd`u=k1_99+T^S9G(&D?e84X50< z=}}g__TYq2-@=1cm-hayZ-x{WE5xE(#xFgm@TSAi!llKTs>1sZ?tVBs@#{Moz(-`l zyv1nG9*4qxr^{vDaB)Cy@82o+%zg6L$^zkcG}Ux%dRQ##qUrWMSa?5AFV7LqdvxQr z?|_1HCt=m}+P3wJ`Kq7{NS=Sb{*0A7mwqqGfH|EaFEg1JpUC)8bLFAEgFIkP_O6#s zE4%}bg&}Wlhnd@S*ked5>BoO;lMj#DCUA;*0tny&vr2< z{8$zfqvXSxiSK>!Z+ze_zn&jL(F}lh;bHy!=f46HiykTbz`lX|Y5!l-+Cb00tf|5e z?;9x2w|1gEaMR18*qzL7x#@9A>KBm)4(94Se1i6~KN$RIjj*}z!1)%!#`ZRS=foiE zn|{}kN1y;tqq*#@{_xT>3vZUsm1*@4pH%ftQvE~JIdSO|PrmZ80eSaKP37azD_+b@ zdgqej%uJzPAvL=`JFq|sK>RMr6fRwo{jC_$-bB`=ga1`M_+$AQapJsZH+ z*`M5B(Q&*xu+D)PcXsV~2w#<<@SS25DBS&o=ttqZ2OcHX0q@@TjY`stN=3_(IACpv7Lrv9UgXh^Q1q+Zt3=s_W6OIHqvK6YZz zo$S^uyr~0>k?r}DfvZT>@CCZPO+VcA(v-rR|At0(>*~86VgtW1uy=n&c5d&Qfh6Oh z)SUwj{=jzcyZ^)h*nfHdWM3UV*}$D;fV|OJ@(>b15cun?)|Y0(X=Lfeg}WD!KM>|(FC4o{p?z7ui2JGBM<4m0=(hRH+W5)yI z2A`=KSSraKdqUo=!aL3*1DQu;k%2dnMy3euZ92T`C7@Ku^^&!F`qti7c>8$LeQWm& z{9P3F9k-e5r}46u1GT&NRj^I!27W_!6(2Y4uMqJ5ByhF$g@FT7Xa6{VIQMaBRa^N8 zGY_hUIkb@vFQY(mRQMOdpHc4m84}TNG?G6E<;Ay*ujE**N?tti>r4f2IQ;dlerMOw zb%i&7oB~XI_Eco(@q0p5s-FrZrR1c(qk#1A&K-Z|b!WFW{K0S5cB1W8?FrE^F9a|d zhX*hBheVTF67Cm?j<-t8?BgTLvpqGLht&rETY9Of8vKC1Z1J6g&)REkfSLT6*3c2c zf8n9w{=w&Jm|I9+&0P4^^Y_*r7ARfGO7%Uv<#Et(AKyhgeB(`SlZ|e&4f$ zAJS>dpSqOmR=3m|$8k0kr^|}d#*{@8(XwbH6EUSuJQ;~bqS4f{itWYQOP!3nJyV?4 z3vQ-+yEBnC|H@5dQoVYyvB1o2i$v#1kxVL3L>l#rx21FK)JVauK)I#T+v41xi%r{G z>$@YJuG!idS!NQ+RCgq9BIzxr+wERv*0>p&L8LsH&6q9mY?Oj-yu&nPEh^ldbOdVtT?(+GboWy=d&qi<`%a{iD-b(Zrb9>_AT*PI+IU1b@i*m zrah98U@ywbI+Ce&*EFfZ%)5^3LJ z+EU4F2@{WXc4f*sQ;}X1jik2Nl+A35XWiU=*Y(S`_eT6=%8hyj1eFq?cdr|dC%2hx zU9pTyKe5D?GSi-nCsWRv#^#2q)y{^M^($7cCbVwkMxrCu*%6DofutR_Q|q>6I~^9! zbz*5JlLZB$PO_t;z>IM#QDCA{$Fx$`Nhan~*vWLcj^=7hynZyYl_5uC>7IC`H`3E> zYHiY~YHDz*>l<5~SOOq-M>4TwqTDpQX*VS`)}|wEAW?HwgI}3#Vw~bA=-r-4rqWI% ze@=X*9$Bby`}hR)j0BxxlFnUtV7mHXV_8yiL}@ncD>}C@!_n zV|xCjraQPrq9c}w>K}#9nyLosr@`TjX-#%^GBN>Tx|ghO2ueERO?P#5m8n_TVmjSq zx68IMWo3zEnasN@63^%#!55pik-Llu)LrZprx^%8)8)o{^pBL|?nY-rQ&nqgxOt6J zUS7V@bj6r(qT5YmO{}{o-IGeTxyEiAFVYb^8>*UD*c$8#=}A$!3?KwKSH97$F;x z_DpQ6OR`6T)7p5AcH-1EH#XR$Ij8a*6Hc_JdV4Z%)PkcsdVyXWOHjOMm z>a?zJ3JY?PTpeDc_XJkCM7|VIWD@-4UOK%knTnFgrllx97I4%qQxzP_O{aBH z7CV^EL;g4$ z>|TH<)K=G5wQSs|*@@&0%$pU~q1_Jpydp?d|bMw@GB#u&H#cGhw31cs!CaJuU<`Av8DT zW=y1;>olwz#>i5|;EpVTn~1v|8JkK8^)%h^tF*}`AjRqSWQz8$&C*#7EE= z8)j^-HJ6zyOsiRM)|!~9H;twVI!qBaqm4@1&85h-9cZ>qGCCpnNhE`0+|-#BJji^h zS!Gr;#qOApTA551YISWkDKwbIZ7LIsM_rTdiZOT{RXmdJB9$_4HCLK-W-G0BcSj6_ zBrSl5C8MU3#g_iA%|cXU8v(wwFe_76Y3df3y7NulLQ{8vsk_kBU1aLsV(J!gs{&FS zcj+DGzr|%CHF7qv)mDYq+l@wIqj74w-1aT8M5hz$aEgl4MUJ~2HkgLCIPemvP$CH> zYR)DSQm9A?DqEyT3&3^LCY^0>2O-=jR5Ah;j5>2OUF;>@P8p{I`6vzrMao*xkv8*P z{$2yY>2#sR)X13m{K@BJJJJixeEFNt>yV24$>+q<$we1lSYhUSiTs_-QkFmY9Izv{ z-OSf0pPO=H;G`7xQ~7&a8K2y-aXx>$Wb!AU!zM_%9kK1p%zQg1FJ=ltlgs09hybm1 zAnx`bFf2~<$LWzjfH4naj~4qe)3pB+-jZ z*o#2u$Ub26$*4e6K+LwI`$#vuqO7bvn@T5BWg={Y)0z`^BdM}&J)uTeOU40L(u@pXISnFMsVwa6 zlXSL6=&1@X(&$$BxEDJOjkRIptsgO@3StN6_akL7^{w@dYYeTh4#-A+!dX?lzBSxp z2LoMCLq(9A%8S{rYZF`GcnQSyAO6oc46Z+S6tw)EQYm zozH2CM-mXQCZV8Frzf`Ejhi*eM41Z5&cae>!37tBB*>pgdMQLTr$#TAAYrBLv5uGzTLw327(&l8l+d;$PVVV)7a+S_KymFB8fzz=Q$`4IbwXu#4k#`cR z4=%Q7h^D-;G@l$xH#Og^g?N+&We|+hUn6%@as1aM-#G zQIrAAjOw6S3}>szLhzRkiu8^)*_y6MqSH1nMA+hAy4-1Hw8L~ERsg{(D&R(7M`~BX zD1ecPN!?N%hFsZ-Ips-KPwPSiyAVQDW7BHVhAf*mK})Tio+LQU7+8NqG$+~3D(4#W zR$sb_CD@}-0k1!>-P7Cr{$#9DFxM$%rAs?K0T=5+wTRaO^@{3N%&%TiRPNNR(CJhY zF*-~gZOM47-76^cl>t_bmhW_DfleEX&D`t`OuLI6)niMEvTi9ffjw2~h;~{E#RR22 zos0)@vsk)_3PS^FbZ6kgWZOUHQ25nlKwaHxLR^!!)sn%QWRA+%eA`XKBP93on zLwBWXN2lntM-noX+{#z4D0kMgCX#Qtxl?2{=OSTo01Z@=McWnu`yxyity-iZfbDjs zP&K^O@^Ml3zaX&#rLnjpdUiHtDVU(VUv$LIw3nml!ix)>%PsL9YI0z{#~UdVX!o@cjH#*Cg}m zeush&oK{wVv?vnf@rV!2IN|!1DyPBiPGX2sqk(F29fRny(`uu)KSEWd0LcVp^SUVU9%FZTC}26tOqlO z1AR-ygt&EgyU`e;KUmy>YJ^@o*Q0x~buU~fOE_-~3mPjeHUy_Sf>!Bu#igviv(8z# zqS`r6FG>q68m;!0b(A93Qa1vWzRhM^7o=uI^V({VoGoE--7|uC(it31Rz=i&k8yWL zfC*G2hL{mcv}4+ot%Usnn$d}DqP(`Jt2Z5MNAkkpLn-9AIB4N-ny{F8bYr!M9^q7$ zUy!%%c*Hwr7V1E@a~i6fWfObaE;tf#qA6?;rNT138b!iht)NgO^f5BBMqOQtBNl*| z+NPYmlwj3ZnV{dR6*O`dr(}D3wnvwhBBCy((;eBkKb`!>@KP-Zv&bnvr5Ac3luN}O zF+ItM1z>cT8xK>04E5wBCoyLFAdk9RWAy2XKO)m$x%7zRXr#!gqetJEg+i?Ap*4=c z>=9m%b3XyDC}I`nYBGR8*0|Cu3u9d zZgy6Nt7@H=a7}Atv*@y|RjaSDR~Rk=zx>JsjEM?PZ`p0bFk=e^(V#HaV>vBVIxmbs zHm#6u-*T6OrJxPy!S+jG=7{%NzMG$r()(Umgcu`~u?Lu@(}gB+Y_5+svV>AU&t+ji z;C>FTlx@q%l8z6QQiV#X4;E=62pM6;B4vujO$Hm3KZcj1qBIDv!D2uqzTHXn>(!iBBOY?-^YEjpWg6KaVL!KY7RJ7u4-U94Cnnopz+J=1B+ z#yCewAo*Z$NkkEQ)*xETp7L{q0whW@par6fil$Oe7f0=x(kJC@hXLG^OqAJE&oG+SA|kYNSI7|dy?V1jR|mk4OKvLlk&v{Tcx)~7at zv36|8ze(tBMkTR$GTGy!%LwQhqw*7bP|Vn>en+}FG1y}5w?Y*o&T2iOvde1wkBLC2 z!|}Inq=z{{5kX-AFccJ40Bf~qY+Imgw#TFP36Fh`IWB*oS42``4O=`69ik=3hgQuO z$r7R0!xxW7<@QyMoymrZ6y)_9OExnoFWRuZ%qtSModvR=!LKw%gt30U0f`d>IA^E3 zV3~5F1=om7$^k;aAhpqBoX&>mMxQ;}!U!o?mnq#tsA*hNSHHrq-yDYU2D3&Cq~0=Y zziFmv8Lw5Q{LzUZ?VY+QZ5Gxmd&KJ=SVkOg&Puj|dkq6Emw;B-22*pIXVgd3rNRV5GrORQ7y}uGZrBtCI>L3jHQjdU6bayc~ z_@$zPeptw$q>&)i^tFp>$WP2%h8z(B3Wc$qf(4)9R&e&x;uh8r#N6~c}FVQZB2YCGeY-r z5-sADRrNSW1EDdQw85>qeSN#g8==R{)jopx!>Ph>4dB&;>02~XuD^X%Q}8!FXy?_o zd)`|jdk!iH=No_0+0ITGnJPody#ajAV?qQe+dj?6L80HRi?Iu0L)jvGrdm|$6nV$0 zlJrhiCCOy7+a=+jvZ9`_3yN}QtxT;ok3}O6UL81mJZ;r9u|dOx<@C|#q2LZH=wsk8 z!Zg6XH{76#5BPp;G;*XG>Kp-5~A3)6$x5A+1j212ZSFug;dp} zNhQ||R`g2-Y4a=|Gu!;~$Xdi>nA5-mieKX)(lt&~O}=H6N_Z`nUz|y#;W4MC;}f%h zjKgk){He6GpU?M?tp)guf&U3tBq+gR*i6Ez65=GH=4VHV0m~{@Aoz*Zuh0ch2)hJv zYa3h8h*d%4I)U-pXZ6ZiulJQ7 zW`VS&s3ga~B2_iiULfQRb>R5m_2fId)$Mi+igr2AA+NC@Nsx0Y34&#*S#EFBG86x_mBUa`oznB{20IP~V*La&ioEIg zy$GFR=f-3BO3D3AwvQ5j7^4HKm6B;u_-S>MZLy@3v9!BFG{xwW+ozCr`Vxzmp6f6{ zkN4z^B_kJ)YtLoHdOgrS=4vs$1KUWdGmF{V${ynLAZXo*>d5YaWWTRd>R%&7|g^ikqm zD4NQM05j`?awB*x>lfs(x;ukF^IVuL7Wyts$HgvQOr%yk&l|{t#kL3o&B90HEWaGS zvn0CheWn^fvt|+hBL2C6-LNW5S&Q{ZMMakiG!mCQ4{TlT_T!LppMP_-g^?uV6a|>G z9+}93TA4Ga`H=+;$qRnn*eh5el}9=~c_6=m#7`BkC2&-hLN@yF4Tk>fTg+L_P2rZs z;g)(RjcyyUw}{{!IDNG?3Khgs>3IrL2me~j;nlUx_U0>la?g@#5%j$NW1OzSyD|T% zkZM^SjoEDkDB3ev>vL+Jqhk(AAtDxlOcCumooy@2PngvN!&O8I$Z}ZztYenY7Hhwd zb!W4w=4)HKt;Onoac$qkL0N>q? z2bK^S#1aY!nWT+`Q(qgl>akHNuVn3Wgi7?0Qv1qW4{vl1Ee z#||h47+=2vq!B+YqNQcfO6(^t`bqTNs8D2 zzn3~lxZNVGLjzbKmALHeJZgr$8QkPBThu0Rmj2GMyG<<-YZ~E`$W1ns*wol;uh5rqBW!63himn& zdJ$gH*le#r8Sx>6lh(Jc*ZXPlE^KLSY|<-BUY2248fN-eDp+srhC)LkkbQAH^vF@U zBZIMfC>rY&@+08&Rd?TLIjoM9R=P6REr+)|iWf{6&S*=DRwMCR&k zQ>0J`9DPBUtkWa{h)i2rmX)n-4VMw5zAU@Iz`v!kwUuT{#iR@{{9C^0VIk#Pn*>4a z8U3b262#wx2WE+qs7>OBSt7DeW0T*8Cnq6O2z13FJ=Yg@a|*9V$b+ZmdbsX!*Wlra zWvh8;%H-5qIlLHJJDBfD^VQ zMXTe4(Q;ee}P*U1Wci{Wuv>)5ISWI$n&az5VC7lJ2SPM4SEhYAi8=(&f{ zAM%6%CBB=r^XRbf|^C=|G9LHHF)w6tc{D}V$}=VB<|%v| zyB7M0P*_#el~k*6p^^d0FhJWpJ~X>s9IuoHH)CRH%1(Px9T6kPrWZXcL0y}>k0#(bSr1e;$2Yj*Gl-05Qqnfl% zKzK3zj7??GM$ut>3B|1vXEqvo%v$QBfwA9Vkaz zEG`EKLJ8Ap%rkaaG6Nr(a}M94+{&a-ec%anfkdOnN|>R=zkAHOV1uU>Rkf_dKOB3N zZ$Rka2?X&o^?{Q!FbQySZsjsO(MOf%>4}fOm9?HOEK^r6OOdGs-9#l%>gjtciM z6ak09OdN=|$GWrKzTyKV)lwsXZBbQ*q5_+UWKai2C2}*CSq$~EUo7Z5lCnQUGFhfh zHOIKCw}dZ~674~kb@FtRC<7hgp`N>Utn<3u%I}d{xDGO!U?%J?qU$T(LCk6xY9OsD z6=gm?Fqsk(lhn3?2q1)yCa^oJl7^5;VWCFDF$gaowUBh9;R|KHN)F{yPPnB;ch1%8 z^inMP)>xFoAAbjUi$mihw$=#jw>w%l2Dm1~V3c3MN|YiuRf$`W_@p5~;eUR@i~M=F zt-j!dHHI~uuWlM5+XYM&+bb&~?G=linD=z7kl3E2eS|kq{FoW2eMMFeEI?CJsFBnK zRD&2CCylh761^kmwyY=8p2-xT^tlVhmVea2-xa}!ERI>$ zT!zzv%~-q?F+1UDBL;HyowUxW$8o&yT46Fp0YxL20YiWoa4AXsA#&E_X!YI5gz=s4gW>_6<&J& zEyAOO9}=D>{EF~r!e0sFc{|NC!W#&42=fUS5W<8tgb1OF&`a1s2>sfaYC=7siEsts zYJy9M6FfnOM}e)xWeUQw;c-5;PsbK)5bUxjC0HwzTrAcb%?#`0d+gsCvKH^-l@Z-1 z8NNojS5tmuyZgL;f^A5;>9@wbneZ&>|4mr$)eW{G=@0)NTpKjzUSbJlq^kngmwD;i zc~zue=6hcHqCe*I{Cl^I$UDIGXg_tUUa@Aa-C{x|EhS1j&fMbYDyWyZkI%>Bb=9zq zHLpM(`c|fF35Ce!7-981N)(Ta<(V`UX98rzUumAm^akT>a2oKPahGmKTR*Qp-szqIPEB##6^91(8C8)|Os%6g z&?JYGdRS+DBzdMM5|0JPG+M9uyoOksLv(f33QWUCBLJsLVx@iJbV0tJpIYs4$2MGB zwmFpz)yJ?uzvSrgD*L_<-!i7hCY+$yqcHD?Wb~RgcWokvT-LYLo|jlXA`OvJ(+_WT z7~@x;hgUYxlyx&v$0~$ZAT&mG#h;uM6;z>A=nxx|D(qsK2QT~wKJ%^Bv+%y46BNnp zfg`$5zUZi_8r!}#2l%>V-X`Gb$KX%9=O?ab`z}YSzM7MVA9fM3b`0xhwKxQMl22}r z3|}R2olT7e;Jk;0cVsmBO2YufQ)*b(dJ*v7is-`(b_eE8Msn7VW2h{$s1&F&s|}$&##1Z~&L=OknlL$4BW3`veWW z)A;!0<>v8E2u)u6$ghi@GDa`l+d${jo*$w83fm!cdV z7tBj&cJ7%w$nlo+@IiYzo~>*h{%mc3{QeoaB6x03BV+?22uvrZLcAad3XZlv%8i)SYR9E+BjOQLEGcg1#D(uf%e`Ue zyI4(+d7x{IhqvfV{QHk-!ivaxP~bBcftrO*O>IR*Wp0@A0Ct{&_Tv@J{|BFP`%<5BWCe@Cso47Kx za6&DQ{Z+3H*NT)>&0_|z)MAK;piP0PZ>VWj9k!{y#x&Gau|!556C`q+#xM_`=zC*6)QGMn4_SDC3?hNH;XN#|p^E;zkpO81w2?>c zjt`r&D;PiaZO9XzhK$E+Yi@N*6K~335aOGAOv4y8C>QEYu|#tC~fk+@Qy-kIO;|N}|&2*-SMElw55YzwJM~9a8~H-!TIj zt7ESXsgDe#1Qkvkcyu}#1UDEx5-xV=AYJ@XT45dlT;Pml6- z#l%`i*Q$@_3kF~wOxEeMK+L=jp+J2OTGUlathi0`96ET4vd^=_MxNT2-J{1EV(~@A zfUMcK6Y+Wri>NY|lHzoU>L-G^lHsu{jK%2;Hwp?`k@j=a4mKj#wd~EP6C9hQRU-{+ z0q**CWf2nHW1fwWcU1^$vUXy-vjmF&>~G|lg4bhe%)w5B6-K1%^daUs-qW=wp|Fjp zul=v|Un&4h0>ETVi~u_L_`kjV>flH-WB$B>TjR6q6t^o~CE`F;O>lOVy`z-e-~vNB zzKzU+(ZYq=U?XCm>IkAR=1@rdp-Wsn3KPr}sl*$Zhk7~ZC8-Na>T!KZyY(Q-xu@&f zZhX~P=N#<6q)j`J7LMsHKNPP+QUCIz&=LFgcPfwCG5JaDK^*$gc*RXpRB>-65q;=j zZb_pZwAHcZsQ{LPgA}J3+&BPJ3KN|5&hc6pQ4BiaoeWU86R>hVEcFDk-T0!515tJu zG>%1sAbgIyJ|df!@K_S<+j0?aP`(4D+_Ao!Isj|R<+K+a);m@jb};V^#e2;VZhbX@ zwsi(FcwS8fO@I{K_0f=77zpnRq=We*(;q&`a#HUducGY8eol1#aj)%9jp*ZZfotji zOM&ar+Wh8-`ww#cDB%gh`5*hg2~G5K7D3`*xOl|1+}k=vo}V9#CH-nbux~&8YU=;9 zWmk+czkjyPS5x1IuWY5y|G$vAJPJsC+d9jk=Uq$L zhI{kv-$we8z_pYQ_TNtV+X#~XB=Ijl8#15#`0yZkkwCs&`{hQ)BkLaT+Hc2iL&^rz z$E!Q?p496IjB(_Bxo#cf{%Czl*Wx-rWZsciS$<^w|Lt|dtLRtCzS{D^agA12@`68J$t~Y+G!o05 zX5Q=H_$g!NkiLrak#CXvpYYI6+dN4--wv5A+}m`o%}Yv}ytfnI@8!LV^gZN#miSMf zk&pQr^99oT^y^N1T$pq};W@$(q2P-lGmCJ5^!Eu*5q?GZBjIm^3EVq{@Or}8g#Tn* z_kYfqvuU@2YlqjL*AsVq-j1o2^gR!R%zKHyLZ0+5=?@dSzsg4?$&+`$`@aXspU2l< zW!{oLM0kbpPA^Z=J0A*}bH4;{{DN(-g0%Tw$kY+1zcjqPGm$o`OV4us4@=tLS7^B558{8IftlA*htZP z2W>e?@B9%sLA>-Kn>Xnz)Ftor#7}#9=aN41W7eBE^gTP@IO*j-;XIaj$jiHt^bztt zNId1BE%zU!cRm?1-z8r7ura4GzI|LDAv{W6_z`1HCGRoPM}A6M#2w@@OEUr7asCTj zBz_-xGB-(|PFPM@c*y33N$;fGRm8Pko_U(Ogcy0P*CK<~!__IAOu^@n$;f@G$x3pUubQN&krS!gD5?YbgIS z(iap@GN+UOYtk29J=x4AJwW=RH%~EVk$#T!Th5(o-bngo(u?L6n5opA^tF(wm^aOw zN_+;P?3(GOh%y{M+k{OPnHX+;NuKK`g%l^Ln$(OB?eB^E&qWXV_zr zsyCV^nD6=Qqjbxg%VushO5bFEgj)(ifXkbLmUWtXz7zIU|>@ zGOx>}tIZp7=^EqY(zWIsFMWe)G3Sx)K5X~Y0?Gen$eacYKKO*)qsxB{jU&8=yvLrj z<(%JgYxOgmw|oHlL%5B+)~D^hy^HkDLF69df?wG721wuYN9Y;xl3xy|%de2P zj=TvTR3w_fx?Dq^(CTTVk5KpZ#C_z=A+MP9@;^Z{i4S^the?}fLgsEhBKR4?KEjU( z{eI|v^q+($S>I6`=yFlG8U^Lj!Bp_Z_Y5GU*;+)4N(;ah~mgx?U3 z5~j}>XB@&p!b-wbgdW08gu4l!A?zdkh|o`XnK1K|aVC1|IJ2E_8{r%sXJEL zBYz2*-$EOm=b!_Gdk9Ae&huOo%!}j^pH5ssI6~U_EA)``CgOVt`v`_MmJ`;IpC#N( z*va)riN8pAgs_k6Ul2b_2pt6;gaw2K!e+wA->i`tTuUjNKXcgKe7+XR-IIJi?3W8Y zxjQFLh|gBV9O%(G%=gXt@rh5@l-VIucoy>^_&@R8%3KmMQ>&n{1pg<#Tsv0+=LUSf z8g2f=E!MZ|oDCs!cw@-ic~!o=_=3IkmXP_kMIm#?5}RK_yW#`(-A-iPF67qD`SRjZ z7H<{$3r<~O^QY6U_?9)zhYz2RzC-N)#P_UgUdS9h7utKC&Hq$+{=Q$%k5zc*qQJ{g z{2M=U^3+pizGl{IXTSc9e!&s3v^X@b+?0>V_b>H+Xso+ZiV}`rdV=EpZ1D9A!pZyu zLqx`UjaQg&F)AL&rzIy5WIhuK(+EN{rxV5#W)Or@oI;SE3JIhA##3t|EloxWnM!NZ zs98vlrU)sWK6Bqj|uDLN|s&<3i&@6GD?hQ$o{2GefgOPN*WZ zJhUk|AL-Ta&+liF&P!${bCcQ0{H6h;>GU*%91Fu>JIAKMLB>`HEG{uOm?1M18X7+| zd8lycO+%Lq-5^?_zc*!HN?LwCctU4~JNxea{xh%q{2O;~ZCx;P^7K<*J8|kMvnEWN zdB&uI!qc~ZeDjl+f9*j3&w8A5{`7-yKk)g&>;8J~{+m~vR#)-K&|P)^cPjtU#@Q}e&Y+vzqEYcWmjJP=1(8^>cGaC z^MBGZt9IOtzx&8j2mk)W|Nq_he>vwTlP`Mk<{3YJ{*SY+3{M>R^{0-0?3tH;Ixg9H z%j$FYRxf&K=*AbWy}2mz!S3mA`RzYye}DhSKlQ`^UbSh}H(%)a)_3mTfBpOCzEtv& z-|wz?=0_9Xu!nE`{^+N_eechHcl5fCzRA7(GY{1k&3pdeht93}#MyV=yXc;Gzx?3( z4eq-RO}}Hu^Un-Dw(+Ljjn{uNdE|Gcugt0mee5HrPFeG|>swyD;4h26{msXpJolYX zynWF5kq;>gx6%F{uf!%6v4Tqb*dW4Jb{5+`z*j1Cf0*~!{a}9S$r;}jO!+5&qcnh| zttaq9p{AO8$8p$ul-l>oc-f3#jYgrNkj79HjmHn!+Y^Q+==H>*i5gEDnxygMp~)Ig z8JeQ;)S;;w7Yr3>JZ)&2#?yzUYdm9UhQ_B1ouYB!P@y(lIAkWsmZ}bXRm^TU Ho!$Qc-BTe< diff --git a/src/linker.ld b/src/linker.ld new file mode 100644 index 0000000..9a19dc3 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,26 @@ +ENTRY(loader) /* the name of the entry label */ + +SECTIONS { + . = 0x00100000; /* the code should be loaded at 1 MB */ + + .text ALIGN (0x1000) : /* align at 4 KB */ + { + *(.text) /* all text sections from all files */ + } + + .rodata ALIGN (0x1000) : /* align at 4 KB */ + { + *(.rodata*) /* all read-only data sections from all files */ + } + + .data ALIGN (0x1000) : /* align at 4 KB */ + { + *(.data) /* all data sections from all files */ + } + + .bss ALIGN (0x1000) : /* align at 4 KB */ + { + *(COMMON) /* all COMMON sections from all files */ + *(.bss) /* all bss sections from all files */ + } +} From a756993df683dd8692322032b0ee5dea763896dc Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 22 Feb 2023 17:42:08 +0700 Subject: [PATCH 003/176] Currently develop at 3.7 --- makefile | 12 ++++++++++++ other/grub1 | Bin 0 -> 105522 bytes src/.vscode/launch.json | 7 +++++++ src/.vscode/settings.json | 5 +++++ src/.vscode/tasks.json | 28 ++++++++++++++++++++++++++ src/framebuffer.c | 37 +++++++++++++++++++++++++++++++++++ src/kernel.c | 15 ++++++++++---- src/lib-header/framebuffer.h | 30 ++++++++++++++++++++++++---- src/lib-header/gdt.h | 2 +- src/lib-header/portio.h | 2 +- src/lib-header/stdmem.h | 2 +- src/menu.lst | 5 +++++ 12 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 other/grub1 create mode 100644 src/.vscode/launch.json create mode 100644 src/.vscode/settings.json create mode 100644 src/.vscode/tasks.json create mode 100644 src/framebuffer.c create mode 100644 src/menu.lst diff --git a/makefile b/makefile index b0c0033..ab894d8 100644 --- a/makefile +++ b/makefile @@ -29,6 +29,8 @@ clean: kernel: @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o # TODO: Compile C file with CFLAGS + @$(CC) $(CFLAGS) $(SOURCE_FOLDER)/kernel.c -o $(OUTPUT_FOLDER)/kernel.o +# DONE @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o @@ -39,4 +41,14 @@ iso: kernel @cp other/grub1 $(OUTPUT_FOLDER)/iso/boot/grub/ @cp $(SOURCE_FOLDER)/menu.lst $(OUTPUT_FOLDER)/iso/boot/grub/ # TODO: Create ISO image + @cd bin + genisoimage -R -b boot/grub/grub1 -no-emul-boot + -boot-load-size 4 + -A os + -input-charset utf8 + -quiet + -boot-info-table + -o OS2023.iso + iso +# DONE @rm -r $(OUTPUT_FOLDER)/iso/ diff --git a/other/grub1 b/other/grub1 new file mode 100644 index 0000000000000000000000000000000000000000..9e1617cee78bb8f1ab6838837c9a1f36d729c9fd GIT binary patch literal 105522 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 I8%}5UKb>zEqW}N^ literal 0 HcmV?d00001 diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json new file mode 100644 index 0000000..5c7247b --- /dev/null +++ b/src/.vscode/launch.json @@ -0,0 +1,7 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [] +} \ No newline at end of file diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json new file mode 100644 index 0000000..8fb8c15 --- /dev/null +++ b/src/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "kernel_loader.h": "c" + } +} \ No newline at end of file diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json new file mode 100644 index 0000000..0bb8a85 --- /dev/null +++ b/src/.vscode/tasks.json @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc-9 build active file", + "command": "/usr/bin/gcc-9", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}/${fileBasenameNoExtension}" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Task generated by Debugger." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/src/framebuffer.c b/src/framebuffer.c new file mode 100644 index 0000000..c7841c1 --- /dev/null +++ b/src/framebuffer.c @@ -0,0 +1,37 @@ +#include "lib-header/framebuffer.h" +#include "lib-header/stdtype.h" +#include "lib-header/stdmem.h" +#include "lib-header/portio.h" + +uint8_t* mfb = MEMORY_FRAMEBUFFER; + +void framebuffer_set_cursor(uint8_t r, uint8_t c) { + uint16_t cursor_index = r * 80 + c; + out(CURSOR_PORT_CMD, 0x0F); + out(CURSOR_PORT_DATA, (uint8_t) (cursor_index & 0xFF)); + out(CURSOR_PORT_CMD, 0x0E); + out(CURSOR_PORT_DATA, (uint8_t) ((cursor_index >> 8) & 0xFF)); + + // TODO : Implement +} + +void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg) { + int frame_buffer_index = (row * 80 + col) * 2; + mfb[frame_buffer_index] = c; + mfb[frame_buffer_index + 1] = (bg << 4) | fg; + + // TODO : Implement +} + +void framebuffer_clear(void) { + size_t mfb_size = 80 * 25 * 2; + for (size_t i = 0; i < mfb_size; i++) + if (i % 2 == 0){ + mfb[i] = 0x00; + } + else { + mfb[i] = 0x07; + } + + // TODO : Implement +} diff --git a/src/kernel.c b/src/kernel.c index 01b5a07..cbef69c 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,13 +1,20 @@ -#include "lib-header/portio.h" +#include "portio.c" #include "lib-header/stdtype.h" -#include "lib-header/stdmem.h" -#include "lib-header/gdt.h" +// #include "lib-header/stdmem.h" +// #include "lib-header/gdt.h" #include "lib-header/framebuffer.h" -#include "lib-header/kernel_loader.h" +// #include "lib-header/kernel_loader.h" void kernel_setup(void) { uint32_t a; uint32_t volatile b = 0x0000BABE; __asm__("mov $0xCAFE0000, %0" : "=r"(a)); + framebuffer_clear(); + framebuffer_write(3, 8, 'H', 0, 0xF); + framebuffer_write(3, 9, 'a', 0, 0xF); + framebuffer_write(3, 10, 'i', 0, 0xF); + framebuffer_write(3, 11, '!', 0, 0xF); + framebuffer_set_cursor(3, 10); + while (TRUE); while (TRUE) b += 1; } \ No newline at end of file diff --git a/src/lib-header/framebuffer.h b/src/lib-header/framebuffer.h index 1e6786e..1727215 100644 --- a/src/lib-header/framebuffer.h +++ b/src/lib-header/framebuffer.h @@ -1,12 +1,15 @@ #ifndef _FRAMEBUFFER_H #define _FRAMEBUFFER_H -#include "lib-header/stdtype.h" + +#include "stdtype.h" #define MEMORY_FRAMEBUFFER (uint8_t *) 0xB8000 #define CURSOR_PORT_CMD 0x03D4 #define CURSOR_PORT_DATA 0x03D5 +uint8_t* mfb = MEMORY_FRAMEBUFFER; + /** * Terminal framebuffer * Resolution: 80x25 @@ -25,7 +28,11 @@ * @param fg Foreground / Character color * @param bg Background color */ -void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg); +void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg){ + int frame_buffer_index = (row * 80 + col) * 2; + mfb[frame_buffer_index] = c; + mfb[frame_buffer_index + 1] = (bg << 4) | fg; +} /** * Set cursor to specified location. Row and column starts from 0 @@ -33,13 +40,28 @@ void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg) * @param r row * @param c column */ -void framebuffer_set_cursor(uint8_t r, uint8_t c); +void framebuffer_set_cursor(uint8_t r, uint8_t c){ + uint16_t cursor_index = r * 80 + c; + out(CURSOR_PORT_CMD, 0x0F); + out(CURSOR_PORT_DATA, (uint8_t) (cursor_index & 0xFF)); + out(CURSOR_PORT_CMD, 0x0E); + out(CURSOR_PORT_DATA, (uint8_t) ((cursor_index >> 8) & 0xFF)); +} /** * Set all cell in framebuffer character to 0x00 (empty character) * and color to 0x07 (gray character & black background) * */ -void framebuffer_clear(void); +void framebuffer_clear(void){ + size_t mfb_size = 80 * 25 * 2; + for (size_t i = 0; i < mfb_size; i++) + if (i % 2 == 0){ + mfb[i] = 0x00; + } + else { + mfb[i] = 0x07; + } +} #endif \ No newline at end of file diff --git a/src/lib-header/gdt.h b/src/lib-header/gdt.h index 8071183..e41e3ab 100644 --- a/src/lib-header/gdt.h +++ b/src/lib-header/gdt.h @@ -1,7 +1,7 @@ #ifndef _GDT_H #define _GDT_H -#include "lib-header/stdtype.h" +#include "stdtype.h" #define GDT_MAX_ENTRY_COUNT 32 diff --git a/src/lib-header/portio.h b/src/lib-header/portio.h index c4080b9..ed32fb3 100644 --- a/src/lib-header/portio.h +++ b/src/lib-header/portio.h @@ -1,7 +1,7 @@ #ifndef _PORTIO_H #define _PORTIO_H -#include "lib-header/stdtype.h" +#include "stdtype.h" /** out: * Sends the given data to the given I/O port diff --git a/src/lib-header/stdmem.h b/src/lib-header/stdmem.h index a95fce1..10ecd1b 100644 --- a/src/lib-header/stdmem.h +++ b/src/lib-header/stdmem.h @@ -1,7 +1,7 @@ #ifndef _STDMEM_H #define _STDMEM_H -#include "lib-header/stdtype.h" +#include "stdtype.h" /** * C standard memset, check man memset or diff --git a/src/menu.lst b/src/menu.lst new file mode 100644 index 0000000..5c5d15c --- /dev/null +++ b/src/menu.lst @@ -0,0 +1,5 @@ +default 0 +timeout 0 + +title os +kernel /boot/kernel From 8611498feb7df719ae80eddc1fed9efd269cf751 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 22 Feb 2023 18:31:23 +0700 Subject: [PATCH 004/176] fix: makefile --- makefile | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/makefile b/makefile index ab894d8..7155f3d 100644 --- a/makefile +++ b/makefile @@ -6,7 +6,7 @@ CC = gcc # Directory SOURCE_FOLDER = src OUTPUT_FOLDER = bin -ISO_NAME = os2023 +ISO_NAME = OS2023 # Flags WARNING_CFLAG = -Wall -Wextra -Werror @@ -18,7 +18,7 @@ LFLAGS = -T $(SOURCE_FOLDER)/linker.ld -melf_i386 run: all - @qemu-system-i386 -s -S -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso + @qemu-system-i386 -s -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso all: build build: iso clean: @@ -27,10 +27,9 @@ clean: kernel: - @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o + $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o # TODO: Compile C file with CFLAGS - @$(CC) $(CFLAGS) $(SOURCE_FOLDER)/kernel.c -o $(OUTPUT_FOLDER)/kernel.o -# DONE + @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o @@ -41,14 +40,14 @@ iso: kernel @cp other/grub1 $(OUTPUT_FOLDER)/iso/boot/grub/ @cp $(SOURCE_FOLDER)/menu.lst $(OUTPUT_FOLDER)/iso/boot/grub/ # TODO: Create ISO image - @cd bin - genisoimage -R -b boot/grub/grub1 -no-emul-boot - -boot-load-size 4 - -A os - -input-charset utf8 - -quiet - -boot-info-table - -o OS2023.iso - iso -# DONE - @rm -r $(OUTPUT_FOLDER)/iso/ + genisoimage -R \ + -b boot/grub/grub1 \ + -no-emul-boot \ + -boot-load-size 4 \ + -A os \ + -input-charset utf8 \ + -quiet \ + -boot-info-table \ + -o bin/OS2023.iso \ + bin/iso + @rm -r $(OUTPUT_FOLDER)/iso/ \ No newline at end of file From 44b42a95e8f8831d2ae589154532fd3f768cfa18 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 23 Feb 2023 18:16:36 +0700 Subject: [PATCH 005/176] add gdt --- src/gdt.c | 72 ++++++++++++++++++++++++++++++++++++++++++++ src/kernel.c | 2 +- src/lib-header/gdt.h | 11 +++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 src/gdt.c diff --git a/src/gdt.c b/src/gdt.c new file mode 100644 index 0000000..31af4db --- /dev/null +++ b/src/gdt.c @@ -0,0 +1,72 @@ +#include "lib-header/stdtype.h" +#include "lib-header/gdt.h" + +/** + * global_descriptor_table, predefined GDT. + * Initial SegmentDescriptor already set properly according to GDT definition in Intel Manual & OSDev. + * Table entry : [{Null Descriptor}, {Kernel Code}, {Kernel Data (variable, etc)}, ...]. + */ +struct GlobalDescriptorTable global_descriptor_table = { + .table = { + { + .limit_low = 0, + .base_low = 0, + .base_middle = 0, + .type_bit = 0, + .non_system = 0, + .DPL = 0, + .P = 0, + .segment_limit = 0, + .AVL = 0, + .L = 0, + .D_B = 0, + .G = 0, + .base_high = 0 + + }, + { + .limit_low = 0xFFFF, + .base_low = 0, + .base_middle = 0, + .type_bit = 0xA, + .non_system = 1, + .DPL = 0, + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + // TODO : Implement + }, + { + .limit_low = 0xFFFF, + .base_low = 0, + .base_middle = 0, + .type_bit = 0x2, + .non_system = 1, + .DPL = 0, + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + // TODO : Implement + } + } +}; + +/** + * _gdt_gdtr, predefined system GDTR. + * GDT pointed by this variable is already set to point global_descriptor_table above. + * From: https://wiki.osdev.org/Global_Descriptor_Table, GDTR.size is GDT size minus 1. + */ +struct GDTR _gdt_gdtr = { + .size = sizeof(struct GlobalDescriptorTable) - 1, + .address = &global_descriptor_table; + // TODO : Implement, this GDTR will point to global_descriptor_table. + // Use sizeof operator +}; diff --git a/src/kernel.c b/src/kernel.c index cbef69c..255d338 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,7 +14,7 @@ void kernel_setup(void) { framebuffer_write(3, 9, 'a', 0, 0xF); framebuffer_write(3, 10, 'i', 0, 0xF); framebuffer_write(3, 11, '!', 0, 0xF); - framebuffer_set_cursor(3, 10); + framebuffer_set_cursor(3, 9); while (TRUE); while (TRUE) b += 1; } \ No newline at end of file diff --git a/src/lib-header/gdt.h b/src/lib-header/gdt.h index e41e3ab..f0262ec 100644 --- a/src/lib-header/gdt.h +++ b/src/lib-header/gdt.h @@ -28,6 +28,16 @@ struct SegmentDescriptor { uint8_t type_bit : 4; uint8_t non_system : 1; // TODO : Continue GDT definition + uint8_t DPL : 2; + uint8_t P : 1; + uint8_t segment_limit : 4; + uint8_t AVL : 1; + uint8_t L : 1; + uint8_t D_B : 1; + uint8_t G : 1; + uint8_t base_high : 8; + + } __attribute__((packed)); @@ -50,6 +60,7 @@ struct GlobalDescriptorTable { struct GDTR { uint16_t size; struct GlobalDescriptorTable *address; + } __attribute__((packed)); #endif \ No newline at end of file From 3c1c962d3578045ba298204260303dedb37051ea Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 23 Feb 2023 19:20:03 +0700 Subject: [PATCH 006/176] Finished spec --- src/gdt.c | 16 +++++++++------- src/kernel.c | 9 ++++++--- src/kernel_loader.s | 8 ++++++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/gdt.c b/src/gdt.c index 31af4db..a70e2c6 100644 --- a/src/gdt.c +++ b/src/gdt.c @@ -9,9 +9,9 @@ struct GlobalDescriptorTable global_descriptor_table = { .table = { { - .limit_low = 0, + .segment_low = 0, .base_low = 0, - .base_middle = 0, + .base_mid = 0, .type_bit = 0, .non_system = 0, .DPL = 0, @@ -25,9 +25,9 @@ struct GlobalDescriptorTable global_descriptor_table = { }, { - .limit_low = 0xFFFF, + .segment_low = 0xFFFF, .base_low = 0, - .base_middle = 0, + .base_mid = 0, .type_bit = 0xA, .non_system = 1, .DPL = 0, @@ -41,9 +41,9 @@ struct GlobalDescriptorTable global_descriptor_table = { // TODO : Implement }, { - .limit_low = 0xFFFF, + .segment_low = 0xFFFF, .base_low = 0, - .base_middle = 0, + .base_mid = 0, .type_bit = 0x2, .non_system = 1, .DPL = 0, @@ -65,8 +65,10 @@ struct GlobalDescriptorTable global_descriptor_table = { * From: https://wiki.osdev.org/Global_Descriptor_Table, GDTR.size is GDT size minus 1. */ struct GDTR _gdt_gdtr = { + .size = sizeof(struct GlobalDescriptorTable) - 1, - .address = &global_descriptor_table; + .address = &global_descriptor_table + // TODO : Implement, this GDTR will point to global_descriptor_table. // Use sizeof operator }; diff --git a/src/kernel.c b/src/kernel.c index 255d338..aecd426 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,14 +1,17 @@ #include "portio.c" #include "lib-header/stdtype.h" -// #include "lib-header/stdmem.h" -// #include "lib-header/gdt.h" +#include "lib-header/stdmem.h" +#include "gdt.c" #include "lib-header/framebuffer.h" -// #include "lib-header/kernel_loader.h" +// #include "kernel_loader.s" +#include "lib-header/kernel_loader.h" + void kernel_setup(void) { uint32_t a; uint32_t volatile b = 0x0000BABE; __asm__("mov $0xCAFE0000, %0" : "=r"(a)); + enter_protected_mode(&_gdt_gdtr); framebuffer_clear(); framebuffer_write(3, 8, 'H', 0, 0xF); framebuffer_write(3, 9, 'a', 0, 0xF); diff --git a/src/kernel_loader.s b/src/kernel_loader.s index 20445c0..2439411 100644 --- a/src/kernel_loader.s +++ b/src/kernel_loader.s @@ -33,11 +33,13 @@ loader: ; the loader label (defined as en ; More details: https://en.wikibooks.org/wiki/X86_Assembly/Protected_Mode enter_protected_mode: cli - mov eax, [esp+4] + mov eax, [esp+4] + lgdt [eax] ; TODO: Load GDT from GDTDescriptor ; eax at this line will carry GDTR location, dont forget to use square bracket [eax] mov eax, cr0 + or eax, 0x1 ; Set the protection enable bit in eax ; TODO: Set bit-0 (Protection Enable bit-flag) in Control Register 0 (CR0) ; Set eax with above condition, eax will be copied to CR0 with next instruction mov cr0, eax @@ -46,7 +48,9 @@ enter_protected_mode: ; Warning: Invalid GDT will raise exception in any instruction below jmp 0x8:flush_cs flush_cs: - mov ax, 10h + mov ax, 10h + mov ds, ax ; Set the data segment register DS + mov es, ax ; Set the data segment register ES ; Set the stack segment register SS ; TODO: Set all data segment register with 0x10 ; Segments register need to set with 0x10: ss, ds, es mov ss, ax From 70752244fee82a57222d19560cf37050f1fb3815 Mon Sep 17 00:00:00 2001 From: christodharma <13521009@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 08:32:08 +0700 Subject: [PATCH 007/176] changes --- src/kernel.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/kernel.c b/src/kernel.c index aecd426..4a5bd52 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -20,4 +20,16 @@ void kernel_setup(void) { framebuffer_set_cursor(3, 9); while (TRUE); while (TRUE) b += 1; +} +void write_splash_screen() { + framebuffer_write(10, 30, 'B', 2, 0); + framebuffer_write(10, 31, 'R', 2, 0); + framebuffer_write(10, 32, 'O', 2, 0); + framebuffer_write(10, 33, 'T', 2, 0); + framebuffer_write(10, 34, 'H', 2, 0); + framebuffer_write(10, 35, 'E', 2, 0); + framebuffer_write(10, 36, 'R', 2, 0); + framebuffer_write(10, 37, '4', 2, 0); + framebuffer_write(10, 38, '2', 2, 0); + framebuffer_write(10, 39, '0', 2, 0); } \ No newline at end of file From 1003ebf1797434e7466bdd25742011b2261a3e06 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 11:42:12 +0700 Subject: [PATCH 008/176] refactor: splash --- src/kernel.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 4a5bd52..df678fa 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,12 +1,11 @@ -#include "portio.c" +#include "lib-header/portio.h" #include "lib-header/stdtype.h" #include "lib-header/stdmem.h" -#include "gdt.c" +#include "lib-header/gdt.h" #include "lib-header/framebuffer.h" -// #include "kernel_loader.s" #include "lib-header/kernel_loader.h" - +void write_splash_screen(); void kernel_setup(void) { uint32_t a; uint32_t volatile b = 0x0000BABE; @@ -17,10 +16,12 @@ void kernel_setup(void) { framebuffer_write(3, 9, 'a', 0, 0xF); framebuffer_write(3, 10, 'i', 0, 0xF); framebuffer_write(3, 11, '!', 0, 0xF); + write_splash_screen(); framebuffer_set_cursor(3, 9); while (TRUE); while (TRUE) b += 1; } + void write_splash_screen() { framebuffer_write(10, 30, 'B', 2, 0); framebuffer_write(10, 31, 'R', 2, 0); From ae81db191118eb7da505e05526105cf3450a4352 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 11:42:25 +0700 Subject: [PATCH 009/176] fix: linker done --- makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makefile b/makefile index 7155f3d..ef7a764 100644 --- a/makefile +++ b/makefile @@ -30,6 +30,8 @@ kernel: $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o # TODO: Compile C file with CFLAGS @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o + @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o + @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o From 1cdbbe00a93b69cd087fba87db1a3d74c3f812fa Mon Sep 17 00:00:00 2001 From: christodharma <13521009@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 12:59:01 +0700 Subject: [PATCH 010/176] splash screen in ascii (experiment) --- src/kernel.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index 4a5bd52..10fc610 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -32,4 +32,18 @@ void write_splash_screen() { framebuffer_write(10, 37, '4', 2, 0); framebuffer_write(10, 38, '2', 2, 0); framebuffer_write(10, 39, '0', 2, 0); -} \ No newline at end of file +} +// void write_splash_screen() { +// framebuffer_write(10, 0, "BBBBB RRRRRR OOOOOO TTTTTTTT HH HH EEEEEEE RRRRRR ", 2, 0); +// framebuffer_write(11, 0, "BB BB RR RR OO OO TT HH HH EE RR RR ", 2, 0); +// framebuffer_write(12, 0, "BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR ", 2, 0); +// framebuffer_write(13, 0, "BB BB RR RR OO OO TT HH HH EE RR RR ", 2, 0); +// framebuffer_write(14, 0, "BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR", 2, 0); +// framebuffer_write(15, 0, " 44 44 22222222222 0000000 ", 2, 0); +// framebuffer_write(16, 0, " 44 44 22 22 00 00 ", 2, 0); +// framebuffer_write(17, 0, " 44 44 22 22 00 00 ", 2, 0); +// framebuffer_write(18, 0, " 44 44 22 00 00 ", 2, 0); +// framebuffer_write(19, 0, " 44444444444 22222222222 00 00 ", 2, 0); +// framebuffer_write(20, 0, " 44 22 00 00 ", 2, 0); +// framebuffer_write(21, 0, " 44 22222222222 0000000 ", 2, 0); +// } \ No newline at end of file From 98f2528455bb50aa64b51a633b51987e8b128907 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 13:07:49 +0700 Subject: [PATCH 011/176] check --- src/kernel.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index a06bd9a..cd1b703 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -16,7 +16,7 @@ void kernel_setup(void) { framebuffer_write(3, 9, 'a', 0, 0xF); framebuffer_write(3, 10, 'i', 0, 0xF); framebuffer_write(3, 11, '!', 0, 0xF); - write_splash_screen(); + write_splash_screen3(); framebuffer_set_cursor(3, 9); while (TRUE); while (TRUE) b += 1; @@ -47,4 +47,30 @@ void write_splash_screen() { // framebuffer_write(19, 0, " 44444444444 22222222222 00 00 ", 2, 0); // framebuffer_write(20, 0, " 44 22 00 00 ", 2, 0); // framebuffer_write(21, 0, " 44 22222222222 0000000 ", 2, 0); -// } \ No newline at end of file +// } + +void write_splash_screen3() { + char splash_screen[] = "BBBBB RRRRRR OOOOOO TTTTTTTT HH HH EEEEEEE RRRRRR \n" + "BB BB RR RR OO OO TT HH HH EE RR RR \n" + "BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR \n" + "BB BB RR RR OO OO TT HH HH EE RR RR \n" + "BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR\n" + " 44 44 22222222222 0000000 \n" + " 44 44 22 22 00 00 \n" + " 44 44 22 22 00 00 \n" + " 44 44 22 00 00 \n" + " 44444444444 22222222222 00 00 \n" + " 44 22 00 00 \n" + " 44 22222222222 0000000 \n"; + + int row = 10, col = 30; + for (int i = 0; i < strlen(splash_screen); i++) { + if (splash_screen[i] == '\n') { + row++; + col = 30; + } else { + framebuffer_write(row, col, splash_screen[i], 2, 0); + col++; + } + } +} From 6f352d227b465ad46b677fbe13a43758d858dadf Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 13:26:23 +0700 Subject: [PATCH 012/176] feat: splashh --- src/kernel.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index cd1b703..d8e9108 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -5,17 +5,18 @@ #include "lib-header/framebuffer.h" #include "lib-header/kernel_loader.h" -void write_splash_screen(); +void write_splash_screen3(); void kernel_setup(void) { uint32_t a; uint32_t volatile b = 0x0000BABE; __asm__("mov $0xCAFE0000, %0" : "=r"(a)); enter_protected_mode(&_gdt_gdtr); - framebuffer_clear(); + framebuffer_write(3, 8, 'H', 0, 0xF); framebuffer_write(3, 9, 'a', 0, 0xF); framebuffer_write(3, 10, 'i', 0, 0xF); framebuffer_write(3, 11, '!', 0, 0xF); + framebuffer_clear(); write_splash_screen3(); framebuffer_set_cursor(3, 9); while (TRUE); @@ -55,6 +56,7 @@ void write_splash_screen3() { "BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR \n" "BB BB RR RR OO OO TT HH HH EE RR RR \n" "BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR\n" + " \n" " 44 44 22222222222 0000000 \n" " 44 44 22 22 00 00 \n" " 44 44 22 22 00 00 \n" @@ -63,13 +65,20 @@ void write_splash_screen3() { " 44 22 00 00 \n" " 44 22222222222 0000000 \n"; - int row = 10, col = 30; - for (int i = 0; i < strlen(splash_screen); i++) { + int row = 5, col = 5; + for (int i = 0; i < 69*13; i++) { if (splash_screen[i] == '\n') { row++; - col = 30; + col = 5; } else { - framebuffer_write(row, col, splash_screen[i], 2, 0); + if (splash_screen[i] == '4') + framebuffer_write(row, col, splash_screen[i], 0x0c, 0); + else if (splash_screen[i] == '2') + framebuffer_write(row, col, splash_screen[i], 0x0a, 0); + else if (splash_screen[i] == '0') + framebuffer_write(row, col, splash_screen[i], 0x09, 0); + else + framebuffer_write(row, col, splash_screen[i], 0x0b, 0); col++; } } From a6f42c8b1fec44c6429ce1240d6e3ea90edb5dee Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 1 Mar 2023 13:43:45 +0700 Subject: [PATCH 013/176] feat: border to splash --- src/kernel.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index d8e9108..26be83d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -51,25 +51,31 @@ void write_splash_screen() { // } void write_splash_screen3() { - char splash_screen[] = "BBBBB RRRRRR OOOOOO TTTTTTTT HH HH EEEEEEE RRRRRR \n" - "BB BB RR RR OO OO TT HH HH EE RR RR \n" - "BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR \n" - "BB BB RR RR OO OO TT HH HH EE RR RR \n" - "BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR\n" - " \n" - " 44 44 22222222222 0000000 \n" - " 44 44 22 22 00 00 \n" - " 44 44 22 22 00 00 \n" - " 44 44 22 00 00 \n" - " 44444444444 22222222222 00 00 \n" - " 44 22 00 00 \n" - " 44 22222222222 0000000 \n"; + char splash_screen[] = "===============================================================================\n" + "|| ||\n" + "|| ||\n" + "|| BBBBB RRRRRR OOOOOO TTTTTTTT HH HH EEEEEEE RRRRRR ||\n" + "|| BB BB RR RR OO OO TT HH HH EE RR RR ||\n" + "|| BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR ||\n" + "|| BB BB RR RR OO OO TT HH HH EE RR RR ||\n" + "|| BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR ||\n" + "|| ||\n" + "|| 44 44 22222222222 0000000 ||\n" + "|| 44 44 22 22 00 00 ||\n" + "|| 44 44 22 22 00 00 ||\n" + "|| 44 44 22 00 00 ||\n" + "|| 44444444444 22222222222 00 00 ||\n" + "|| 44 22 00 00 ||\n" + "|| 44 22222222222 0000000 ||\n" + "|| ||\n" + "|| ||\n" + "===============================================================================\n"; - int row = 5, col = 5; - for (int i = 0; i < 69*13; i++) { + int row = 2, col = 0; + for (int i = 0; i < 80*19; i++) { if (splash_screen[i] == '\n') { row++; - col = 5; + col = 0; } else { if (splash_screen[i] == '4') framebuffer_write(row, col, splash_screen[i], 0x0c, 0); From 3de40e7fe7301fa6ce8f936f5b0a605c703a006d Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 2 Mar 2023 17:43:08 +0700 Subject: [PATCH 014/176] Final mls1 --- src/kernel.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 26be83d..56d1a38 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,44 +11,13 @@ void kernel_setup(void) { uint32_t volatile b = 0x0000BABE; __asm__("mov $0xCAFE0000, %0" : "=r"(a)); enter_protected_mode(&_gdt_gdtr); - - framebuffer_write(3, 8, 'H', 0, 0xF); - framebuffer_write(3, 9, 'a', 0, 0xF); - framebuffer_write(3, 10, 'i', 0, 0xF); - framebuffer_write(3, 11, '!', 0, 0xF); framebuffer_clear(); write_splash_screen3(); - framebuffer_set_cursor(3, 9); + framebuffer_set_cursor(9, 40); while (TRUE); while (TRUE) b += 1; } -void write_splash_screen() { - framebuffer_write(10, 30, 'B', 2, 0); - framebuffer_write(10, 31, 'R', 2, 0); - framebuffer_write(10, 32, 'O', 2, 0); - framebuffer_write(10, 33, 'T', 2, 0); - framebuffer_write(10, 34, 'H', 2, 0); - framebuffer_write(10, 35, 'E', 2, 0); - framebuffer_write(10, 36, 'R', 2, 0); - framebuffer_write(10, 37, '4', 2, 0); - framebuffer_write(10, 38, '2', 2, 0); - framebuffer_write(10, 39, '0', 2, 0); -} -// void write_splash_screen() { -// framebuffer_write(10, 0, "BBBBB RRRRRR OOOOOO TTTTTTTT HH HH EEEEEEE RRRRRR ", 2, 0); -// framebuffer_write(11, 0, "BB BB RR RR OO OO TT HH HH EE RR RR ", 2, 0); -// framebuffer_write(12, 0, "BBBBBB RRRRRR OO OO TT HHHHHHHH EEEEE RRRRRR ", 2, 0); -// framebuffer_write(13, 0, "BB BB RR RR OO OO TT HH HH EE RR RR ", 2, 0); -// framebuffer_write(14, 0, "BBBBB RR RR OOOOOO TT HH HH EEEEEEE RR RR", 2, 0); -// framebuffer_write(15, 0, " 44 44 22222222222 0000000 ", 2, 0); -// framebuffer_write(16, 0, " 44 44 22 22 00 00 ", 2, 0); -// framebuffer_write(17, 0, " 44 44 22 22 00 00 ", 2, 0); -// framebuffer_write(18, 0, " 44 44 22 00 00 ", 2, 0); -// framebuffer_write(19, 0, " 44444444444 22222222222 00 00 ", 2, 0); -// framebuffer_write(20, 0, " 44 22 00 00 ", 2, 0); -// framebuffer_write(21, 0, " 44 22222222222 0000000 ", 2, 0); -// } void write_splash_screen3() { char splash_screen[] = "===============================================================================\n" From 9a9a5007ba29fff76d25cdfb9672dbea9b17a24c Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Fri, 17 Mar 2023 22:16:08 +0700 Subject: [PATCH 015/176] feat: the setup for milestone 2 --- src/fat32.c | 13 ++ src/idt.c | 27 ++++ src/interrupt.c | 50 ++++++++ src/intsetup.s | 127 +++++++++++++++++++ src/kernel.c | 11 +- src/keyboard.c | 24 ++++ src/lib-header/disk.h | 52 ++++++++ src/lib-header/fat32.h | 249 +++++++++++++++++++++++++++++++++++++ src/lib-header/idt.h | 80 ++++++++++++ src/lib-header/interrupt.h | 125 +++++++++++++++++++ src/lib-header/keyboard.h | 74 +++++++++++ 11 files changed, 826 insertions(+), 6 deletions(-) create mode 100644 src/fat32.c create mode 100644 src/idt.c create mode 100644 src/interrupt.c create mode 100644 src/intsetup.s create mode 100644 src/keyboard.c create mode 100644 src/lib-header/disk.h create mode 100644 src/lib-header/fat32.h create mode 100644 src/lib-header/idt.h create mode 100644 src/lib-header/interrupt.h create mode 100644 src/lib-header/keyboard.h diff --git a/src/fat32.c b/src/fat32.c new file mode 100644 index 0000000..c481fcf --- /dev/null +++ b/src/fat32.c @@ -0,0 +1,13 @@ +#include "lib-header/stdtype.h" +#include "lib-header/fat32.h" +#include "lib-header/stdmem.h" + +const uint8_t fs_signature[BLOCK_SIZE] = { + 'C', 'o', 'u', 'r', 's', 'e', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + 'D', 'e', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'b', 'y', ' ', ' ', ' ', ' ', ' ', + 'L', 'a', 'b', ' ', 'S', 'i', 's', 't', 'e', 'r', ' ', 'I', 'T', 'B', ' ', ' ', + 'M', 'a', 'd', 'e', ' ', 'w', 'i', 't', 'h', ' ', '<', '3', ' ', ' ', ' ', ' ', + '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '2', '0', '2', '3', '\n', + [BLOCK_SIZE-2] = 'O', + [BLOCK_SIZE-1] = 'k', +}; \ No newline at end of file diff --git a/src/idt.c b/src/idt.c new file mode 100644 index 0000000..9b8b11a --- /dev/null +++ b/src/idt.c @@ -0,0 +1,27 @@ +#include "lib-header/idt.h" + +void initialize_idt(void) { + /* TODO : + * Iterate all isr_stub_table, + * Set all IDT entry with set_interrupt_gate() + * with following values: + * Vector: i + * Handler Address: isr_stub_table[i] + * Segment: GDT_KERNEL_CODE_SEGMENT_SELECTOR + * Privilege: 0 + */ + __asm__ volatile("lidt %0" : : "m"(_idt_idtr)); + __asm__ volatile("sti"); +} + +void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege) { + struct IDTGate *idt_int_gate = &interrupt_descriptor_table.table[int_vector]; + // TODO : Set handler offset, privilege & segment + + // Target system 32-bit and flag this as valid interrupt gate + idt_int_gate->_r_bit_1 = INTERRUPT_GATE_R_BIT_1; + idt_int_gate->_r_bit_2 = INTERRUPT_GATE_R_BIT_2; + idt_int_gate->_r_bit_3 = INTERRUPT_GATE_R_BIT_3; + idt_int_gate->gate_32 = 1; + idt_int_gate->valid_bit = 1; +} diff --git a/src/interrupt.c b/src/interrupt.c new file mode 100644 index 0000000..77700c9 --- /dev/null +++ b/src/interrupt.c @@ -0,0 +1,50 @@ +void io_wait(void) { + out(0x80, 0); +} + +void pic_ack(uint8_t irq) { + if (irq >= 8) + out(PIC2_COMMAND, PIC_ACK); + out(PIC1_COMMAND, PIC_ACK); +} + +void pic_remap(void) { + uint8_t a1, a2; + + // Save masks + a1 = in(PIC1_DATA); + a2 = in(PIC2_DATA); + + // Starts the initialization sequence in cascade mode + out(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + out(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + out(PIC1_DATA, PIC1_OFFSET); // ICW2: Master PIC vector offset + io_wait(); + out(PIC2_DATA, PIC2_OFFSET); // ICW2: Slave PIC vector offset + io_wait(); + out(PIC1_DATA, 0b0100); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) + io_wait(); + out(PIC2_DATA, 0b0010); // ICW3: tell Slave PIC its cascade identity (0000 0010) + io_wait(); + + out(PIC1_DATA, ICW4_8086); + io_wait(); + out(PIC2_DATA, ICW4_8086); + io_wait(); + + // Restore masks + out(PIC1_DATA, a1); + out(PIC2_DATA, a2); +} + +void main_interrupt_handler( + __attribute__((unused)) struct CPURegister cpu, + uint32_t int_number, + __attribute__((unused)) struct InterruptStack info +) { + switch (int_number) { + + } +} diff --git a/src/intsetup.s b/src/intsetup.s new file mode 100644 index 0000000..ba9eae6 --- /dev/null +++ b/src/intsetup.s @@ -0,0 +1,127 @@ +extern main_interrupt_handler +global isr_stub_table + +; Generic handler section for interrupt +call_generic_handler: + ; Before interrupt_handler_n is called (caller of this generic handler section), + ; stack will have these value that pushed automatically by CPU + ; [esp + 12] eflags + ; [esp + 8 ] cs + ; [esp + 4 ] eip + ; [esp + 0 ] error code + + ; CPURegister + push esp + push ebp + push edx + push ecx + push ebx + push eax + + + ; call the C function + call main_interrupt_handler + + ; restore the registers + pop eax + pop ebx + pop ecx + pop edx + pop ebp + pop esp + + ; restore the esp (interrupt number & error code) + add esp, 8 + + ; return to the code that got interrupted + ; at this point, stack should be structured like this + ; [esp], [esp+4], [esp+8] + ; eip, cs, eflags + ; improper value will cause invalid return address & register + sti + iret + + + +; Macro for creating interrupt handler that only push interrupt number +%macro no_error_code_interrupt_handler 1 +interrupt_handler_%1: + push dword 0 ; push 0 as error code + push dword %1 ; push the interrupt number + jmp call_generic_handler ; jump to the common handler +%endmacro + +%macro error_code_interrupt_handler 1 +interrupt_handler_%1: + push dword %1 + jmp call_generic_handler +%endmacro + +; CPU exception handlers +no_error_code_interrupt_handler 0 ; 0x0 - Division by zero +no_error_code_interrupt_handler 1 ; 0x1 - Debug Exception +no_error_code_interrupt_handler 2 ; 0x2 - NMI, Non-Maskable Interrupt +no_error_code_interrupt_handler 3 ; 0x3 - Breakpoint Exception +no_error_code_interrupt_handler 4 ; 0x4 - INTO Overflow +no_error_code_interrupt_handler 5 ; 0x5 - Out of Bounds +no_error_code_interrupt_handler 6 ; 0x6 - Invalid Opcode +no_error_code_interrupt_handler 7 ; 0x7 - Device Not Available +error_code_interrupt_handler 8 ; 0x8 - Double Fault +no_error_code_interrupt_handler 9 ; 0x9 - Deprecated +error_code_interrupt_handler 10 ; 0xA - Invalid TSS +error_code_interrupt_handler 11 ; 0xB - Segment Not Present +error_code_interrupt_handler 12 ; 0xC - Stack-Segment Fault +error_code_interrupt_handler 13 ; 0xD - General Protection Fault +error_code_interrupt_handler 14 ; 0xE - Page Fault +no_error_code_interrupt_handler 15 ; 0xF - Reserved +no_error_code_interrupt_handler 16 ; 0x10 - x87 Floating-Point Exception +error_code_interrupt_handler 17 ; 0x11 - Alignment Check Exception +no_error_code_interrupt_handler 18 ; 0x12 - Machine Check Exception +no_error_code_interrupt_handler 19 ; 0x13 - SIMD Floating-Point Exception +no_error_code_interrupt_handler 20 ; 0x14 - Virtualization Exception +no_error_code_interrupt_handler 21 ; 0x15 - Control Protection Exception +no_error_code_interrupt_handler 22 ; 0x16 - Reserved +no_error_code_interrupt_handler 23 ; 0x17 - Reserved +no_error_code_interrupt_handler 24 ; 0x18 - Reserved +no_error_code_interrupt_handler 25 ; 0x19 - Reserved +no_error_code_interrupt_handler 26 ; 0x1A - Reserved +no_error_code_interrupt_handler 27 ; 0x1B - Reserved +no_error_code_interrupt_handler 28 ; 0x1C - Hypervisor Injection Exception +no_error_code_interrupt_handler 29 ; 0x1D - VMM Communication Exception +error_code_interrupt_handler 30 ; 0x1E - Security Exception +no_error_code_interrupt_handler 31 ; 0x1F - Reserved + +; User defined interrupt handler +; Assuming PIC1 & PIC2 offset is 0x20 and 0x28 +; 32 - 0x20 - IRQ0: Programmable Interval Timer +; 33 - 0x21 - IRQ1: Keyboard +; 34 - 0x22 - IRQ2: PIC Cascade, used internally +; 35 - 0x23 - IRQ3: COM2, if enabled +; 36 - 0x24 - IRQ4: COM1, if enabled +; 37 - 0x25 - IRQ5: LPT2, if enabled +; 38 - 0x26 - IRQ6: Floppy Disk +; 39 - 0x27 - IRQ7: LPT1 + +; 40 - 0x28 - IRQ8: CMOS real-time clock +; 41 - 0x29 - IRQ9: Free +; 42 - 0x2A - IRQ10: Free +; 43 - 0x2B - IRQ11: Free +; 44 - 0x2C - IRQ12: PS2 Mouse +; 45 - 0x2D - IRQ13: Coprocessor +; 46 - 0x2E - IRQ14: Primary ATA Hard Disk +; 47 - 0x2F - IRQ15: Secondary ATA Hard Disk +%assign i 32 +%rep 32 +no_error_code_interrupt_handler i +%assign i i+1 +%endrep + + + +; ISR stub table, useful for reducing code repetition +isr_stub_table: + %assign i 0 + %rep 64 + dd interrupt_handler_%+i + %assign i i+1 + %endrep \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index 56d1a38..5618bb2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,16 +6,15 @@ #include "lib-header/kernel_loader.h" void write_splash_screen3(); + void kernel_setup(void) { - uint32_t a; - uint32_t volatile b = 0x0000BABE; - __asm__("mov $0xCAFE0000, %0" : "=r"(a)); enter_protected_mode(&_gdt_gdtr); + pic_remap(); + initialize_idt(); framebuffer_clear(); - write_splash_screen3(); - framebuffer_set_cursor(9, 40); + framebuffer_set_cursor(0, 0); + __asm__("int $0x4"); while (TRUE); - while (TRUE) b += 1; } diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..7ff5b82 --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,24 @@ +#include "lib-header/keyboard.h" +#include "lib-header/portio.h" +#include "lib-header/framebuffer.h" +#include "lib-header/stdmem.h" + +const char keyboard_scancode_1_to_ascii_map[256] = { + 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/src/lib-header/disk.h b/src/lib-header/disk.h new file mode 100644 index 0000000..7e73d4d --- /dev/null +++ b/src/lib-header/disk.h @@ -0,0 +1,52 @@ +#ifndef _DISK_H +#define _DISK_H + +#include "stdtype.h" + +/* -- ATA PIO status codes -- */ +#define ATA_STATUS_BSY 0x80 +#define ATA_STATUS_RDY 0x40 +#define ATA_STATUS_DRQ 0x08 +#define ATA_STATUS_DF 0x20 +#define ATA_STATUS_ERR 0x01 + +#define BLOCK_SIZE 512 +#define HALF_BLOCK_SIZE (BLOCK_SIZE/2) + + + + + +// Block buffer data type - @param buf Byte buffer with size of BLOCK_SIZE +struct BlockBuffer { + uint8_t buf[BLOCK_SIZE]; +} __attribute__((packed)); + + + + + +/** + * ATA PIO logical block address read blocks. Will blocking until read is completed. + * Note: ATA PIO will use 2-bytes per read/write operation. + * Recommended to use struct BlockBuffer + * + * @param ptr Pointer for storing reading data, this pointer should point to already allocated memory location. + * With allocated size positive integer multiple of BLOCK_SIZE, ex: buf[1024] + * @param logical_block_address Block address to read data from. Use LBA addressing + * @param block_count How many block to read, starting from block logical_block_address to lba-1 + */ +void read_blocks(void *ptr, uint32_t logical_block_address, uint8_t block_count); + +/** + * ATA PIO logical block address write blocks. Will blocking until write is completed. + * Note: ATA PIO will use 2-bytes per read/write operation. + * Recommended to use struct BlockBuffer + * + * @param ptr Pointer to data that to be written into disk. Memory pointed should be positive integer multiple of BLOCK_SIZE + * @param logical_block_address Block address to write data into. Use LBA addressing + * @param block_count How many block to write, starting from block logical_block_address to lba-1 + */ +void write_blocks(const void *ptr, uint32_t logical_block_address, uint8_t block_count); + +#endif \ No newline at end of file diff --git a/src/lib-header/fat32.h b/src/lib-header/fat32.h new file mode 100644 index 0000000..ee445e3 --- /dev/null +++ b/src/lib-header/fat32.h @@ -0,0 +1,249 @@ +#ifndef _FAT32_H +#define _FAT32_H + +#include "disk.h" +#include "stdtype.h" + + +/** + * FAT32 - IF2230 edition - 2023 + * Check "IF2230 - Guidebook - Milestone 2" for more details + * https://docs.google.com/document/d/1IFyxHSYYpKgecHcS0T64oDc4bVElaq8tBcm1_mjjGGM/edit# + */ + + + +/* -- IF2230 File System constants -- */ +#define BOOT_SECTOR 0 +#define CLUSTER_BLOCK_COUNT 4 +#define CLUSTER_SIZE (BLOCK_SIZE*CLUSTER_BLOCK_COUNT) +#define CLUSTER_MAP_SIZE 512 + +/* -- FAT32 FileAllocationTable constants -- */ +// FAT reserved value for cluster 0 and 1 in FileAllocationTable +#define CLUSTER_0_VALUE 0x0FFFFFF0 +#define CLUSTER_1_VALUE 0x0FFFFFFF + +// EOF also double as valid cluster / "this is last valid cluster in the chain" +#define FAT32_FAT_END_OF_FILE 0x0FFFFFFF +#define FAT32_FAT_EMPTY_ENTRY 0x00000000 + +#define FAT_CLUSTER_NUMBER 1 +#define ROOT_CLUSTER_NUMBER 2 + +/* -- FAT32 DirectoryEntry constants -- */ +#define ATTR_SUBDIRECTORY 0b00010000 +#define UATTR_NOT_EMPTY 0b10101010 + + + +// Boot sector signature for this file system "FAT32 - IF2230 edition" +extern const uint8_t fs_signature[BLOCK_SIZE]; + +// Cluster buffer data type - @param buf Byte buffer with size of CLUSTER_SIZE +struct ClusterBuffer { + uint8_t buf[CLUSTER_SIZE]; +} __attribute__((packed)); + + + + + +/* -- FAT32 Data Structures -- */ + +/** + * FAT32 FileAllocationTable, for more information about this, check guidebook + * + * @param cluster_map Containing cluster map of FAT32 + */ +struct FAT32FileAllocationTable { + uint32_t cluster_map[CLUSTER_MAP_SIZE]; +} __attribute__((packed)); + +/** + * FAT32 standard 8.3 format - 32 bytes DirectoryEntry, Some detail can be found at: + * https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Directory_entry, and click show table. + * + * @param name Entry name + * @param ext File extension + * @param attribute Will be used exclusively for subdirectory flag / determining this entry is file or folder + * @param user_attribute If this attribute equal with UATTR_NOT_EMPTY then entry is not empty + * + * @param undelete Unused / optional + * @param create_time Unused / optional + * @param create_date Unused / optional + * @param access_time Unused / optional + * @param cluster_high Upper 16-bit of cluster number + * + * @param modified_time Unused / optional + * @param modified_date Unused / optional + * @param cluster_low Lower 16-bit of cluster number + * @param filesize Filesize of this file, if this is directory / folder, filesize is 0 + */ +struct FAT32DirectoryEntry { + char name[8]; + char ext[3]; + uint8_t attribute; + uint8_t user_attribute; + + bool undelete; + uint16_t create_time; + uint16_t create_date; + uint16_t access_date; + uint16_t cluster_high; + + uint16_t modified_time; + uint16_t modified_date; + uint16_t cluster_low; + uint32_t filesize; +} __attribute__((packed)); + +// FAT32 DirectoryTable, containing directory entry table - @param table Table of DirectoryEntry that span within 1 cluster +struct FAT32DirectoryTable { + struct FAT32DirectoryEntry table[CLUSTER_SIZE / sizeof(struct FAT32DirectoryEntry)]; +} __attribute__((packed)); + + + + + +/* -- FAT32 Driver -- */ + +/** + * FAT32DriverState - Contain all driver states + * + * @param fat_table FAT of the system, will be loaded during initialize_filesystem_fat32() + * @param dir_table_buf Buffer for directory table + * @param cluster_buf Buffer for cluster + */ +struct FAT32DriverState { + struct FAT32FileAllocationTable fat_table; + struct FAT32DirectoryTable dir_table_buf; + struct ClusterBuffer cluster_buf; +} __attribute__((packed)); + +/** + * FAT32DriverRequest - Request for Driver CRUD operation + * + * @param buf Pointer pointing to buffer + * @param name Name for directory entry + * @param ext Extension for file + * @param parent_cluster_number Parent directory cluster number, for updating metadata + * @param buffer_size Buffer size, CRUD operation will have different behaviour with this attribute + */ +struct FAT32DriverRequest { + void *buf; + char name[8]; + char ext[3]; + uint32_t parent_cluster_number; + uint32_t buffer_size; +} __attribute__((packed)); + + + + + +/* -- Driver Interfaces -- */ + +/** + * Convert cluster number to logical block address + * + * @param cluster Cluster number to convert + * @return uint32_t Logical Block Address + */ +uint32_t cluster_to_lba(uint32_t cluster); + +/** + * Initialize DirectoryTable value with parent DirectoryEntry and directory name + * + * @param dir_table Pointer to directory table + * @param name 8-byte char for directory name + * @param parent_dir_cluster Parent directory cluster number + */ +void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster); + +/** + * Checking whether filesystem signature is missing or not in boot sector + * + * @return True if memcmp(boot_sector, fs_signature) returning inequality + */ +bool is_empty_storage(void); + +/** + * Create new FAT32 file system. Will write fs_signature into boot sector and + * proper FileAllocationTable (contain CLUSTER_0_VALUE, CLUSTER_1_VALUE, + * and initialized root directory) into cluster number 1 + */ +void create_fat32(void); + +/** + * Initialize file system driver state, if is_empty_storage() then create_fat32() + * Else, read and cache entire FileAllocationTable (located at cluster number 1) into driver state + */ +void initialize_filesystem_fat32(void); + +/** + * Write cluster operation, wrapper for write_blocks(). + * Recommended to use struct ClusterBuffer + * + * @param ptr Pointer to source data + * @param cluster_number Cluster number to write + * @param cluster_count Cluster count to write, due limitation of write_blocks block_count 255 => max cluster_count = 63 + */ +void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count); + +/** + * Read cluster operation, wrapper for read_blocks(). + * Recommended to use struct ClusterBuffer + * + * @param ptr Pointer to buffer for reading + * @param cluster_number Cluster number to read + * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 + */ +void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); + + + + + +/* -- CRUD Operation -- */ + +/** + * FAT32 Folder / Directory read + * + * @param request buf point to struct FAT32DirectoryTable, + * name is directory name, + * ext is unused, + * parent_cluster_number is target directory table to read, + * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) + * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown + */ +int8_t read_directory(struct FAT32DriverRequest request); + + +/** + * FAT32 read, read a file from file system. + * + * @param request All attribute will be used for read, buffer_size will limit reading count + * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown + */ +int8_t read(struct FAT32DriverRequest request); + +/** + * FAT32 write, write a file or folder to file system. + * + * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory + * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown + */ +int8_t write(struct FAT32DriverRequest request); + + +/** + * FAT32 delete, delete a file or empty directory (only 1 DirectoryEntry) in file system. + * + * @param request buf and buffer_size is unused + * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown + */ +int8_t delete(struct FAT32DriverRequest request); + +#endif \ No newline at end of file diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h new file mode 100644 index 0000000..90c91e5 --- /dev/null +++ b/src/lib-header/idt.h @@ -0,0 +1,80 @@ +#ifndef _IDT_H +#define _IDT_H + +#include "stdtype.h" + +// IDT hard limit, see Intel x86 manual 3a - 6.10 Interrupt Descriptor Table +#define IDT_MAX_ENTRY_COUNT 256 +#define ISR_STUB_TABLE_LIMIT 64 +#define INTERRUPT_GATE_R_BIT_1 0b000 +#define INTERRUPT_GATE_R_BIT_2 0b110 +#define INTERRUPT_GATE_R_BIT_3 0b0 + +// Some GDT Constant +#define GDT_KERNEL_CODE_SEGMENT_SELECTOR 0x8 +#define GDT_KERNEL_DATA_SEGMENT_SELECTOR 0x10 + + +// Interrupt Handler / ISR stub for reducing code duplication, this array can be iterated in initialize_idt() +extern void *isr_stub_table[ISR_STUB_TABLE_LIMIT]; + +extern struct IDTR _idt_idtr; + +/** + * IDTGate, IDT entry that point into interrupt handler + * Struct defined exactly in Intel x86 Vol 3a - Figure 6-2. IDT Gate Descriptors + * + * @param offset_low Lower 16-bit offset + * @param segment Memory segment + * @param _reserved Reserved bit, bit length: 5 + * @param _r_bit_1 Reserved for idtgate type, bit length: 3 + * @param _r_bit_2 Reserved for idtgate type, bit length: 3 + * @param gate_32 Is this gate size 32-bit? If not then its 16-bit gate + * @param _r_bit_3 Reserved for idtgate type, bit length: 1 + * ... + */ +struct IDTGate { + // First 32-bit (Bit 0 to 31) + uint16_t offset_low; + + // TODO : Implement +} __attribute__((packed)); + +/** + * Interrupt Descriptor Table, containing lists of IDTGate. + * One IDT already defined in idt.c + * + * ... + */ +// TODO : Implement +// ... + +/** + * IDTR, carrying information where's the IDT located and size. + * Global kernel variable defined at idt.c. + * + * ... + */ +// TODO : Implement +// ... + + + +/** + * Set IDTGate with proper interrupt handler values. + * Will directly edit global IDT variable and set values properly + * + * @param int_vector Interrupt vector to handle + * @param handler_address Interrupt handler address + * @param gdt_seg_selector GDT segment selector, for kernel use GDT_KERNEL_CODE_SEGMENT_SELECTOR + * @param privilege Descriptor privilege level + */ +void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege); + + +/** + * Set IDT with proper values and load with lidt + */ +void initialize_idt(void); + +#endif \ No newline at end of file diff --git a/src/lib-header/interrupt.h b/src/lib-header/interrupt.h new file mode 100644 index 0000000..6a84bbc --- /dev/null +++ b/src/lib-header/interrupt.h @@ -0,0 +1,125 @@ +#ifndef _INTERRUPT_H +#define _INTERRUPT_H + +#include "stdtype.h" + +/* -- PIC constants -- */ + +// PIC interrupt offset +#define PIC1_OFFSET 0x20 +#define PIC2_OFFSET 0x28 + +// PIC ports +#define PIC1 0x20 +#define PIC2 0xA0 +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1 + 1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2 + 1) + +// PIC ACK & mask constant +#define PIC_ACK 0x20 +#define PIC_DISABLE_ALL_MASK 0xFF + +// PIC remap constants +#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ + +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFNM 0x10 /* Special fully nested (not) */ + + +/* -- PICs IRQ list -- */ + +// PIC Master +#define IRQ_TIMER 0 +#define IRQ_KEYBOARD 1 +#define IRQ_CASCADE 2 +#define IRQ_COM2 3 +#define IRQ_COM1 4 +#define IRQ_LPT2 5 +#define IRQ_FLOPPY_DISK 6 +#define IRQ_LPT1_SPUR 7 + +// PIC Slave +#define IRQ_CMOS 8 +#define IRQ_PERIPHERAL_1 9 +#define IRQ_PERIPHERAL_2 10 +#define IRQ_PERIPHERAL_3 11 +#define IRQ_MOUSE 12 +#define IRQ_FPU 13 +#define IRQ_PRIMARY_ATA 14 +#define IRQ_SECOND_ATA 15 + + +/** + * CPURegister, store CPU registers that can be used for interrupt handler / ISRs + * + * @param gp_register CPU general purpose register (a, b, c, d) + * @param stack_register CPU stack register (bp, sp) + */ +struct CPURegister { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t ebp; + uint32_t esp; +} __attribute__((packed)); + +/** + * InterruptInfo, data pushed by CPU when interrupt / exception is raised. + * Refer to Intel x86 Vol 3a: Figure 6-4 Stack usage on transfer to Interrupt. + * + * Note, when returning from interrupt handler with iret, esp must be pointing to eip pushed before + * or in other words, CPURegister, int_number and error_code should be pop-ed from stack. + * + * @param error_code Error code that pushed with the exception + * @param eip Instruction pointer where interrupt is raised + * @param cs Code segment selector where interrupt is raised + * @param eflags CPU eflags register when interrupt is raised + */ +struct InterruptStack { + uint32_t error_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; +} __attribute__((packed)); + + + + + +// Activate PIC mask for keyboard only +void activate_keyboard_interrupt(void); + +// I/O port wait, around 1-4 microsecond, for I/O synchronization purpose +void io_wait(void); + +// Send ACK to PIC - @param irq Interrupt request number destination, note: this function already include PIC1_OFFSET +void pic_ack(uint8_t irq); + +// Shift PIC interrupt number to PIC1_OFFSET and PIC2_OFFSET (master and slave) +void pic_remap(void); + +/** + * Main interrupt handler when any interrupt / exception is raised. + * Do not call this function normally. + * + * This function will be called first if any INT 0x00 - 0x40 is raised, + * and will call proper ISR for respective interrupt / exception. + * + * Again, this function is not for normal function call, all parameter will be automatically set when interrupt is called. + * @param cpu CPU register when interrupt is raised + * @param int_number Interrupt number that trigger interrupt exception + * @param info Information about interrupt that pushed automatically by CPU + */ +void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info); + +#endif \ No newline at end of file diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h new file mode 100644 index 0000000..f29c4a8 --- /dev/null +++ b/src/lib-header/keyboard.h @@ -0,0 +1,74 @@ +#ifndef _USER_ISR_H +#define _USER_ISR_H + +#include "interrupt.h" +#include "stdtype.h" + +#define EXT_SCANCODE_UP 0x48 +#define EXT_SCANCODE_DOWN 0x50 +#define EXT_SCANCODE_LEFT 0x4B +#define EXT_SCANCODE_RIGHT 0x4D + +#define KEYBOARD_DATA_PORT 0x60 +#define EXTENDED_SCANCODE_BYTE 0xE0 + +#define KEYBOARD_BUFFER_SIZE 256 + +/** + * keyboard_scancode_1_to_ascii_map[256], Convert scancode values that correspond to ASCII printables + * How to use this array: ascii_char = k[scancode] + * + * By default, QEMU using scancode set 1 (from empirical testing) + */ +extern const char keyboard_scancode_1_to_ascii_map[256]; + +/** + * KeyboardDriverState - Contain all driver states + * + * @param read_extended_mode Optional, can be used for signaling next read is extended scancode (ex. arrow keys) + * @param keyboard_input_on Indicate whether keyboard ISR is activated or not + * @param buffer_index Used for keyboard_buffer index + * @param keyboard_buffer Storing keyboard input values in ASCII + */ +struct KeyboardDriverState { + bool read_extended_mode; + bool keyboard_input_on; + uint8_t buffer_index; + char keyboard_buffer[KEYBOARD_BUFFER_SIZE]; +} __attribute((packed)); + + + + + +/* -- Driver Interfaces -- */ + +// Activate keyboard ISR / start listen keyboard & save to buffer +void keyboard_state_activate(void); + +// Deactivate keyboard ISR / stop listening keyboard interrupt +void keyboard_state_deactivate(void); + +// Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE +void get_keyboard_buffer(char *buf); + +// Check whether keyboard ISR is active or not - @return Equal with keyboard_input_on value +bool is_keyboard_blocking(void); + + +/* -- Keyboard Interrupt Service Routine -- */ + +/** + * Handling keyboard interrupt & process scancodes into ASCII character. + * Will start listen and process keyboard scancode if keyboard_input_on. + * + * Will only print printable character into framebuffer. + * Stop processing when enter key (line feed) is pressed. + * + * Note that, with keyboard interrupt & ISR, keyboard reading is non-blocking. + * This can be made into blocking input with `while (is_keyboard_blocking());` + * after calling `keyboard_state_activate();` + */ +void keyboard_isr(void); + +#endif \ No newline at end of file From b8424b816bbd365299995aa3c9e41c3e9ef4c16c Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 13:03:16 +0700 Subject: [PATCH 016/176] feat: test --- src/idt.c | 18 ++++++++++++++++++ src/interrupt.c | 2 ++ src/lib-header/idt.h | 14 ++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/idt.c b/src/idt.c index 9b8b11a..b968e17 100644 --- a/src/idt.c +++ b/src/idt.c @@ -1,7 +1,11 @@ #include "lib-header/idt.h" +extern struct IDT idt; +extern struct IDTR idtr; + void initialize_idt(void) { /* TODO : + * Iterate all isr_stub_table, * Set all IDT entry with set_interrupt_gate() * with following values: @@ -10,6 +14,17 @@ void initialize_idt(void) { * Segment: GDT_KERNEL_CODE_SEGMENT_SELECTOR * Privilege: 0 */ + // for (int i = 0; i < ISR_STUB_TABLE_LIMIT; i++) { + // isr_stub_table[i] = NULL; + // } + + for (int i = 0; i < ISR_STUB_TABLE_LIMIT; i++) { + set_interrupt_gate(i, isr_stub_table[i], GDT_KERNEL_CODE_SEGMENT_SELECTOR, 0); + } + + idtr.limit = sizeof(idt) - 1; + idtr.base = (uint32_t)&idt; + __asm__ volatile("lidt %0" : : "m"(_idt_idtr)); __asm__ volatile("sti"); } @@ -17,6 +32,9 @@ void initialize_idt(void) { void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege) { struct IDTGate *idt_int_gate = &interrupt_descriptor_table.table[int_vector]; // TODO : Set handler offset, privilege & segment + idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; + idt_int_gate->segment = gdt_seg_selector; + idt_int_gate->privilege = privilege; // Target system 32-bit and flag this as valid interrupt gate idt_int_gate->_r_bit_1 = INTERRUPT_GATE_R_BIT_1; diff --git a/src/interrupt.c b/src/interrupt.c index 77700c9..78ae795 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -1,3 +1,5 @@ +#include "lib-header/interrupt.h" + void io_wait(void) { out(0x80, 0); } diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index 90c91e5..e3d6ce8 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -38,6 +38,13 @@ struct IDTGate { uint16_t offset_low; // TODO : Implement + uint16_t segment; + uint8_t _reserved; + uint8_t _r_bit_1 : 3; + uint8_t _r_bit_2 : 3; + uint8_t gate_32 : 1; + uint8_t _r_bit_3 : 1; + } __attribute__((packed)); /** @@ -47,6 +54,9 @@ struct IDTGate { * ... */ // TODO : Implement +struct IDT { + struct IDTGate entries[IDT_MAX_ENTRY_COUNT]; +} __attribute__((packed)); // ... /** @@ -56,6 +66,10 @@ struct IDTGate { * ... */ // TODO : Implement +struct IDTR { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); // ... From d7515857c8582638e3757ec0b1bad90a51047ac2 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 13:24:35 +0700 Subject: [PATCH 017/176] feat: linker --- makefile | 2 ++ src/kernel.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/makefile b/makefile index ef7a764..e7fced1 100644 --- a/makefile +++ b/makefile @@ -32,6 +32,8 @@ kernel: @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o + @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o + @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o diff --git a/src/kernel.c b/src/kernel.c index 5618bb2..7b0cc8d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -4,6 +4,8 @@ #include "lib-header/gdt.h" #include "lib-header/framebuffer.h" #include "lib-header/kernel_loader.h" +#include "lib-header/interrupt.h" +#include "lib-header/idt.h" void write_splash_screen3(); From 98eccd8183bbd663f26dc2db21cc20743ffe5522 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 13:27:50 +0700 Subject: [PATCH 018/176] feat: linker idt and interrupt --- makefile | 2 ++ src/kernel.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/makefile b/makefile index ef7a764..9122301 100644 --- a/makefile +++ b/makefile @@ -32,6 +32,8 @@ kernel: @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o + @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o + @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o diff --git a/src/kernel.c b/src/kernel.c index 5618bb2..7b0cc8d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -4,6 +4,8 @@ #include "lib-header/gdt.h" #include "lib-header/framebuffer.h" #include "lib-header/kernel_loader.h" +#include "lib-header/interrupt.h" +#include "lib-header/idt.h" void write_splash_screen3(); From 88d4dd8a63c36dc2fcf44a133b7b48b1e4dc11b2 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 13:40:45 +0700 Subject: [PATCH 019/176] not fix: idt thing --- makefile | 2 +- src/idt.c | 14 +------------- src/kernel.c | 2 +- src/lib-header/idt.h | 15 +++++++-------- 4 files changed, 10 insertions(+), 23 deletions(-) diff --git a/makefile b/makefile index e7fced1..9122301 100644 --- a/makefile +++ b/makefile @@ -32,8 +32,8 @@ kernel: @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o - @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o + @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o diff --git a/src/idt.c b/src/idt.c index b968e17..80a33e5 100644 --- a/src/idt.c +++ b/src/idt.c @@ -4,8 +4,7 @@ extern struct IDT idt; extern struct IDTR idtr; void initialize_idt(void) { - /* TODO : - + /* TODO : * Iterate all isr_stub_table, * Set all IDT entry with set_interrupt_gate() * with following values: @@ -14,17 +13,9 @@ void initialize_idt(void) { * Segment: GDT_KERNEL_CODE_SEGMENT_SELECTOR * Privilege: 0 */ - // for (int i = 0; i < ISR_STUB_TABLE_LIMIT; i++) { - // isr_stub_table[i] = NULL; - // } - for (int i = 0; i < ISR_STUB_TABLE_LIMIT; i++) { set_interrupt_gate(i, isr_stub_table[i], GDT_KERNEL_CODE_SEGMENT_SELECTOR, 0); } - - idtr.limit = sizeof(idt) - 1; - idtr.base = (uint32_t)&idt; - __asm__ volatile("lidt %0" : : "m"(_idt_idtr)); __asm__ volatile("sti"); } @@ -32,9 +23,6 @@ void initialize_idt(void) { void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege) { struct IDTGate *idt_int_gate = &interrupt_descriptor_table.table[int_vector]; // TODO : Set handler offset, privilege & segment - idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; - idt_int_gate->segment = gdt_seg_selector; - idt_int_gate->privilege = privilege; // Target system 32-bit and flag this as valid interrupt gate idt_int_gate->_r_bit_1 = INTERRUPT_GATE_R_BIT_1; diff --git a/src/kernel.c b/src/kernel.c index 7b0cc8d..ca7c157 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -4,8 +4,8 @@ #include "lib-header/gdt.h" #include "lib-header/framebuffer.h" #include "lib-header/kernel_loader.h" -#include "lib-header/interrupt.h" #include "lib-header/idt.h" +#include "lib-header/interrupt.h" void write_splash_screen3(); diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index e3d6ce8..bccdca9 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -36,15 +36,14 @@ extern struct IDTR _idt_idtr; struct IDTGate { // First 32-bit (Bit 0 to 31) uint16_t offset_low; - - // TODO : Implement uint16_t segment; - uint8_t _reserved; + uint8_t _reserved : 5; uint8_t _r_bit_1 : 3; uint8_t _r_bit_2 : 3; uint8_t gate_32 : 1; uint8_t _r_bit_3 : 1; - + + // TODO : Implement } __attribute__((packed)); /** @@ -53,10 +52,10 @@ struct IDTGate { * * ... */ -// TODO : Implement -struct IDT { - struct IDTGate entries[IDT_MAX_ENTRY_COUNT]; +struct interrupt_descriptor_table { + struct IDTGate table[IDT_MAX_ENTRY_COUNT]; } __attribute__((packed)); +// TODO : Implement // ... /** @@ -65,11 +64,11 @@ struct IDT { * * ... */ -// TODO : Implement struct IDTR { uint16_t limit; uint32_t base; } __attribute__((packed)); +// TODO : Implement // ... From 696e683e6f3b63cf265feb4c8fdee476b5242fac Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 14:38:21 +0700 Subject: [PATCH 020/176] not fix: idt gate --- src/idt.c | 8 +++++++- src/lib-header/idt.h | 10 ++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/idt.c b/src/idt.c index 80a33e5..6bc92f1 100644 --- a/src/idt.c +++ b/src/idt.c @@ -2,6 +2,7 @@ extern struct IDT idt; extern struct IDTR idtr; +extern struct interrupt_descriptor_table interrupt_descriptor_table; void initialize_idt(void) { /* TODO : @@ -29,5 +30,10 @@ void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_ idt_int_gate->_r_bit_2 = INTERRUPT_GATE_R_BIT_2; idt_int_gate->_r_bit_3 = INTERRUPT_GATE_R_BIT_3; idt_int_gate->gate_32 = 1; - idt_int_gate->valid_bit = 1; + idt_int_gate->privilege = privilege; + idt_int_gate->_reserved = 0; + idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; + idt_int_gate->offset_high = ((uint32_t)handler_address >> 16) & 0xFFFF; + idt_int_gate->segment = gdt_seg_selector; + idt_int_gate->present = 1; } diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index bccdca9..1029ade 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -35,14 +35,17 @@ extern struct IDTR _idt_idtr; */ struct IDTGate { // First 32-bit (Bit 0 to 31) - uint16_t offset_low; - uint16_t segment; uint8_t _reserved : 5; uint8_t _r_bit_1 : 3; uint8_t _r_bit_2 : 3; uint8_t gate_32 : 1; uint8_t _r_bit_3 : 1; - + uint8_t privilege : 2; + uint8_t present : 1; + uint16_t offset_low; + uint16_t offset_high; + uint16_t segment; + // TODO : Implement } __attribute__((packed)); @@ -72,7 +75,6 @@ struct IDTR { // ... - /** * Set IDTGate with proper interrupt handler values. * Will directly edit global IDT variable and set values properly From b014fd225da6c27991afbefb98698a5f117ce7cd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 23 Mar 2023 17:01:41 +0700 Subject: [PATCH 021/176] not fix: bisa run tapi bootloop --- makefile | 4 ++-- src/idt.c | 23 ++++++++++++++--------- src/kernel.c | 14 ++++++++++++++ src/lib-header/idt.h | 20 ++++++++++++-------- src/lib-header/interrupt.h | 1 + 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/makefile b/makefile index 9122301..e6623b7 100644 --- a/makefile +++ b/makefile @@ -28,7 +28,7 @@ clean: kernel: $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o -# TODO: Compile C file with CFLAGS + $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/intsetup.s -o $(OUTPUT_FOLDER)/intsetup.o @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o @@ -43,7 +43,7 @@ iso: kernel @cp $(OUTPUT_FOLDER)/kernel $(OUTPUT_FOLDER)/iso/boot/ @cp other/grub1 $(OUTPUT_FOLDER)/iso/boot/grub/ @cp $(SOURCE_FOLDER)/menu.lst $(OUTPUT_FOLDER)/iso/boot/grub/ -# TODO: Create ISO image + genisoimage -R \ -b boot/grub/grub1 \ -no-emul-boot \ diff --git a/src/idt.c b/src/idt.c index 6bc92f1..d1684d4 100644 --- a/src/idt.c +++ b/src/idt.c @@ -1,9 +1,9 @@ #include "lib-header/idt.h" -extern struct IDT idt; -extern struct IDTR idtr; -extern struct interrupt_descriptor_table interrupt_descriptor_table; +struct interrupt_descriptor_table interrupt_descriptor_table; +struct IDTR _idt_idtr; +void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege); void initialize_idt(void) { /* TODO : * Iterate all isr_stub_table, @@ -24,16 +24,21 @@ void initialize_idt(void) { void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege) { struct IDTGate *idt_int_gate = &interrupt_descriptor_table.table[int_vector]; // TODO : Set handler offset, privilege & segment + idt_int_gate->privilege = privilege; + idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; + idt_int_gate->offset_high = ((uint32_t)handler_address >> 16) & 0xFFFF; + idt_int_gate->segment = gdt_seg_selector; + idt_int_gate->_reserved = 0; + // idt_int_gate->present = 1; // Target system 32-bit and flag this as valid interrupt gate idt_int_gate->_r_bit_1 = INTERRUPT_GATE_R_BIT_1; idt_int_gate->_r_bit_2 = INTERRUPT_GATE_R_BIT_2; idt_int_gate->_r_bit_3 = INTERRUPT_GATE_R_BIT_3; idt_int_gate->gate_32 = 1; - idt_int_gate->privilege = privilege; - idt_int_gate->_reserved = 0; - idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; - idt_int_gate->offset_high = ((uint32_t)handler_address >> 16) & 0xFFFF; - idt_int_gate->segment = gdt_seg_selector; - idt_int_gate->present = 1; + // idt_int_gate->valid = 1; + + + + } diff --git a/src/kernel.c b/src/kernel.c index ca7c157..9baa687 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -20,6 +20,20 @@ void kernel_setup(void) { } +/* Cek rusak */ +// void kernel_setup(void) { +// uint32_t a; +// uint32_t volatile b = 0x0000BABE; +// __asm__("mov $0xCAFE0000, %0" : "=r"(a)); +// enter_protected_mode(&_gdt_gdtr); +// framebuffer_clear(); +// write_splash_screen3(); +// framebuffer_set_cursor(9, 40); +// while (TRUE); +// while (TRUE) b += 1; +// } + + void write_splash_screen3() { char splash_screen[] = "===============================================================================\n" "|| ||\n" diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index 1029ade..a4e0f98 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -19,6 +19,7 @@ extern void *isr_stub_table[ISR_STUB_TABLE_LIMIT]; extern struct IDTR _idt_idtr; +extern struct interrupt_descriptor_table interrupt_descriptor_table; /** * IDTGate, IDT entry that point into interrupt handler @@ -35,16 +36,19 @@ extern struct IDTR _idt_idtr; */ struct IDTGate { // First 32-bit (Bit 0 to 31) - uint8_t _reserved : 5; - uint8_t _r_bit_1 : 3; - uint8_t _r_bit_2 : 3; - uint8_t gate_32 : 1; - uint8_t _r_bit_3 : 1; - uint8_t privilege : 2; - uint8_t present : 1; uint16_t offset_low; - uint16_t offset_high; uint16_t segment; + uint8_t _reserved : 5; + uint8_t _r_bit_1 : 3; + uint8_t _r_bit_2 : 3; + uint8_t gate_32 : 1; + uint8_t _r_bit_3 : 1; + uint8_t privilege : 2; + uint8_t present : 1; + // uint8_t valid : 1; // Valid buat apa ya? + + uint16_t offset_high; + // TODO : Implement } __attribute__((packed)); diff --git a/src/lib-header/interrupt.h b/src/lib-header/interrupt.h index 6a84bbc..e746673 100644 --- a/src/lib-header/interrupt.h +++ b/src/lib-header/interrupt.h @@ -2,6 +2,7 @@ #define _INTERRUPT_H #include "stdtype.h" +#include "portio.h" /* -- PIC constants -- */ From 7f158348c0d9cd48a64471940436b8a8d161690e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 25 Mar 2023 13:49:47 +0700 Subject: [PATCH 022/176] not fix: masih bootloop :( --- src/idt.c | 12 ++++-------- src/lib-header/idt.h | 8 +++----- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/idt.c b/src/idt.c index d1684d4..892ac66 100644 --- a/src/idt.c +++ b/src/idt.c @@ -24,21 +24,17 @@ void initialize_idt(void) { void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege) { struct IDTGate *idt_int_gate = &interrupt_descriptor_table.table[int_vector]; // TODO : Set handler offset, privilege & segment - idt_int_gate->privilege = privilege; - idt_int_gate->offset_low = (uint32_t)handler_address & 0xFFFF; - idt_int_gate->offset_high = ((uint32_t)handler_address >> 16) & 0xFFFF; + idt_int_gate->DPL = privilege; + idt_int_gate->offset_low = (uint32_t)handler_address; + idt_int_gate->offset_high = ((uint32_t)handler_address >> 16); idt_int_gate->segment = gdt_seg_selector; idt_int_gate->_reserved = 0; - // idt_int_gate->present = 1; // Target system 32-bit and flag this as valid interrupt gate idt_int_gate->_r_bit_1 = INTERRUPT_GATE_R_BIT_1; idt_int_gate->_r_bit_2 = INTERRUPT_GATE_R_BIT_2; idt_int_gate->_r_bit_3 = INTERRUPT_GATE_R_BIT_3; idt_int_gate->gate_32 = 1; - // idt_int_gate->valid = 1; - - - + idt_int_gate->valid = 1; } diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index a4e0f98..db048a2 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -43,11 +43,9 @@ struct IDTGate { uint8_t _r_bit_2 : 3; uint8_t gate_32 : 1; uint8_t _r_bit_3 : 1; - uint8_t privilege : 2; - uint8_t present : 1; - // uint8_t valid : 1; // Valid buat apa ya? - - uint16_t offset_high; + uint8_t DPL : 2; + uint8_t valid : 1; + uint16_t offset_high; // Kenapa masih bootloop T_T? // TODO : Implement From 8a152bf0c1b29f5dc081f74abff2be539db6efa4 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Sat, 25 Mar 2023 15:08:47 +0700 Subject: [PATCH 023/176] 3.1 fixed --- src/idt.c | 7 ++++++- src/kernel.c | 2 ++ src/lib-header/idt.h | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/idt.c b/src/idt.c index 892ac66..10558c1 100644 --- a/src/idt.c +++ b/src/idt.c @@ -3,7 +3,12 @@ struct interrupt_descriptor_table interrupt_descriptor_table; struct IDTR _idt_idtr; -void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege); +struct IDTR _idt_idtr = { + .limit = sizeof(struct interrupt_descriptor_table) - 1, + .base = &interrupt_descriptor_table +}; + +// void set_interrupt_gate(uint8_t int_vector, void *handler_address, uint16_t gdt_seg_selector, uint8_t privilege); void initialize_idt(void) { /* TODO : * Iterate all isr_stub_table, diff --git a/src/kernel.c b/src/kernel.c index 9baa687..326df63 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,9 +14,11 @@ void kernel_setup(void) { pic_remap(); initialize_idt(); framebuffer_clear(); + write_splash_screen3(); framebuffer_set_cursor(0, 0); __asm__("int $0x4"); while (TRUE); + } diff --git a/src/lib-header/idt.h b/src/lib-header/idt.h index db048a2..51f490e 100644 --- a/src/lib-header/idt.h +++ b/src/lib-header/idt.h @@ -71,7 +71,7 @@ struct interrupt_descriptor_table { */ struct IDTR { uint16_t limit; - uint32_t base; + struct interrupt_descriptor_table *base; } __attribute__((packed)); // TODO : Implement // ... From e97c9673a2319b78c36cb12da6b487565705dc42 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 07:46:08 +0700 Subject: [PATCH 024/176] feat: keyboard setup --- src/interrupt.c | 11 +++++++++- src/kernel.c | 19 +++++++++++++---- src/keyboard.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 78ae795..f77fbed 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -47,6 +47,15 @@ void main_interrupt_handler( __attribute__((unused)) struct InterruptStack info ) { switch (int_number) { - + case IRQ_KEYBOARD: + keyboard_state_activate(); + break; + default: + break; } } + +void activate_keyboard_interrupt(void) { + out(PIC1_DATA, PIC_DISABLE_ALL_MASK ^ (1 << IRQ_KEYBOARD)); + out(PIC2_DATA, PIC_DISABLE_ALL_MASK); +} diff --git a/src/kernel.c b/src/kernel.c index 326df63..630c7d3 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,14 +14,25 @@ void kernel_setup(void) { pic_remap(); initialize_idt(); framebuffer_clear(); - write_splash_screen3(); framebuffer_set_cursor(0, 0); - __asm__("int $0x4"); - while (TRUE); - + while (TRUE) + keyboard_state_activate(); } +// void kernel_setup(void) { +// enter_protected_mode(&_gdt_gdtr); +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// write_splash_screen3(); +// framebuffer_set_cursor(0, 0); +// __asm__("int $0x4"); +// while (TRUE); + +// } + + /* Cek rusak */ // void kernel_setup(void) { // uint32_t a; diff --git a/src/keyboard.c b/src/keyboard.c index 7ff5b82..ef611be 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -22,3 +22,57 @@ const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; + +static struct KeyboardDriverState keyboard_state = { + .read_extended_mode = 0, + .keyboard_input_on = 0, + .buffer_index = 0, + .keyboard_buffer = {0}, +}; + +// Activate keyboard ISR / start listen keyboard & save to buffer +void keyboard_state_activate(void){ + keyboard_state.keyboard_input_on = 1; +} + +// Deactivate keyboard ISR / stop listening keyboard interrupt +void keyboard_state_deactivate(void){ + keyboard_state.keyboard_input_on = 0; +} + +// Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE +void get_keyboard_buffer(char *buf){ + // memcpy(buf, keyboard_driver_state.keyboard_buffer, KEYBOARD_BUFFER_SIZE); + for (int i = 0; i < KEYBOARD_BUFFER_SIZE; i++) { + buf[i] = keyboard_state.keyboard_buffer[i]; + } +} + +// Check whether keyboard ISR is active or not - @return Equal with keyboard_input_on value +bool is_keyboard_blocking(void){ + return keyboard_state.keyboard_input_on; +} + +void keyboard_isr(void) { + if (!keyboard_state.keyboard_input_on) + keyboard_state.buffer_index = 0; + else { + uint8_t scancode = in(KEYBOARD_DATA_PORT); + char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + // TODO : Implement scancode processing + if (keyboard_state.buffer_index >= KEYBOARD_BUFFER_SIZE) + keyboard_state.buffer_index = 0; + + if (scancode == '\n') { + keyboard_state.buffer_index = 0; + keyboard_state_deactivate(); + } else if (scancode == '\b') { + keyboard_state.buffer_index--; + } else { + keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; + keyboard_state.buffer_index++; + } + + } + pic_ack(IRQ_KEYBOARD); +} From 9aa0be46f98ff866d8f3f309b7a6602b333d899d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 11:49:37 +0700 Subject: [PATCH 025/176] not fix: keyboard on the way --- makefile | 3 +++ src/interrupt.c | 10 ++++---- src/kernel.c | 3 +++ src/keyboard.c | 18 ++++++------- src/lib-header/framebuffer.h | 49 +++++++++++++++++++----------------- src/lib-header/interrupt.h | 1 + 6 files changed, 47 insertions(+), 37 deletions(-) diff --git a/makefile b/makefile index e6623b7..1bdaa4b 100644 --- a/makefile +++ b/makefile @@ -32,7 +32,10 @@ kernel: @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o + @$(CC) $(CFLAGS) src/stdmem.c -o bin/stdmem.o + @$(CC) $(CFLAGS) src/framebuffer.c -o bin/framebuffer.o @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o + @$(CC) $(CFLAGS) src/keyboard.c -o bin/keyboard.o @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... diff --git a/src/interrupt.c b/src/interrupt.c index f77fbed..2bd7780 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -47,11 +47,11 @@ void main_interrupt_handler( __attribute__((unused)) struct InterruptStack info ) { switch (int_number) { - case IRQ_KEYBOARD: - keyboard_state_activate(); - break; - default: - break; + // case IRQ_KEYBOARD: + // keyboard_isr(); + // break; + // default: + // break; } } diff --git a/src/kernel.c b/src/kernel.c index 630c7d3..f36986d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,3 +1,4 @@ +// #include "lib-header/keyboard.h" #include "lib-header/portio.h" #include "lib-header/stdtype.h" #include "lib-header/stdmem.h" @@ -5,8 +6,10 @@ #include "lib-header/framebuffer.h" #include "lib-header/kernel_loader.h" #include "lib-header/idt.h" +#include "lib-header/keyboard.h" #include "lib-header/interrupt.h" + void write_splash_screen3(); void kernel_setup(void) { diff --git a/src/keyboard.c b/src/keyboard.c index ef611be..b2987b0 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3,6 +3,13 @@ #include "lib-header/framebuffer.h" #include "lib-header/stdmem.h" +static struct KeyboardDriverState keyboard_state = { + .read_extended_mode = FALSE, + .keyboard_input_on = FALSE, + .buffer_index = 0, + .keyboard_buffer = {0} +}; + const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', @@ -23,13 +30,6 @@ const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static struct KeyboardDriverState keyboard_state = { - .read_extended_mode = 0, - .keyboard_input_on = 0, - .buffer_index = 0, - .keyboard_buffer = {0}, -}; - // Activate keyboard ISR / start listen keyboard & save to buffer void keyboard_state_activate(void){ keyboard_state.keyboard_input_on = 1; @@ -60,8 +60,8 @@ void keyboard_isr(void) { uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; // TODO : Implement scancode processing - if (keyboard_state.buffer_index >= KEYBOARD_BUFFER_SIZE) - keyboard_state.buffer_index = 0; + // if (keyboard_state.buffer_index >= KEYBOARD_BUFFER_SIZE) + // keyboard_state.buffer_index = 0; if (scancode == '\n') { keyboard_state.buffer_index = 0; diff --git a/src/lib-header/framebuffer.h b/src/lib-header/framebuffer.h index 1727215..c782ea1 100644 --- a/src/lib-header/framebuffer.h +++ b/src/lib-header/framebuffer.h @@ -8,7 +8,7 @@ #define CURSOR_PORT_CMD 0x03D4 #define CURSOR_PORT_DATA 0x03D5 -uint8_t* mfb = MEMORY_FRAMEBUFFER; +// uint8_t* mfb = MEMORY_FRAMEBUFFER; /** * Terminal framebuffer @@ -28,11 +28,12 @@ uint8_t* mfb = MEMORY_FRAMEBUFFER; * @param fg Foreground / Character color * @param bg Background color */ -void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg){ - int frame_buffer_index = (row * 80 + col) * 2; - mfb[frame_buffer_index] = c; - mfb[frame_buffer_index + 1] = (bg << 4) | fg; -} +void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg); +// { +// int frame_buffer_index = (row * 80 + col) * 2; +// mfb[frame_buffer_index] = c; +// mfb[frame_buffer_index + 1] = (bg << 4) | fg; +// } /** * Set cursor to specified location. Row and column starts from 0 @@ -40,28 +41,30 @@ void framebuffer_write(uint8_t row, uint8_t col, char c, uint8_t fg, uint8_t bg) * @param r row * @param c column */ -void framebuffer_set_cursor(uint8_t r, uint8_t c){ - uint16_t cursor_index = r * 80 + c; - out(CURSOR_PORT_CMD, 0x0F); - out(CURSOR_PORT_DATA, (uint8_t) (cursor_index & 0xFF)); - out(CURSOR_PORT_CMD, 0x0E); - out(CURSOR_PORT_DATA, (uint8_t) ((cursor_index >> 8) & 0xFF)); -} +void framebuffer_set_cursor(uint8_t r, uint8_t c); +// { +// uint16_t cursor_index = r * 80 + c; +// out(CURSOR_PORT_CMD, 0x0F); +// out(CURSOR_PORT_DATA, (uint8_t) (cursor_index & 0xFF)); +// out(CURSOR_PORT_CMD, 0x0E); +// out(CURSOR_PORT_DATA, (uint8_t) ((cursor_index >> 8) & 0xFF)); +// } /** * Set all cell in framebuffer character to 0x00 (empty character) * and color to 0x07 (gray character & black background) * */ -void framebuffer_clear(void){ - size_t mfb_size = 80 * 25 * 2; - for (size_t i = 0; i < mfb_size; i++) - if (i % 2 == 0){ - mfb[i] = 0x00; - } - else { - mfb[i] = 0x07; - } -} +void framebuffer_clear(void); +// { +// size_t mfb_size = 80 * 25 * 2; +// for (size_t i = 0; i < mfb_size; i++) +// if (i % 2 == 0){ +// mfb[i] = 0x00; +// } +// else { +// mfb[i] = 0x07; +// } +// } #endif \ No newline at end of file diff --git a/src/lib-header/interrupt.h b/src/lib-header/interrupt.h index e746673..b3d7192 100644 --- a/src/lib-header/interrupt.h +++ b/src/lib-header/interrupt.h @@ -3,6 +3,7 @@ #include "stdtype.h" #include "portio.h" +#include "keyboard.h" /* -- PIC constants -- */ From 02f39ab99336f4d34ad100fdfcdc04f575c048dd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 14:00:49 +0700 Subject: [PATCH 026/176] refactor: boolean --- src/interrupt.c | 8 +++----- src/keyboard.c | 7 +++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 2bd7780..3b12153 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -47,11 +47,9 @@ void main_interrupt_handler( __attribute__((unused)) struct InterruptStack info ) { switch (int_number) { - // case IRQ_KEYBOARD: - // keyboard_isr(); - // break; - // default: - // break; + case (PIC1 + IRQ_KEYBOARD): + keyboard_isr(); + break; } } diff --git a/src/keyboard.c b/src/keyboard.c index b2987b0..f4bcd9f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -32,12 +32,12 @@ const char keyboard_scancode_1_to_ascii_map[256] = { // Activate keyboard ISR / start listen keyboard & save to buffer void keyboard_state_activate(void){ - keyboard_state.keyboard_input_on = 1; + keyboard_state.keyboard_input_on = TRUE; } // Deactivate keyboard ISR / stop listening keyboard interrupt void keyboard_state_deactivate(void){ - keyboard_state.keyboard_input_on = 0; + keyboard_state.keyboard_input_on = FALSE; } // Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE @@ -60,8 +60,6 @@ void keyboard_isr(void) { uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; // TODO : Implement scancode processing - // if (keyboard_state.buffer_index >= KEYBOARD_BUFFER_SIZE) - // keyboard_state.buffer_index = 0; if (scancode == '\n') { keyboard_state.buffer_index = 0; @@ -72,6 +70,7 @@ void keyboard_isr(void) { keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; keyboard_state.buffer_index++; } + framebuffer_write(0, keyboard_state.buffer_index, mapped_char, 0x0c, 0); } pic_ack(IRQ_KEYBOARD); From b37cf7f56bd793b05192b7ab1ff6439c92b25d05 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 14:48:13 +0700 Subject: [PATCH 027/176] fix: bisa ngetik tapi kecepetan + spasi aneh --- src/interrupt.c | 8 ++++++-- src/keyboard.c | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 3b12153..6ce05fc 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -1,4 +1,5 @@ #include "lib-header/interrupt.h" +#include "lib-header/framebuffer.h" void io_wait(void) { out(0x80, 0); @@ -46,10 +47,13 @@ void main_interrupt_handler( uint32_t int_number, __attribute__((unused)) struct InterruptStack info ) { + if (int_number == 32){ // casting paksa di awal + keyboard_isr(); + } + switch (int_number) { - case (PIC1 + IRQ_KEYBOARD): + case (PIC1_OFFSET + IRQ_KEYBOARD): keyboard_isr(); - break; } } diff --git a/src/keyboard.c b/src/keyboard.c index f4bcd9f..3d6034e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -54,9 +54,11 @@ bool is_keyboard_blocking(void){ } void keyboard_isr(void) { - if (!keyboard_state.keyboard_input_on) + if (!keyboard_state.keyboard_input_on){ keyboard_state.buffer_index = 0; - else { + framebuffer_write(21,11,'L',0xa,0); + } else { + framebuffer_write(21,12,'M',0xa,0); uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; // TODO : Implement scancode processing @@ -67,6 +69,7 @@ void keyboard_isr(void) { } else if (scancode == '\b') { keyboard_state.buffer_index--; } else { + // get_keyboard_buffer(&mapped_char); keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; keyboard_state.buffer_index++; } From 27a1e54c4e6f3d54ebffb85d5a2546214b2a7eab Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 15:01:39 +0700 Subject: [PATCH 028/176] feat: 3.3 setup --- makefile | 5 ++- src/disk.c | 51 +++++++++++++++++++++++++ src/fat32.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 src/disk.c diff --git a/makefile b/makefile index 1bdaa4b..395445f 100644 --- a/makefile +++ b/makefile @@ -7,6 +7,7 @@ CC = gcc SOURCE_FOLDER = src OUTPUT_FOLDER = bin ISO_NAME = OS2023 +DISK_NAME = storage # Flags WARNING_CFLAG = -Wall -Wextra -Werror @@ -16,6 +17,8 @@ CFLAGS = $(DEBUG_CFLAG) $(WARNING_CFLAG) $(STRIP_CFLAG) -m32 -c -I$(SOURC AFLAGS = -f elf32 -g -F dwarf LFLAGS = -T $(SOURCE_FOLDER)/linker.ld -melf_i386 +disk: + @qemu-img create -f raw $(OUTPUT_FOLDER)/$(DISK_NAME).bin 4M run: all @qemu-system-i386 -s -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso @@ -24,7 +27,7 @@ build: iso clean: rm -rf *.o *.iso $(OUTPUT_FOLDER)/kernel - +@qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom os2023.iso kernel: $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o diff --git a/src/disk.c b/src/disk.c new file mode 100644 index 0000000..79b26b6 --- /dev/null +++ b/src/disk.c @@ -0,0 +1,51 @@ +#include "lib-header/disk.h" +#include "lib-header/portio.h" + +static void ATA_busy_wait() { + while (in(0x1F7) & ATA_STATUS_BSY); +} + +static void ATA_DRQ_wait() { + while (!(in(0x1F7) & ATA_STATUS_RDY)); +} + +void read_blocks(void *ptr, uint32_t logical_block_address, uint8_t block_count) { + ATA_busy_wait(); + out(0x1F6, 0xE0 | ((logical_block_address >> 24) & 0xF)); + out(0x1F2, block_count); + out(0x1F3, (uint8_t) logical_block_address); + out(0x1F4, (uint8_t) (logical_block_address >> 8)); + out(0x1F5, (uint8_t) (logical_block_address >> 16)); + out(0x1F7, 0x20); + + uint16_t *target = (uint16_t*) ptr; + + for (uint32_t i = 0; i < block_count; i++) { + ATA_busy_wait(); + ATA_DRQ_wait(); + for (uint32_t j = 0; j < HALF_BLOCK_SIZE; j++) + target[j] = in16(0x1F0); + // Note : uint16_t => 2 bytes, HALF_BLOCK_SIZE*2 = BLOCK_SIZE with pointer arithmetic + target += HALF_BLOCK_SIZE; + } +} + +void write_blocks(const void *ptr, uint32_t logical_block_address, uint8_t block_count) { + ATA_busy_wait(); + out(0x1F6, 0xE0 | ((logical_block_address >> 24) & 0xF)); + out(0x1F2, block_count); + out(0x1F3, (uint8_t) logical_block_address); + out(0x1F4, (uint8_t) (logical_block_address >> 8)); + out(0x1F5, (uint8_t) (logical_block_address >> 16)); + out(0x1F7, 0x30); + + for (uint32_t i = 0; i < block_count; i++) { + ATA_busy_wait(); + ATA_DRQ_wait(); + /* Note : uint16_t => 2 bytes, i is current block number to write + HALF_BLOCK_SIZE*i = block_offset with pointer arithmetic + */ + for (uint32_t j = 0; j < HALF_BLOCK_SIZE; j++) + out16(0x1F0, ((uint16_t*) ptr)[HALF_BLOCK_SIZE*i + j]); + } +} diff --git a/src/fat32.c b/src/fat32.c index c481fcf..4483fc0 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -10,4 +10,107 @@ const uint8_t fs_signature[BLOCK_SIZE] = { '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '2', '0', '2', '3', '\n', [BLOCK_SIZE-2] = 'O', [BLOCK_SIZE-1] = 'k', -}; \ No newline at end of file +}; + +/* -- Driver Interfaces -- */ + +/** + * Convert cluster number to logical block address + * + * @param cluster Cluster number to convert + * @return uint32_t Logical Block Address + */ +uint32_t cluster_to_lba(uint32_t cluster); + +/** + * Initialize DirectoryTable value with parent DirectoryEntry and directory name + * + * @param dir_table Pointer to directory table + * @param name 8-byte char for directory name + * @param parent_dir_cluster Parent directory cluster number + */ +void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster); + +/** + * Checking whether filesystem signature is missing or not in boot sector + * + * @return True if memcmp(boot_sector, fs_signature) returning inequality + */ +bool is_empty_storage(void); + +/** + * Create new FAT32 file system. Will write fs_signature into boot sector and + * proper FileAllocationTable (contain CLUSTER_0_VALUE, CLUSTER_1_VALUE, + * and initialized root directory) into cluster number 1 + */ +void create_fat32(void); + +/** + * Initialize file system driver state, if is_empty_storage() then create_fat32() + * Else, read and cache entire FileAllocationTable (located at cluster number 1) into driver state + */ +void initialize_filesystem_fat32(void); + +/** + * Write cluster operation, wrapper for write_blocks(). + * Recommended to use struct ClusterBuffer + * + * @param ptr Pointer to source data + * @param cluster_number Cluster number to write + * @param cluster_count Cluster count to write, due limitation of write_blocks block_count 255 => max cluster_count = 63 + */ +void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count); + +/** + * Read cluster operation, wrapper for read_blocks(). + * Recommended to use struct ClusterBuffer + * + * @param ptr Pointer to buffer for reading + * @param cluster_number Cluster number to read + * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 + */ +void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); + + + + + +/* -- CRUD Operation -- */ + +/** + * FAT32 Folder / Directory read + * + * @param request buf point to struct FAT32DirectoryTable, + * name is directory name, + * ext is unused, + * parent_cluster_number is target directory table to read, + * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) + * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown + */ +int8_t read_directory(struct FAT32DriverRequest request); + + +/** + * FAT32 read, read a file from file system. + * + * @param request All attribute will be used for read, buffer_size will limit reading count + * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown + */ +int8_t read(struct FAT32DriverRequest request); + +/** + * FAT32 write, write a file or folder to file system. + * + * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory + * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown + */ +int8_t write(struct FAT32DriverRequest request); + + +/** + * FAT32 delete, delete a file or empty directory (only 1 DirectoryEntry) in file system. + * + * @param request buf and buffer_size is unused + * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown + */ +int8_t delete(struct FAT32DriverRequest request); \ No newline at end of file From d2c7f616fd8240145c16200816f56e283b5135c0 Mon Sep 17 00:00:00 2001 From: AlphaThrone Date: Sun, 26 Mar 2023 15:35:49 +0700 Subject: [PATCH 029/176] fix: keyboard index issue: rapidly type --- src/keyboard.c | 179 +++++++++++++++++++++++++++---------------------- 1 file changed, 99 insertions(+), 80 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 3d6034e..b6331c1 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,80 +1,99 @@ -#include "lib-header/keyboard.h" -#include "lib-header/portio.h" -#include "lib-header/framebuffer.h" -#include "lib-header/stdmem.h" - -static struct KeyboardDriverState keyboard_state = { - .read_extended_mode = FALSE, - .keyboard_input_on = FALSE, - .buffer_index = 0, - .keyboard_buffer = {0} -}; - -const char keyboard_scancode_1_to_ascii_map[256] = { - 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -// Activate keyboard ISR / start listen keyboard & save to buffer -void keyboard_state_activate(void){ - keyboard_state.keyboard_input_on = TRUE; -} - -// Deactivate keyboard ISR / stop listening keyboard interrupt -void keyboard_state_deactivate(void){ - keyboard_state.keyboard_input_on = FALSE; -} - -// Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE -void get_keyboard_buffer(char *buf){ - // memcpy(buf, keyboard_driver_state.keyboard_buffer, KEYBOARD_BUFFER_SIZE); - for (int i = 0; i < KEYBOARD_BUFFER_SIZE; i++) { - buf[i] = keyboard_state.keyboard_buffer[i]; - } -} - -// Check whether keyboard ISR is active or not - @return Equal with keyboard_input_on value -bool is_keyboard_blocking(void){ - return keyboard_state.keyboard_input_on; -} - -void keyboard_isr(void) { - if (!keyboard_state.keyboard_input_on){ - keyboard_state.buffer_index = 0; - framebuffer_write(21,11,'L',0xa,0); - } else { - framebuffer_write(21,12,'M',0xa,0); - uint8_t scancode = in(KEYBOARD_DATA_PORT); - char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; - // TODO : Implement scancode processing - - if (scancode == '\n') { - keyboard_state.buffer_index = 0; - keyboard_state_deactivate(); - } else if (scancode == '\b') { - keyboard_state.buffer_index--; - } else { - // get_keyboard_buffer(&mapped_char); - keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; - keyboard_state.buffer_index++; - } - framebuffer_write(0, keyboard_state.buffer_index, mapped_char, 0x0c, 0); - - } - pic_ack(IRQ_KEYBOARD); -} +#include "lib-header/keyboard.h" +#include "lib-header/portio.h" +#include "lib-header/stdmem.h" +#include "lib-header/framebuffer.h" +static struct KeyboardDriverState keyboard_state; +static int row=0; +const char keyboard_scancode_1_to_ascii_map[256] = { + 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, '+', 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* -- Driver Interfaces -- */ + +// Activate keyboard ISR / start listen keyboard & save to buffer +void keyboard_state_activate(void){ + keyboard_state.keyboard_input_on=TRUE; +} + +// Deactivate keyboard ISR / stop listening keyboard interrupt +void keyboard_state_deactivate(void){ + keyboard_state.keyboard_input_on=FALSE; +} + +// Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE +void get_keyboard_buffer(char *buf){ + for (int i = 0; i < KEYBOARD_BUFFER_SIZE; i++) { + buf[i] = keyboard_state.keyboard_buffer[i]; + } +} + +// Check whether keyboard ISR is active or not - @return Equal with keyboard_input_on value +bool is_keyboard_blocking(void){ + return keyboard_state.keyboard_input_on; +} + + +/* -- Keyboard Interrupt Service Routine -- */ + +/** + * Handling keyboard interrupt & process scancodes into ASCII character. + * Will start listen and process keyboard scancode if keyboard_input_on. + * + * Will only print printable character into framebuffer. + * Stop processing when enter key (line feed) is pressed. + * + * Note that, with keyboard interrupt & ISR, keyboard reading is non-blocking. + * This can be made into blocking input with `while (is_keyboard_blocking());` + * after calling `keyboard_state_activate();` + */ +void keyboard_isr(void) { + + if (!keyboard_state.keyboard_input_on){ + keyboard_state.buffer_index = 0; + framebuffer_write(21,11,'L',0xa,0); + } + else { + uint8_t scancode = in(KEYBOARD_DATA_PORT); + char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + if(mapped_char=='\b'){ + if(keyboard_state.buffer_index){ + keyboard_state.buffer_index--; + } else if(keyboard_state.buffer_index==0){ + row--; + } + framebuffer_set_cursor(row, keyboard_state.buffer_index); + mapped_char=0; + } else if(mapped_char=='\n'){ + keyboard_state.buffer_index=0; + keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=0; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + mapped_char=0; + row++; + } else if(mapped_char!=0 || mapped_char=='\n' || mapped_char=='\b'){ + keyboard_state.buffer_index++; + keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=mapped_char; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + } else { + + } + framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); + } + pic_ack(IRQ_KEYBOARD); +} + From 3fb454a2d11028f6a2ff3436dc137fc2c277fe8b Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 15:38:39 +0700 Subject: [PATCH 030/176] style: comment on qemu --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index 395445f..00ffb39 100644 --- a/makefile +++ b/makefile @@ -27,7 +27,7 @@ build: iso clean: rm -rf *.o *.iso $(OUTPUT_FOLDER)/kernel -@qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom os2023.iso +# @qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom os2023.iso kernel: $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o From e0aa265381ac4102db72e1d93caae22088a6d7a0 Mon Sep 17 00:00:00 2001 From: AlphaThrone Date: Sun, 26 Mar 2023 15:55:50 +0700 Subject: [PATCH 031/176] fix: overloading index keyboard --- src/keyboard.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index b6331c1..c8d777e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -75,7 +75,11 @@ void keyboard_isr(void) { if(keyboard_state.buffer_index){ keyboard_state.buffer_index--; } else if(keyboard_state.buffer_index==0){ - row--; + if(row<=0){ + row=0; + } else { + row--; + } } framebuffer_set_cursor(row, keyboard_state.buffer_index); mapped_char=0; @@ -84,8 +88,20 @@ void keyboard_isr(void) { keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=0; framebuffer_set_cursor(row, keyboard_state.buffer_index); mapped_char=0; - row++; + if(row>=24){ + row=24; + } else { + row++; + } } else if(mapped_char!=0 || mapped_char=='\n' || mapped_char=='\b'){ + if(keyboard_state.buffer_index>=79){ + if(row>=24){ + row=24; + } else { + row++; + } + keyboard_state.buffer_index=0; + } keyboard_state.buffer_index++; keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=mapped_char; framebuffer_set_cursor(row, keyboard_state.buffer_index); From d566e16a48a8e9ba2f84478ab88595a8a07bf82a Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 26 Mar 2023 21:27:49 +0700 Subject: [PATCH 032/176] fix: keyboard double and backspace --- src/keyboard.c | 100 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index c8d777e..d56915a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3,7 +3,17 @@ #include "lib-header/stdmem.h" #include "lib-header/framebuffer.h" static struct KeyboardDriverState keyboard_state; -static int row=0; +static int row = 0; +static char antiDouble = -1; +static int holding = 0; +static char charHold = -1; +static int backspaceLine[25] = { + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0, + 0,0,0,0,0 +}; const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', @@ -63,7 +73,6 @@ bool is_keyboard_blocking(void){ * after calling `keyboard_state_activate();` */ void keyboard_isr(void) { - if (!keyboard_state.keyboard_input_on){ keyboard_state.buffer_index = 0; framebuffer_write(21,11,'L',0xa,0); @@ -71,44 +80,69 @@ void keyboard_isr(void) { else { uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; - if(mapped_char=='\b'){ - if(keyboard_state.buffer_index){ - keyboard_state.buffer_index--; - } else if(keyboard_state.buffer_index==0){ - if(row<=0){ - row=0; - } else { - row--; + if (mapped_char != antiDouble){ + antiDouble = mapped_char; + if (mapped_char == '\b') { + if (keyboard_state.buffer_index) { + keyboard_state.buffer_index--; + backspaceLine[row]--; + } else if (keyboard_state.buffer_index == 0){ + if (row <= 0) { + row = 0; + } else { + row--; + keyboard_state.buffer_index = backspaceLine[row]; + } } - } - framebuffer_set_cursor(row, keyboard_state.buffer_index); - mapped_char=0; - } else if(mapped_char=='\n'){ - keyboard_state.buffer_index=0; - keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=0; - framebuffer_set_cursor(row, keyboard_state.buffer_index); - mapped_char=0; - if(row>=24){ - row=24; - } else { - row++; - } - } else if(mapped_char!=0 || mapped_char=='\n' || mapped_char=='\b'){ - if(keyboard_state.buffer_index>=79){ - if(row>=24){ - row=24; + framebuffer_write(row, keyboard_state.buffer_index, 0, 0x0c, 0); + framebuffer_set_cursor(row, keyboard_state.buffer_index); + } else if (mapped_char=='\n') { + keyboard_state.buffer_index=0; + keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = 0; + framebuffer_set_cursor(row + 1, keyboard_state.buffer_index); + mapped_char = 0; + if (row >= 24) { + row = 24; } else { row++; } - keyboard_state.buffer_index=0; + } else if (mapped_char !=0){ + framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); + if (keyboard_state.buffer_index >= 79){ + if (row >= 24) { + row = 24; + } else { + row++; + } + keyboard_state.buffer_index = 0; + } else { + keyboard_state.buffer_index++; + backspaceLine[row]++; + keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; + } + if (keyboard_state.buffer_index >= 79 && row < 24){ + framebuffer_set_cursor(row + 1, 0); + } else if (row >= 24){ + framebuffer_set_cursor(24, 0); + } else { + framebuffer_set_cursor(row, keyboard_state.buffer_index); + } + } else { + } - keyboard_state.buffer_index++; - keyboard_state.keyboard_buffer[keyboard_state.buffer_index]=mapped_char; - framebuffer_set_cursor(row, keyboard_state.buffer_index); - } else { + } else { + if (mapped_char == charHold){ + holding++; + } else { + charHold = mapped_char; + holding = 0; + } + antiDouble = -1; + for (int i = 0; i < 550000 - holding * 40000; i++) + io_wait(); } - framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); + } pic_ack(IRQ_KEYBOARD); } From 477f9d5f0bc722e60db8d78dac4bb3ef30516e0f Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Mon, 27 Mar 2023 07:27:30 +0700 Subject: [PATCH 033/176] feat: fat32.c setup --- src/fat32.c | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 4483fc0..88df5d4 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -20,7 +20,9 @@ const uint8_t fs_signature[BLOCK_SIZE] = { * @param cluster Cluster number to convert * @return uint32_t Logical Block Address */ -uint32_t cluster_to_lba(uint32_t cluster); +uint32_t cluster_to_lba(uint32_t cluster){ + return (cluster - 2) * CLUSTER_SIZE + 1; +} /** * Initialize DirectoryTable value with parent DirectoryEntry and directory name @@ -29,27 +31,41 @@ uint32_t cluster_to_lba(uint32_t cluster); * @param name 8-byte char for directory name * @param parent_dir_cluster Parent directory cluster number */ -void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster); +void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ + +} /** * Checking whether filesystem signature is missing or not in boot sector * * @return True if memcmp(boot_sector, fs_signature) returning inequality */ -bool is_empty_storage(void); +bool is_empty_storage(void){ + uint8_t boot_sector[BLOCK_SIZE]; + read_blocks(boot_sector, 0, 1); + return memcmp(boot_sector, fs_signature, BLOCK_SIZE); +} /** * Create new FAT32 file system. Will write fs_signature into boot sector and * proper FileAllocationTable (contain CLUSTER_0_VALUE, CLUSTER_1_VALUE, * and initialized root directory) into cluster number 1 */ -void create_fat32(void); +void create_fat32(void){ + +} /** * Initialize file system driver state, if is_empty_storage() then create_fat32() * Else, read and cache entire FileAllocationTable (located at cluster number 1) into driver state */ -void initialize_filesystem_fat32(void); +void initialize_filesystem_fat32(void){ + if (is_empty_storage()){ + create_fat32(); + } else { + + } +} /** * Write cluster operation, wrapper for write_blocks(). @@ -59,7 +75,9 @@ void initialize_filesystem_fat32(void); * @param cluster_number Cluster number to write * @param cluster_count Cluster count to write, due limitation of write_blocks block_count 255 => max cluster_count = 63 */ -void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count); +void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count){ + +} /** * Read cluster operation, wrapper for read_blocks(). @@ -69,7 +87,9 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_number Cluster number to read * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ -void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); +void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ + +} @@ -87,7 +107,9 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ -int8_t read_directory(struct FAT32DriverRequest request); +int8_t read_directory(struct FAT32DriverRequest request){ + +} /** @@ -96,7 +118,9 @@ int8_t read_directory(struct FAT32DriverRequest request); * @param request All attribute will be used for read, buffer_size will limit reading count * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown */ -int8_t read(struct FAT32DriverRequest request); +int8_t read(struct FAT32DriverRequest request){ + +} /** * FAT32 write, write a file or folder to file system. @@ -104,7 +128,9 @@ int8_t read(struct FAT32DriverRequest request); * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ -int8_t write(struct FAT32DriverRequest request); +int8_t write(struct FAT32DriverRequest request){ + +} /** @@ -113,4 +139,6 @@ int8_t write(struct FAT32DriverRequest request); * @param request buf and buffer_size is unused * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ -int8_t delete(struct FAT32DriverRequest request); \ No newline at end of file +int8_t delete(struct FAT32DriverRequest request){ + +} \ No newline at end of file From 94a0705969ab66770ac0b62ec80b5d6be3d88db4 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <16521502@std.stei.itb.ac.id> Date: Mon, 27 Mar 2023 18:48:23 +0700 Subject: [PATCH 034/176] feat: kernel tester for FAT --- src/kernel.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index f36986d..eaa5c79 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -16,13 +16,59 @@ void kernel_setup(void) { enter_protected_mode(&_gdt_gdtr); pic_remap(); initialize_idt(); + activate_keyboard_interrupt(); framebuffer_clear(); framebuffer_set_cursor(0, 0); - while (TRUE) - keyboard_state_activate(); + initialize_filesystem_fat32(); + keyboard_state_activate(); + + struct ClusterBuffer cbuf[5]; + for (uint32_t i = 0; i < 5; i++) + for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + cbuf[i].buf[j] = i + 'a'; + + struct FAT32DriverRequest request = { + .buf = cbuf, + .name = "ikanaide", + .ext = "uwu", + .parent_cluster_number = ROOT_CLUSTER_NUMBER, + .buffer_size = 0, + } ; + + write(request); // Create folder "ikanaide" + memcpy(request.name, "kano1\0\0\0", 8); + write(request); // Create folder "kano1" + memcpy(request.name, "ikanaide", 8); + delete(request); // Delete first folder, thus creating hole in FS + + memcpy(request.name, "daijoubu", 8); + request.buffer_size = 5*CLUSTER_SIZE; + write(request); // Create fragmented file "daijoubu" + + struct ClusterBuffer readcbuf; + read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); + // If read properly, readcbuf should filled with 'a' + + request.buffer_size = CLUSTER_SIZE; + read(request); // Failed read due not enough buffer size + request.buffer_size = 5*CLUSTER_SIZE; + read(request); // Success read on file "daijoubu" + + while (TRUE); } +// void kernel_setup(void) { +// enter_protected_mode(&_gdt_gdtr); +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// framebuffer_set_cursor(0, 0); +// while (TRUE) +// keyboard_state_activate(); +// } + + // void kernel_setup(void) { // enter_protected_mode(&_gdt_gdtr); // pic_remap(); From 6d3c4b85651bd50398fb074e7828c1c558020629 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 27 Mar 2023 18:52:33 +0700 Subject: [PATCH 035/176] feat: setup for FAT --- .vscode/tasks.json | 3 +- src/interrupt.c | 4 +- src/kernel.c | 96 +++++++++++++++++++++++----------------------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2e633d6..f273cb5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -19,7 +19,7 @@ { "type": "shell", "label": "Launch QEMU", - "command": "echo Starting QEMU&qemu-system-i386 -s -S -cdrom os2023.iso", + "command": "echo Starting QEMU&qemu-system-i386 -s -S -cdrom OS2023.iso", "isBackground": true, "dependsOn": "Build OS", "options": { @@ -45,6 +45,7 @@ "type": "shell", "label": "Exit QEMU", "command": "pkill -f qemu || test $? -eq 1" + } ], } \ No newline at end of file diff --git a/src/interrupt.c b/src/interrupt.c index 6ce05fc..f1c2ed2 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -48,7 +48,9 @@ void main_interrupt_handler( __attribute__((unused)) struct InterruptStack info ) { if (int_number == 32){ // casting paksa di awal - keyboard_isr(); + if (is_keyboard_blocking()) { + int_number++; + } } switch (int_number) { diff --git a/src/kernel.c b/src/kernel.c index eaa5c79..ebd0d84 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -12,63 +12,63 @@ void write_splash_screen3(); -void kernel_setup(void) { - enter_protected_mode(&_gdt_gdtr); - pic_remap(); - initialize_idt(); - activate_keyboard_interrupt(); - framebuffer_clear(); - framebuffer_set_cursor(0, 0); - initialize_filesystem_fat32(); - keyboard_state_activate(); - - struct ClusterBuffer cbuf[5]; - for (uint32_t i = 0; i < 5; i++) - for (uint32_t j = 0; j < CLUSTER_SIZE; j++) - cbuf[i].buf[j] = i + 'a'; - - struct FAT32DriverRequest request = { - .buf = cbuf, - .name = "ikanaide", - .ext = "uwu", - .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = 0, - } ; - - write(request); // Create folder "ikanaide" - memcpy(request.name, "kano1\0\0\0", 8); - write(request); // Create folder "kano1" - memcpy(request.name, "ikanaide", 8); - delete(request); // Delete first folder, thus creating hole in FS - - memcpy(request.name, "daijoubu", 8); - request.buffer_size = 5*CLUSTER_SIZE; - write(request); // Create fragmented file "daijoubu" - - struct ClusterBuffer readcbuf; - read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); - // If read properly, readcbuf should filled with 'a' - - request.buffer_size = CLUSTER_SIZE; - read(request); // Failed read due not enough buffer size - request.buffer_size = 5*CLUSTER_SIZE; - read(request); // Success read on file "daijoubu" - - while (TRUE); -} - - // void kernel_setup(void) { // enter_protected_mode(&_gdt_gdtr); // pic_remap(); // initialize_idt(); +// activate_keyboard_interrupt(); // framebuffer_clear(); // framebuffer_set_cursor(0, 0); -// while (TRUE) -// keyboard_state_activate(); +// initialize_filesystem_fat32(); +// keyboard_state_activate(); + +// struct ClusterBuffer cbuf[5]; +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// cbuf[i].buf[j] = i + 'a'; + +// struct FAT32DriverRequest request = { +// .buf = cbuf, +// .name = "ikanaide", +// .ext = "uwu", +// .parent_cluster_number = ROOT_CLUSTER_NUMBER, +// .buffer_size = 0, +// } ; + +// write(request); // Create folder "ikanaide" +// memcpy(request.name, "kano1\0\0\0", 8); +// write(request); // Create folder "kano1" +// memcpy(request.name, "ikanaide", 8); +// delete(request); // Delete first folder, thus creating hole in FS + +// memcpy(request.name, "daijoubu", 8); +// request.buffer_size = 5*CLUSTER_SIZE; +// write(request); // Create fragmented file "daijoubu" + +// struct ClusterBuffer readcbuf; +// read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); +// // If read properly, readcbuf should filled with 'a' + +// request.buffer_size = CLUSTER_SIZE; +// read(request); // Failed read due not enough buffer size +// request.buffer_size = 5*CLUSTER_SIZE; +// read(request); // Success read on file "daijoubu" + +// while (TRUE); // } +void kernel_setup(void) { + enter_protected_mode(&_gdt_gdtr); + pic_remap(); + initialize_idt(); + framebuffer_clear(); + framebuffer_set_cursor(0, 0); + while (TRUE) + keyboard_state_activate(); +} + + // void kernel_setup(void) { // enter_protected_mode(&_gdt_gdtr); // pic_remap(); From c24d51f4fa4435e4024ee0fb78b528ef17041a87 Mon Sep 17 00:00:00 2001 From: christodharma <13521009@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 07:16:51 +0700 Subject: [PATCH 036/176] Co-authored-by: Hidayatullah Wildan Ghaly Buchary Co-authored-by: Muhammad Haidar Akita Tresnadi --- .vscode/settings.json | 4 ++ .vscode/tasks.json | 2 +- makefile | 9 +++- src/fat32.c | 47 +++++++++++-------- src/kernel.c | 99 +++++++++++++++++++++-------------------- src/lib-header/fat32.h | 15 +++---- src/lib-header/portio.h | 4 ++ src/portio.c | 18 ++++++++ 8 files changed, 120 insertions(+), 78 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index dec631f..8e83c50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { "debug.onTaskErrors": "debugAnyway", + "files.associations": { + "fat32.h": "c", + "portio.h": "c" + }, } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f273cb5..701f6eb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -19,7 +19,7 @@ { "type": "shell", "label": "Launch QEMU", - "command": "echo Starting QEMU&qemu-system-i386 -s -S -cdrom OS2023.iso", + "command": "echo Starting QEMU&qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom OS2023.iso", "isBackground": true, "dependsOn": "Build OS", "options": { diff --git a/makefile b/makefile index 00ffb39..1fcacd8 100644 --- a/makefile +++ b/makefile @@ -21,15 +21,18 @@ disk: @qemu-img create -f raw $(OUTPUT_FOLDER)/$(DISK_NAME).bin 4M run: all - @qemu-system-i386 -s -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso + @qemu-system-i386 -s -S -drive file=bin/storage.bin,format=raw,if=ide,index=0,media=disk -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso + + all: build build: iso + clean: rm -rf *.o *.iso $(OUTPUT_FOLDER)/kernel # @qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom os2023.iso -kernel: +kernel: disk $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/intsetup.s -o $(OUTPUT_FOLDER)/intsetup.o @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o @@ -40,6 +43,8 @@ kernel: @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o @$(CC) $(CFLAGS) src/keyboard.c -o bin/keyboard.o @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o + @$(CC) $(CFLAGS) src/disk.c -o bin/disk.o + @$(CC) $(CFLAGS) src/fat32.c -o bin/fat32.o @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel @echo Linking object files and generate elf32... @rm -f *.o diff --git a/src/fat32.c b/src/fat32.c index 88df5d4..65cdeda 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -2,6 +2,14 @@ #include "lib-header/fat32.h" #include "lib-header/stdmem.h" +// static struct ClusterBuffer clusterBuffer; +static struct FAT32FileAllocationTable fat_table; +// static struct FAT32DirectoryEntry root_dir_entry; +// static struct FAT32DirectoryTable root_dir_table; +// static struct FAT32DriverState driver_state; +// static struct FAT32DriverRequest driver_request; + + const uint8_t fs_signature[BLOCK_SIZE] = { 'C', 'o', 'u', 'r', 's', 'e', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'D', 'e', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'b', 'y', ' ', ' ', ' ', ' ', ' ', @@ -31,15 +39,16 @@ uint32_t cluster_to_lba(uint32_t cluster){ * @param name 8-byte char for directory name * @param parent_dir_cluster Parent directory cluster number */ -void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ +// void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ -} +// } /** * Checking whether filesystem signature is missing or not in boot sector * * @return True if memcmp(boot_sector, fs_signature) returning inequality */ + bool is_empty_storage(void){ uint8_t boot_sector[BLOCK_SIZE]; read_blocks(boot_sector, 0, 1); @@ -52,7 +61,9 @@ bool is_empty_storage(void){ * and initialized root directory) into cluster number 1 */ void create_fat32(void){ - + fat_table.cluster_map[0] = CLUSTER_0_VALUE; + fat_table.cluster_map[1] = CLUSTER_1_VALUE; + fat_table.cluster_map[2] = FAT32_FAT_END_OF_FILE; } /** @@ -76,7 +87,7 @@ void initialize_filesystem_fat32(void){ * @param cluster_count Cluster count to write, due limitation of write_blocks block_count 255 => max cluster_count = 63 */ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count){ - + write_blocks(ptr, cluster_number * CLUSTER_SIZE, cluster_count * CLUSTER_SIZE); } /** @@ -87,9 +98,9 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_number Cluster number to read * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ -void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ +// void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ -} +// } @@ -107,9 +118,9 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ -int8_t read_directory(struct FAT32DriverRequest request){ - -} +// int8_t read_directory(struct FAT32DriverRequest request){ +// return 0; +// } /** @@ -118,9 +129,9 @@ int8_t read_directory(struct FAT32DriverRequest request){ * @param request All attribute will be used for read, buffer_size will limit reading count * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown */ -int8_t read(struct FAT32DriverRequest request){ - -} +// int8_t read(struct FAT32DriverRequest request){ +// return 0; +// } /** * FAT32 write, write a file or folder to file system. @@ -128,9 +139,9 @@ int8_t read(struct FAT32DriverRequest request){ * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ -int8_t write(struct FAT32DriverRequest request){ - -} +// int8_t write(struct FAT32DriverRequest request){ +// return 0; +// } /** @@ -139,6 +150,6 @@ int8_t write(struct FAT32DriverRequest request){ * @param request buf and buffer_size is unused * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ -int8_t delete(struct FAT32DriverRequest request){ - -} \ No newline at end of file +// int8_t delete(struct FAT32DriverRequest request){ +// return 0; +// } \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index ebd0d84..3d7b9e2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -8,67 +8,70 @@ #include "lib-header/idt.h" #include "lib-header/keyboard.h" #include "lib-header/interrupt.h" +#include "lib-header/fat32.h" void write_splash_screen3(); -// void kernel_setup(void) { -// enter_protected_mode(&_gdt_gdtr); -// pic_remap(); -// initialize_idt(); -// activate_keyboard_interrupt(); -// framebuffer_clear(); -// framebuffer_set_cursor(0, 0); -// initialize_filesystem_fat32(); -// keyboard_state_activate(); - -// struct ClusterBuffer cbuf[5]; -// for (uint32_t i = 0; i < 5; i++) -// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) -// cbuf[i].buf[j] = i + 'a'; - -// struct FAT32DriverRequest request = { -// .buf = cbuf, -// .name = "ikanaide", -// .ext = "uwu", -// .parent_cluster_number = ROOT_CLUSTER_NUMBER, -// .buffer_size = 0, -// } ; - -// write(request); // Create folder "ikanaide" -// memcpy(request.name, "kano1\0\0\0", 8); -// write(request); // Create folder "kano1" -// memcpy(request.name, "ikanaide", 8); -// delete(request); // Delete first folder, thus creating hole in FS - -// memcpy(request.name, "daijoubu", 8); -// request.buffer_size = 5*CLUSTER_SIZE; -// write(request); // Create fragmented file "daijoubu" - -// struct ClusterBuffer readcbuf; -// read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); -// // If read properly, readcbuf should filled with 'a' - -// request.buffer_size = CLUSTER_SIZE; -// read(request); // Failed read due not enough buffer size -// request.buffer_size = 5*CLUSTER_SIZE; -// read(request); // Success read on file "daijoubu" - -// while (TRUE); -// } - - void kernel_setup(void) { enter_protected_mode(&_gdt_gdtr); + keyboard_state_activate(); pic_remap(); initialize_idt(); + activate_keyboard_interrupt(); framebuffer_clear(); framebuffer_set_cursor(0, 0); - while (TRUE) - keyboard_state_activate(); + initialize_filesystem_fat32(); + while (TRUE) + keyboard_state_activate(); + + // struct ClusterBuffer cbuf[5]; + // for (uint32_t i = 0; i < 5; i++) + // for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + // cbuf[i].buf[j] = i + 'a'; + + // struct FAT32DriverRequest request = { + // .buf = cbuf, + // .name = "ikanaide", + // .ext = "uwu", + // .parent_cluster_number = ROOT_CLUSTER_NUMBER, + // .buffer_size = 0, + // } ; + + // write(request); // Create folder "ikanaide" + // memcpy(request.name, "kano1\0\0\0", 8); + // write(request); // Create folder "kano1" + // memcpy(request.name, "ikanaide", 8); + // delete(request); // Delete first folder, thus creating hole in FS + + // memcpy(request.name, "daijoubu", 8); + // request.buffer_size = 5*CLUSTER_SIZE; + // write(request); // Create fragmented file "daijoubu" + + // struct ClusterBuffer readcbuf; + // read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); + // // If read properly, readcbuf should filled with 'a' + + // request.buffer_size = CLUSTER_SIZE; + // read(request); // Failed read due not enough buffer size + // request.buffer_size = 5*CLUSTER_SIZE; + // read(request); // Success read on file "daijoubu" + + while (TRUE); } +// void kernel_setup(void) { +// enter_protected_mode(&_gdt_gdtr); +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// framebuffer_set_cursor(0, 0); +// while (TRUE) +// keyboard_state_activate(); +// } + + // void kernel_setup(void) { // enter_protected_mode(&_gdt_gdtr); // pic_remap(); diff --git a/src/lib-header/fat32.h b/src/lib-header/fat32.h index ee445e3..c3081e9 100644 --- a/src/lib-header/fat32.h +++ b/src/lib-header/fat32.h @@ -46,9 +46,6 @@ struct ClusterBuffer { } __attribute__((packed)); - - - /* -- FAT32 Data Structures -- */ /** @@ -160,7 +157,7 @@ uint32_t cluster_to_lba(uint32_t cluster); * @param name 8-byte char for directory name * @param parent_dir_cluster Parent directory cluster number */ -void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster); +// void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster); /** * Checking whether filesystem signature is missing or not in boot sector @@ -200,7 +197,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_number Cluster number to read * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ -void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); +// void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); @@ -218,7 +215,7 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ -int8_t read_directory(struct FAT32DriverRequest request); +// int8_t read_directory(struct FAT32DriverRequest request); /** @@ -227,7 +224,7 @@ int8_t read_directory(struct FAT32DriverRequest request); * @param request All attribute will be used for read, buffer_size will limit reading count * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown */ -int8_t read(struct FAT32DriverRequest request); +// int8_t read(struct FAT32DriverRequest request); /** * FAT32 write, write a file or folder to file system. @@ -235,7 +232,7 @@ int8_t read(struct FAT32DriverRequest request); * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ -int8_t write(struct FAT32DriverRequest request); +// int8_t write(struct FAT32DriverRequest request); /** @@ -244,6 +241,6 @@ int8_t write(struct FAT32DriverRequest request); * @param request buf and buffer_size is unused * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ -int8_t delete(struct FAT32DriverRequest request); +// int8_t delete(struct FAT32DriverRequest request); #endif \ No newline at end of file diff --git a/src/lib-header/portio.h b/src/lib-header/portio.h index ed32fb3..5610ddd 100644 --- a/src/lib-header/portio.h +++ b/src/lib-header/portio.h @@ -19,4 +19,8 @@ void out(uint16_t port, uint8_t data); */ uint8_t in(uint16_t port); +uint16_t in16(uint16_t port); + +void out16(uint16_t port, uint16_t data); + #endif \ No newline at end of file diff --git a/src/portio.c b/src/portio.c index 5f51edd..c1fef45 100644 --- a/src/portio.c +++ b/src/portio.c @@ -22,4 +22,22 @@ uint8_t in(uint16_t port) { : "Nd"(port) ); return result; +} + +void out16(uint16_t port, uint16_t data) { + __asm__( + "outb %0, %1" + : // + : "a"(data), "Nd"(port) + ); +} + +uint16_t in16(uint16_t port) { + uint8_t result; + __asm__ volatile( + "inb %1, %0" + : "=a"(result) + : "Nd"(port) + ); + return result; } \ No newline at end of file From abe9879c10b738c2168635de9ed44a8711a95721 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 00:56:10 +0700 Subject: [PATCH 037/176] fix: makerun --- makefile | 73 ++++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/makefile b/makefile index 1fcacd8..f0e8351 100644 --- a/makefile +++ b/makefile @@ -1,68 +1,51 @@ # Compiler & linker -ASM = nasm -LIN = ld -CC = gcc +ASM = nasm +LIN = ld +CC = gcc +ISO = genisoimage # Directory SOURCE_FOLDER = src OUTPUT_FOLDER = bin -ISO_NAME = OS2023 -DISK_NAME = storage +ISO_NAME = OS2023 # Flags WARNING_CFLAG = -Wall -Wextra -Werror -DEBUG_CFLAG = -ffreestanding -fshort-wchar -g -STRIP_CFLAG = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -CFLAGS = $(DEBUG_CFLAG) $(WARNING_CFLAG) $(STRIP_CFLAG) -m32 -c -I$(SOURCE_FOLDER) -AFLAGS = -f elf32 -g -F dwarf -LFLAGS = -T $(SOURCE_FOLDER)/linker.ld -melf_i386 +DEBUG_CFLAG = -ffreestanding -fshort-wchar -g +STRIP_CFLAG = -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs +CFLAGS = $(DEBUG_CFLAG) $(WARNING_CFLAG) $(STRIP_CFLAG) -m32 -c -I$(SOURCE_FOLDER) +AFLAGS = -f elf32 -g -F dwarf +LFLAGS = -T $(SOURCE_FOLDER)/linker.ld -melf_i386 +IFLAGS = -R -b boot/grub/grub1 -no-emul-boot -boot-load-size 4 -A os -input-charset utf8 -quiet -boot-info-table +DISK_NAME = storage -disk: - @qemu-img create -f raw $(OUTPUT_FOLDER)/$(DISK_NAME).bin 4M run: all - @qemu-system-i386 -s -S -drive file=bin/storage.bin,format=raw,if=ide,index=0,media=disk -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso + @qemu-system-i386 -s -drive file=bin/storage.bin,format=raw,if=ide,index=0,media=disk -cdrom $(OUTPUT_FOLDER)/$(ISO_NAME).iso +disk: + @qemu-img create -f raw $(OUTPUT_FOLDER)/$(DISK_NAME).bin 4M all: build + build: iso clean: rm -rf *.o *.iso $(OUTPUT_FOLDER)/kernel -# @qemu-system-i386 -s -S -drive file=storage.bin,format=raw,if=ide,index=0,media=disk -cdrom os2023.iso - -kernel: disk - $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o - $(ASM) $(AFLAGS) $(SOURCE_FOLDER)/intsetup.s -o $(OUTPUT_FOLDER)/intsetup.o - @$(CC) $(CFLAGS) src/kernel.c -o bin/kernel.o - @$(CC) $(CFLAGS) src/gdt.c -o bin/gdt.o - @$(CC) $(CFLAGS) src/portio.c -o bin/portio.o - @$(CC) $(CFLAGS) src/stdmem.c -o bin/stdmem.o - @$(CC) $(CFLAGS) src/framebuffer.c -o bin/framebuffer.o - @$(CC) $(CFLAGS) src/idt.c -o bin/idt.o - @$(CC) $(CFLAGS) src/keyboard.c -o bin/keyboard.o - @$(CC) $(CFLAGS) src/interrupt.c -o bin/interrupt.o - @$(CC) $(CFLAGS) src/disk.c -o bin/disk.o - @$(CC) $(CFLAGS) src/fat32.c -o bin/fat32.o +kernel:disk + @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o + @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/intsetup.s -o $(OUTPUT_FOLDER)/intsetup.o + $(foreach file, $(wildcard $(SOURCE_FOLDER)/*.c), $(CC) $(CFLAGS) $(file) -o $(OUTPUT_FOLDER)/$(notdir $(file:.c=.o));) @$(LIN) $(LFLAGS) bin/*.o -o $(OUTPUT_FOLDER)/kernel - @echo Linking object files and generate elf32... - @rm -f *.o + @rm -f bin/*.o + iso: kernel @mkdir -p $(OUTPUT_FOLDER)/iso/boot/grub - @cp $(OUTPUT_FOLDER)/kernel $(OUTPUT_FOLDER)/iso/boot/ - @cp other/grub1 $(OUTPUT_FOLDER)/iso/boot/grub/ - @cp $(SOURCE_FOLDER)/menu.lst $(OUTPUT_FOLDER)/iso/boot/grub/ - - genisoimage -R \ - -b boot/grub/grub1 \ - -no-emul-boot \ - -boot-load-size 4 \ - -A os \ - -input-charset utf8 \ - -quiet \ - -boot-info-table \ - -o bin/OS2023.iso \ - bin/iso - @rm -r $(OUTPUT_FOLDER)/iso/ \ No newline at end of file + @cp $(OUTPUT_FOLDER)/kernel $(OUTPUT_FOLDER)/iso/boot/ + @cp other/grub1 $(OUTPUT_FOLDER)/iso/boot/grub/ + @cp $(SOURCE_FOLDER)/menu.lst $(OUTPUT_FOLDER)/iso/boot/grub/ + @echo Creating ISO image... + @$(ISO) $(IFLAGS) -o $(OUTPUT_FOLDER)/$(ISO_NAME).iso $(OUTPUT_FOLDER)/iso + @rm -r $(OUTPUT_FOLDER)/iso/ From 72bd7698a645d7936a5a36dae02739b7d7473e6d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 01:20:55 +0700 Subject: [PATCH 038/176] not fix: the FAT --- src/fat32.c | 57 +++++++++++++++++++++++++----------- src/kernel.c | 65 +++++++++++++++++++++--------------------- src/lib-header/fat32.h | 8 +++--- 3 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 65cdeda..3700355 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -3,13 +3,12 @@ #include "lib-header/stdmem.h" // static struct ClusterBuffer clusterBuffer; -static struct FAT32FileAllocationTable fat_table; +// static struct FAT32FileAllocationTable fat_table; // static struct FAT32DirectoryEntry root_dir_entry; // static struct FAT32DirectoryTable root_dir_table; -// static struct FAT32DriverState driver_state; +struct FAT32DriverState driver_state; // static struct FAT32DriverRequest driver_request; - const uint8_t fs_signature[BLOCK_SIZE] = { 'C', 'o', 'u', 'r', 's', 'e', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'D', 'e', 's', 'i', 'g', 'n', 'e', 'd', ' ', 'b', 'y', ' ', ' ', ' ', ' ', ' ', @@ -39,16 +38,29 @@ uint32_t cluster_to_lba(uint32_t cluster){ * @param name 8-byte char for directory name * @param parent_dir_cluster Parent directory cluster number */ -// void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ - -// } +void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ + dir_table->table[0].name[0] = '.'; + dir_table->table[0].cluster_high = (uint16_t)(parent_dir_cluster >> 16); + dir_table->table[0].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); + + dir_table->table[1].name[0] = '.'; + dir_table->table[1].name[1] = '.'; + dir_table->table[1].cluster_high = (uint16_t)(parent_dir_cluster >> 16); + dir_table->table[1].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); + + for (uint8_t i = 0; i < 8; i++){ + dir_table->table[2].name[i] = name[i]; + } + + dir_table->table[2].cluster_high = 0; + dir_table->table[2].cluster_low = 2; +} /** * Checking whether filesystem signature is missing or not in boot sector * * @return True if memcmp(boot_sector, fs_signature) returning inequality */ - bool is_empty_storage(void){ uint8_t boot_sector[BLOCK_SIZE]; read_blocks(boot_sector, 0, 1); @@ -61,9 +73,19 @@ bool is_empty_storage(void){ * and initialized root directory) into cluster number 1 */ void create_fat32(void){ - fat_table.cluster_map[0] = CLUSTER_0_VALUE; - fat_table.cluster_map[1] = CLUSTER_1_VALUE; - fat_table.cluster_map[2] = FAT32_FAT_END_OF_FILE; + uint8_t boot_sector[BLOCK_SIZE]; + memset(boot_sector, 0, BLOCK_SIZE); + memcpy(boot_sector, fs_signature, BLOCK_SIZE); + write_blocks(boot_sector, 0, 1); + + driver_state.fat_table.cluster_map[0] = CLUSTER_0_VALUE; + driver_state.fat_table.cluster_map[1] = CLUSTER_1_VALUE; + write_clusters(driver_state.fat_table.cluster_map, 1, 1); + + struct FAT32DirectoryTable root_dir_table = {0}; + init_directory_table(&root_dir_table, "root", 0); + write_clusters(&root_dir_table.table, 2, 1); + } /** @@ -74,7 +96,8 @@ void initialize_filesystem_fat32(void){ if (is_empty_storage()){ create_fat32(); } else { - + create_fat32(); + read_clusters(driver_state.fat_table.cluster_map, 1, 1); } } @@ -98,9 +121,9 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_number Cluster number to read * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ -// void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ - -// } +void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ + read_blocks(ptr, cluster_number * CLUSTER_SIZE, cluster_count * CLUSTER_SIZE); +} @@ -119,7 +142,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ // int8_t read_directory(struct FAT32DriverRequest request){ -// return 0; + // } @@ -140,7 +163,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ // int8_t write(struct FAT32DriverRequest request){ -// return 0; + // } @@ -151,5 +174,5 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ // int8_t delete(struct FAT32DriverRequest request){ -// return 0; + // } \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index 3d7b9e2..3b35403 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -15,47 +15,46 @@ void write_splash_screen3(); void kernel_setup(void) { enter_protected_mode(&_gdt_gdtr); - keyboard_state_activate(); pic_remap(); initialize_idt(); - activate_keyboard_interrupt(); + // activate_keyboard_interrupt(); framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); while (TRUE) keyboard_state_activate(); - // struct ClusterBuffer cbuf[5]; - // for (uint32_t i = 0; i < 5; i++) - // for (uint32_t j = 0; j < CLUSTER_SIZE; j++) - // cbuf[i].buf[j] = i + 'a'; - - // struct FAT32DriverRequest request = { - // .buf = cbuf, - // .name = "ikanaide", - // .ext = "uwu", - // .parent_cluster_number = ROOT_CLUSTER_NUMBER, - // .buffer_size = 0, - // } ; - - // write(request); // Create folder "ikanaide" - // memcpy(request.name, "kano1\0\0\0", 8); - // write(request); // Create folder "kano1" - // memcpy(request.name, "ikanaide", 8); - // delete(request); // Delete first folder, thus creating hole in FS - - // memcpy(request.name, "daijoubu", 8); - // request.buffer_size = 5*CLUSTER_SIZE; - // write(request); // Create fragmented file "daijoubu" - - // struct ClusterBuffer readcbuf; - // read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); - // // If read properly, readcbuf should filled with 'a' - - // request.buffer_size = CLUSTER_SIZE; - // read(request); // Failed read due not enough buffer size - // request.buffer_size = 5*CLUSTER_SIZE; - // read(request); // Success read on file "daijoubu" + struct ClusterBuffer cbuf[5]; + for (uint32_t i = 0; i < 5; i++) + for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + cbuf[i].buf[j] = i + 'a'; + + struct FAT32DriverRequest request = { + .buf = cbuf, + .name = "ikanaide", + .ext = "uwu", + .parent_cluster_number = ROOT_CLUSTER_NUMBER, + .buffer_size = 0, + } ; + + write(request); // Create folder "ikanaide" + memcpy(request.name, "kano1\0\0\0", 8); + write(request); // Create folder "kano1" + memcpy(request.name, "ikanaide", 8); + delete(request); // Delete first folder, thus creating hole in FS + + memcpy(request.name, "daijoubu", 8); + request.buffer_size = 5*CLUSTER_SIZE; + write(request); // Create fragmented file "daijoubu" + + struct ClusterBuffer readcbuf; + read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); + // If read properly, readcbuf should filled with 'a' + + request.buffer_size = CLUSTER_SIZE; + read(request); // Failed read due not enough buffer size + request.buffer_size = 5*CLUSTER_SIZE; + read(request); // Success read on file "daijoubu" while (TRUE); } diff --git a/src/lib-header/fat32.h b/src/lib-header/fat32.h index c3081e9..54137b3 100644 --- a/src/lib-header/fat32.h +++ b/src/lib-header/fat32.h @@ -197,7 +197,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_number Cluster number to read * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ -// void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); +void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count); @@ -224,7 +224,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param request All attribute will be used for read, buffer_size will limit reading count * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown */ -// int8_t read(struct FAT32DriverRequest request); +int8_t read(struct FAT32DriverRequest request); /** * FAT32 write, write a file or folder to file system. @@ -232,7 +232,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ -// int8_t write(struct FAT32DriverRequest request); +int8_t write(struct FAT32DriverRequest request); /** @@ -241,6 +241,6 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param request buf and buffer_size is unused * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ -// int8_t delete(struct FAT32DriverRequest request); +int8_t delete(struct FAT32DriverRequest request); #endif \ No newline at end of file From 0e6156b0d4da9b899539aee24fc868ba112b1bf7 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 01:28:36 +0700 Subject: [PATCH 039/176] not fix: the FAT --- src/fat32.c | 2 +- src/portio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 3700355..bf8ced1 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -83,7 +83,7 @@ void create_fat32(void){ write_clusters(driver_state.fat_table.cluster_map, 1, 1); struct FAT32DirectoryTable root_dir_table = {0}; - init_directory_table(&root_dir_table, "root", 0); + init_directory_table(&root_dir_table, "ROOT", 0); write_clusters(&root_dir_table.table, 2, 1); } diff --git a/src/portio.c b/src/portio.c index c1fef45..fe66787 100644 --- a/src/portio.c +++ b/src/portio.c @@ -33,7 +33,7 @@ void out16(uint16_t port, uint16_t data) { } uint16_t in16(uint16_t port) { - uint8_t result; + uint16_t result; __asm__ volatile( "inb %1, %0" : "=a"(result) From 55c313afe7424bfc8c3ad175b5637bdea9aabe82 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 01:54:56 +0700 Subject: [PATCH 040/176] fix: portio bruh --- src/kernel.c | 9 +++++++++ src/portio.c | 42 +++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 3b35403..c34f90a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -13,6 +13,15 @@ void write_splash_screen3(); +// void kernel_setup(void) { +// enter_protected_mode(&_gdt_gdtr); +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// framebuffer_set_cursor(0,0); +// write_blocks(fs_signature, 0, 1); +// } + void kernel_setup(void) { enter_protected_mode(&_gdt_gdtr); pic_remap(); diff --git a/src/portio.c b/src/portio.c index fe66787..e3a285f 100644 --- a/src/portio.c +++ b/src/portio.c @@ -2,42 +2,42 @@ #include "lib-header/portio.h" /** x86 inb/outb: - * @param dx target port - * @param al input/output byte - */ +* @param dx target port +* @param al input/output byte +*/ void out(uint16_t port, uint8_t data) { - __asm__( - "outb %0, %1" - : // - : "a"(data), "Nd"(port) + __asm__ volatile( + "outb %0, %1" + : // + : "a"(data), "Nd"(port) ); } -uint8_t in(uint16_t port) { - uint8_t result; +void out16(uint16_t port, uint16_t data) { __asm__ volatile( - "inb %1, %0" - : "=a"(result) - : "Nd"(port) + "outw %0, %1" + : // + : "a"(data), "Nd"(port) ); - return result; } -void out16(uint16_t port, uint16_t data) { - __asm__( - "outb %0, %1" - : // - : "a"(data), "Nd"(port) +uint8_t in(uint16_t port) { + uint8_t result; + __asm__ volatile( + "inb %1, %0" + : "=a"(result) + : "Nd"(port) ); + return result; } uint16_t in16(uint16_t port) { uint16_t result; __asm__ volatile( - "inb %1, %0" - : "=a"(result) - : "Nd"(port) + "inw %1, %0" + : "=a"(result) + : "Nd"(port) ); return result; } \ No newline at end of file From 0f3817cc35ead1dd3c6393ae8550c5a358d80726 Mon Sep 17 00:00:00 2001 From: christodharma <13521009@std.stei.itb.ac.id> Date: Tue, 28 Mar 2023 10:18:16 +0700 Subject: [PATCH 041/176] fix: hasil asistensi --- src/fat32.c | 2 +- src/interrupt.c | 5 ----- src/kernel.c | 1 + 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index bf8ced1..b89a9c8 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -110,7 +110,7 @@ void initialize_filesystem_fat32(void){ * @param cluster_count Cluster count to write, due limitation of write_blocks block_count 255 => max cluster_count = 63 */ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_count){ - write_blocks(ptr, cluster_number * CLUSTER_SIZE, cluster_count * CLUSTER_SIZE); + write_blocks(ptr, cluster_number * 4, cluster_count * CLUSTER_BLOCK_COUNT); } /** diff --git a/src/interrupt.c b/src/interrupt.c index f1c2ed2..8e030b8 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -47,11 +47,6 @@ void main_interrupt_handler( uint32_t int_number, __attribute__((unused)) struct InterruptStack info ) { - if (int_number == 32){ // casting paksa di awal - if (is_keyboard_blocking()) { - int_number++; - } - } switch (int_number) { case (PIC1_OFFSET + IRQ_KEYBOARD): diff --git a/src/kernel.c b/src/kernel.c index c34f90a..09463ba 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -25,6 +25,7 @@ void write_splash_screen3(); void kernel_setup(void) { enter_protected_mode(&_gdt_gdtr); pic_remap(); + activate_keyboard_interrupt(); initialize_idt(); // activate_keyboard_interrupt(); framebuffer_clear(); From 0d29ece473ee79edafcd9416b28706ff0d279ec9 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 04:58:53 +0700 Subject: [PATCH 042/176] Adding read and write template and fix some bug --- src/fat32.c | 64 ++++++++++++++++++++++++++++++++++++++------- src/kernel_loader.s | 6 ++--- src/linker.ld | 5 ++++ 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index b89a9c8..aa786d8 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -80,10 +80,11 @@ void create_fat32(void){ driver_state.fat_table.cluster_map[0] = CLUSTER_0_VALUE; driver_state.fat_table.cluster_map[1] = CLUSTER_1_VALUE; + driver_state.fat_table.cluster_map[2] = FAT32_FAT_END_OF_FILE; write_clusters(driver_state.fat_table.cluster_map, 1, 1); - + struct FAT32DirectoryTable root_dir_table = {0}; - init_directory_table(&root_dir_table, "ROOT", 0); + init_directory_table(&root_dir_table, "ROOT", 2); write_clusters(&root_dir_table.table, 2, 1); } @@ -122,7 +123,7 @@ void write_clusters(const void *ptr, uint32_t cluster_number, uint8_t cluster_co * @param cluster_count Cluster count to read, due limitation of read_blocks block_count 255 => max cluster_count = 63 */ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ - read_blocks(ptr, cluster_number * CLUSTER_SIZE, cluster_count * CLUSTER_SIZE); + read_blocks(ptr, cluster_number * 4, cluster_count * CLUSTER_BLOCK_COUNT); } @@ -152,9 +153,43 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ * @param request All attribute will be used for read, buffer_size will limit reading count * @return Error code: 0 success - 1 not a file - 2 not enough buffer - 3 not found - -1 unknown */ -// int8_t read(struct FAT32DriverRequest request){ -// return 0; -// } +int8_t read(struct FAT32DriverRequest request){ + uint32_t total_cluster; + uint32_t location; + read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + if (request.buffer_size < driver_state.dir_table_buf.table[i].filesize) { + return 2; + } else if (driver_state.dir_table_buf.table[i].attribute == 1){ + return 1; + } + total_cluster = driver_state.dir_table_buf.table[i].filesize / CLUSTER_SIZE; + if (total_cluster * CLUSTER_SIZE < driver_state.dir_table_buf.table[i].filesize){ + total_cluster += 1; + } else { + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + for (uint32_t j = 0; j < total_cluster; j++){ + if (j == 0){ + read_clusters(request.buf + CLUSTER_SIZE * j, location, 1); + } else { + read_clusters(request.buf + CLUSTER_SIZE * j, driver_state.fat_table.cluster_map[location], 1); + location = driver_state.fat_table.cluster_map[location]; + } + } + + //Implementasi untuk read isi dari cluster belum dilakukan + + } + break; + } + + + } + return 0; +} + /** * FAT32 write, write a file or folder to file system. @@ -162,9 +197,20 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ * @param request All attribute will be used for write, buffer_size == 0 then create a folder / directory * @return Error code: 0 success - 1 file/folder already exist - 2 invalid parent cluster - -1 unknown */ -// int8_t write(struct FAT32DriverRequest request){ - -// } +int8_t write(struct FAT32DriverRequest request){ + read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + if (request.buffer_size < driver_state.dir_table_buf.table[i].filesize) { + return 2; + } else if (driver_state.dir_table_buf.table[i].attribute == 1){ + return 1; + } + } + } + return 0; +} /** diff --git a/src/kernel_loader.s b/src/kernel_loader.s index 2439411..6df0408 100644 --- a/src/kernel_loader.s +++ b/src/kernel_loader.s @@ -4,7 +4,7 @@ extern kernel_setup ; kernel -KERNEL_STACK_SIZE equ 4096 ; size of stack in bytes +KERNEL_STACK_SIZE equ 2097152 ; size of stack in bytes MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant FLAGS equ 0x0 ; multiboot flags CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum @@ -15,14 +15,14 @@ align 4 ; align at 4 bytes kernel_stack: ; label points to beginning of memory resb KERNEL_STACK_SIZE ; reserve stack for the kernel -section .text ; start of the text (code) section +section .multiboot ; start of the text (code) section align 4 ; the code must be 4 byte aligned dd MAGIC_NUMBER ; write the magic number to the machine code, dd FLAGS ; the flags, dd CHECKSUM ; and the checksum - +section .text loader: ; the loader label (defined as entry point in linker script) mov esp, kernel_stack + KERNEL_STACK_SIZE ; setup stack register to proper location call kernel_setup diff --git a/src/linker.ld b/src/linker.ld index 9a19dc3..d6b81ab 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -3,6 +3,11 @@ ENTRY(loader) /* the name of the entry label */ SECTIONS { . = 0x00100000; /* the code should be loaded at 1 MB */ + .multiboot : + { + *(.multiboot) + } + .text ALIGN (0x1000) : /* align at 4 KB */ { *(.text) /* all text sections from all files */ From f9705a90e6a9638e5bc05362b62b1e0f8173766c Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 05:18:00 +0700 Subject: [PATCH 043/176] edit write --- src/fat32.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index aa786d8..0b02d31 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -200,16 +200,23 @@ int8_t read(struct FAT32DriverRequest request){ int8_t write(struct FAT32DriverRequest request){ read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); - for (int i = 0; i < 64; i++){ - if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ - if (request.buffer_size < driver_state.dir_table_buf.table[i].filesize) { - return 2; - } else if (driver_state.dir_table_buf.table[i].attribute == 1){ - return 1; - } - } + uint32_t cluster = 0; + while (driver_state.fat_table.cluster_map[cluster] != 0){ + cluster++; + } + // Todo : Request wajib memberikan request.parent_cluster_number yang valid (cluster tersebut berisikan directory). + + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + return 1; } - return 0; + } + if(request.buffer_size == 0){ + driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; + write_clusters(driver_state.fat_table.cluster_map,1,1); + } + + return 0; } From 06e8b171625a7db5b52357eb81216540f61f1ccd Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 05:42:10 +0700 Subject: [PATCH 044/176] last commit sleep bentar --- src/fat32.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fat32.c b/src/fat32.c index 0b02d31..bd99bc4 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -142,6 +142,7 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ * buffer_size must be exactly sizeof(struct FAT32DirectoryTable) * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ + // int8_t read_directory(struct FAT32DriverRequest request){ // } @@ -179,7 +180,7 @@ int8_t read(struct FAT32DriverRequest request){ } } - //Implementasi untuk read isi dari cluster belum dilakukan + } break; @@ -214,6 +215,8 @@ int8_t write(struct FAT32DriverRequest request){ if(request.buffer_size == 0){ driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; write_clusters(driver_state.fat_table.cluster_map,1,1); + } else if (request.buffer_size > 0){ + } return 0; From b716c80015b4332df53d584ac7de40fcd649c8d9 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 12:52:01 +0700 Subject: [PATCH 045/176] feat!(write): add write func; belum direct table --- src/fat32.c | 68 ++++++++++++++++++++++++++++++++++++++++++++-------- src/kernel.c | 26 ++++++++++---------- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index bd99bc4..5ffc8f8 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -158,7 +158,7 @@ int8_t read(struct FAT32DriverRequest request){ uint32_t total_cluster; uint32_t location; read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); - read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); + read_clusters(&driver_state.fat_table, 1, 1); for (int i = 0; i < 64; i++){ if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ if (request.buffer_size < driver_state.dir_table_buf.table[i].filesize) { @@ -173,15 +173,12 @@ int8_t read(struct FAT32DriverRequest request){ location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; for (uint32_t j = 0; j < total_cluster; j++){ if (j == 0){ - read_clusters(request.buf + CLUSTER_SIZE * j, location, 1); + read_clusters(request.buf + CLUSTER_SIZE * j, location, 1); } else { read_clusters(request.buf + CLUSTER_SIZE * j, driver_state.fat_table.cluster_map[location], 1); location = driver_state.fat_table.cluster_map[location]; } } - - - } break; } @@ -200,23 +197,62 @@ int8_t read(struct FAT32DriverRequest request){ */ int8_t write(struct FAT32DriverRequest request){ read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); - read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); + read_clusters(&driver_state.fat_table, 1, 1); uint32_t cluster = 0; + uint32_t clusterNext = 0; while (driver_state.fat_table.cluster_map[cluster] != 0){ - cluster++; + cluster++; // Ini index } // Todo : Request wajib memberikan request.parent_cluster_number yang valid (cluster tersebut berisikan directory). for (int i = 0; i < 64; i++){ if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ - return 1; + return 1; } } - if(request.buffer_size == 0){ + + if (request.buffer_size == 0){ driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; write_clusters(driver_state.fat_table.cluster_map,1,1); + + struct FAT32DirectoryTable new_dir = {0}; + init_directory_table(&new_dir, request.name, cluster); + } else if (request.buffer_size > 0){ + struct FAT32DirectoryTable new_dir = {0}; + init_directory_table(&new_dir, request.name, cluster); + + uint32_t total_cluster = request.buffer_size / CLUSTER_SIZE; + if (total_cluster * CLUSTER_SIZE < request.buffer_size){ + total_cluster += 1; + } + + for (uint32_t i = 0; i < total_cluster + 1; i++){ + + cluster = 0; + + while (driver_state.fat_table.cluster_map[cluster] != 0){ + cluster++; // Ini index + } + clusterNext = cluster + 1; + + while (driver_state.fat_table.cluster_map[clusterNext] != 0){ + clusterNext++; // Ini index + } + + if (i < total_cluster - 1){ + driver_state.fat_table.cluster_map[cluster] = clusterNext; + } else { + driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; + } + + write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); + + write_clusters(driver_state.fat_table.cluster_map,1,1); + } + + } return 0; @@ -230,5 +266,17 @@ int8_t write(struct FAT32DriverRequest request){ * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ // int8_t delete(struct FAT32DriverRequest request){ - +// read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); +// read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); +// for (int i = 0; i < 64; i++){ +// if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ +// if (driver_state.dir_table_buf.table[i].attribute == 1){ +// return 2; +// } +// driver_state.dir_table_buf.table[i].name[0] = 0xE5; +// write_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); +// break; +// } +// } +// return 0; // } \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index 09463ba..939db51 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -31,8 +31,8 @@ void kernel_setup(void) { framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); - while (TRUE) - keyboard_state_activate(); + // while (TRUE) + // keyboard_state_activate(); struct ClusterBuffer cbuf[5]; for (uint32_t i = 0; i < 5; i++) @@ -51,22 +51,24 @@ void kernel_setup(void) { memcpy(request.name, "kano1\0\0\0", 8); write(request); // Create folder "kano1" memcpy(request.name, "ikanaide", 8); - delete(request); // Delete first folder, thus creating hole in FS + // delete(request); // Delete first folder, thus creating hole in FS memcpy(request.name, "daijoubu", 8); request.buffer_size = 5*CLUSTER_SIZE; write(request); // Create fragmented file "daijoubu" - struct ClusterBuffer readcbuf; - read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); - // If read properly, readcbuf should filled with 'a' + // struct ClusterBuffer readcbuf; + // read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); + // // If read properly, readcbuf should filled with 'a' - request.buffer_size = CLUSTER_SIZE; - read(request); // Failed read due not enough buffer size - request.buffer_size = 5*CLUSTER_SIZE; - read(request); // Success read on file "daijoubu" - - while (TRUE); + // request.buffer_size = CLUSTER_SIZE; + // int8_t debug01 = read(request); // Failed read due not enough buffer size + // request.buffer_size = 5*CLUSTER_SIZE; + // int8_t debug02 = read(request); // Success read on file "daijoubu" + + while (TRUE) { + // debug01 += debug02; + } } From cda718aa607f5dd8b462aca7dd07f22c23652198 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 13:29:34 +0700 Subject: [PATCH 046/176] feat: add dir table template for write folder --- src/fat32.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/fat32.c b/src/fat32.c index 5ffc8f8..cdce5d8 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -203,7 +203,7 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } - // Todo : Request wajib memberikan request.parent_cluster_number yang valid (cluster tersebut berisikan directory). + // TODO : Request wajib memberikan request.parent_cluster_number yang valid (cluster tersebut berisikan directory). for (int i = 0; i < 64; i++){ if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ @@ -218,6 +218,17 @@ int8_t write(struct FAT32DriverRequest request){ struct FAT32DirectoryTable new_dir = {0}; init_directory_table(&new_dir, request.name, cluster); + write_clusters(new_dir.table, request.parent_cluster_number, 1); + + cluster = 0; + + // cari empty + while (driver_state.dir_table_buf.table[cluster].user_attribute == UATTR_NOT_EMPTY){ + cluster++; // Ini index + } + + + } else if (request.buffer_size > 0){ struct FAT32DirectoryTable new_dir = {0}; init_directory_table(&new_dir, request.name, cluster); From 3d44d8a2d008b61359810931657cf373d9a6c818 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 14:20:22 +0700 Subject: [PATCH 047/176] repair minor mistake (dtble) --- src/fat32.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index cdce5d8..0f009f6 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -39,21 +39,19 @@ uint32_t cluster_to_lba(uint32_t cluster){ * @param parent_dir_cluster Parent directory cluster number */ void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ - dir_table->table[0].name[0] = '.'; + // dir_table->table[0].name[0] = '.'; dir_table->table[0].cluster_high = (uint16_t)(parent_dir_cluster >> 16); dir_table->table[0].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); - - dir_table->table[1].name[0] = '.'; - dir_table->table[1].name[1] = '.'; - dir_table->table[1].cluster_high = (uint16_t)(parent_dir_cluster >> 16); - dir_table->table[1].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); - for (uint8_t i = 0; i < 8; i++){ - dir_table->table[2].name[i] = name[i]; + dir_table->table[0].name[i] = name[i]; } - dir_table->table[2].cluster_high = 0; - dir_table->table[2].cluster_low = 2; + // dir_table->table[1].name[0] = '.'; + // dir_table->table[1].name[1] = '.'; + // dir_table->table[1].cluster_high = (uint16_t)(parent_dir_cluster >> 16); + // dir_table->table[1].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); + // dir_table->table[2].cluster_high = 0; + // dir_table->table[2].cluster_low = 2; } /** @@ -85,6 +83,8 @@ void create_fat32(void){ struct FAT32DirectoryTable root_dir_table = {0}; init_directory_table(&root_dir_table, "ROOT", 2); + driver_state.dir_table_buf.table[0] = root_dir_table.table[0]; + write_clusters(driver_state.dir_table_buf.table, 2, 1); write_clusters(&root_dir_table.table, 2, 1); } @@ -200,6 +200,7 @@ int8_t write(struct FAT32DriverRequest request){ read_clusters(&driver_state.fat_table, 1, 1); uint32_t cluster = 0; uint32_t clusterNext = 0; + uint32_t cluster_table = 0; while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } @@ -217,15 +218,18 @@ int8_t write(struct FAT32DriverRequest request){ struct FAT32DirectoryTable new_dir = {0}; init_directory_table(&new_dir, request.name, cluster); + + write_clusters(new_dir.table, cluster, 1); - write_clusters(new_dir.table, request.parent_cluster_number, 1); + cluster_table = 0; - cluster = 0; - - // cari empty - while (driver_state.dir_table_buf.table[cluster].user_attribute == UATTR_NOT_EMPTY){ - cluster++; // Ini index + // cari empty di dirtable + while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ + cluster_table++; // Ini index } + driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; + write_clusters(driver_state.dir_table_buf.table, 2,1); + From bb8a6f69a2a6a4ba20d0d43e183a50fa13f46aef Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 14:34:31 +0700 Subject: [PATCH 048/176] edit write dirtable --- src/fat32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 0f009f6..f63d427 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -45,6 +45,8 @@ void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uin for (uint8_t i = 0; i < 8; i++){ dir_table->table[0].name[i] = name[i]; } + dir_table->table[0].user_attribute = UATTR_NOT_EMPTY; + // dir_table->table[1].name[0] = '.'; // dir_table->table[1].name[1] = '.'; @@ -83,8 +85,6 @@ void create_fat32(void){ struct FAT32DirectoryTable root_dir_table = {0}; init_directory_table(&root_dir_table, "ROOT", 2); - driver_state.dir_table_buf.table[0] = root_dir_table.table[0]; - write_clusters(driver_state.dir_table_buf.table, 2, 1); write_clusters(&root_dir_table.table, 2, 1); } From f40a08e2e1174d85c66359cb18d7366433e9b59a Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 15:03:17 +0700 Subject: [PATCH 049/176] fix minor bug --- src/fat32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index f63d427..c51dd45 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -222,13 +222,13 @@ int8_t write(struct FAT32DriverRequest request){ write_clusters(new_dir.table, cluster, 1); cluster_table = 0; - + // cari empty di dirtable while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ cluster_table++; // Ini index } driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; - write_clusters(driver_state.dir_table_buf.table, 2,1); + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); From 0d6738d22192a5b822380dfc93825c32e9018292 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 15:27:51 +0700 Subject: [PATCH 050/176] Write bismilllah final --- src/fat32.c | 24 +++++++++++++++++------- src/kernel.c | 4 +++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index c51dd45..51c310f 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -198,9 +198,9 @@ int8_t read(struct FAT32DriverRequest request){ int8_t write(struct FAT32DriverRequest request){ read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); read_clusters(&driver_state.fat_table, 1, 1); - uint32_t cluster = 0; - uint32_t clusterNext = 0; - uint32_t cluster_table = 0; + uint16_t cluster = 0; + uint16_t clusterNext = 0; + uint16_t cluster_table = 0; while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } @@ -234,8 +234,6 @@ int8_t write(struct FAT32DriverRequest request){ } else if (request.buffer_size > 0){ - struct FAT32DirectoryTable new_dir = {0}; - init_directory_table(&new_dir, request.name, cluster); uint32_t total_cluster = request.buffer_size / CLUSTER_SIZE; if (total_cluster * CLUSTER_SIZE < request.buffer_size){ @@ -255,15 +253,27 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.fat_table.cluster_map[clusterNext] != 0){ clusterNext++; // Ini index } + + cluster_table = 0; + + while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ + cluster_table++; // Ini index + } + driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; + memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); + memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); + driver_state.dir_table_buf.table[cluster_table].attribute = 0; + driver_state.dir_table_buf.table[cluster_table].cluster_low = cluster; if (i < total_cluster - 1){ driver_state.fat_table.cluster_map[cluster] = clusterNext; + driver_state.dir_table_buf.table[cluster_table].filesize = 2048; } else { driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; } - - write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); + write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); write_clusters(driver_state.fat_table.cluster_map,1,1); } diff --git a/src/kernel.c b/src/kernel.c index 939db51..6fdcaef 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -48,13 +48,15 @@ void kernel_setup(void) { } ; write(request); // Create folder "ikanaide" + request.parent_cluster_number = 3; memcpy(request.name, "kano1\0\0\0", 8); write(request); // Create folder "kano1" - memcpy(request.name, "ikanaide", 8); + // memcpy(request.name, "ikanaide", 8); // delete(request); // Delete first folder, thus creating hole in FS memcpy(request.name, "daijoubu", 8); request.buffer_size = 5*CLUSTER_SIZE; + request.parent_cluster_number = 4; write(request); // Create fragmented file "daijoubu" // struct ClusterBuffer readcbuf; From 7f5558678125a6876f2aaefd72cee6659b87bff3 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 15:47:03 +0700 Subject: [PATCH 051/176] fix: add size handling for not maximum line in file --- src/fat32.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 51c310f..93da447 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -257,8 +257,9 @@ int8_t write(struct FAT32DriverRequest request){ cluster_table = 0; while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ - cluster_table++; // Ini index - } + cluster_table++; // Ini index + } + driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); @@ -270,6 +271,7 @@ int8_t write(struct FAT32DriverRequest request){ driver_state.dir_table_buf.table[cluster_table].filesize = 2048; } else { driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; + driver_state.dir_table_buf.table[cluster_table].filesize = request.buffer_size - (CLUSTER_SIZE * i); } write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); From 161fb6037b665a974e858ccffe6cb9dca49bd88e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 16:14:38 +0700 Subject: [PATCH 052/176] fix: multiFile read; issue: merging file --- src/fat32.c | 11 ++++++----- src/kernel.c | 24 +++++++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 93da447..75a237f 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -260,7 +260,7 @@ int8_t write(struct FAT32DriverRequest request){ cluster_table++; // Ini index } - driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; + memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); driver_state.dir_table_buf.table[cluster_table].attribute = 0; @@ -268,17 +268,18 @@ int8_t write(struct FAT32DriverRequest request){ if (i < total_cluster - 1){ driver_state.fat_table.cluster_map[cluster] = clusterNext; - driver_state.dir_table_buf.table[cluster_table].filesize = 2048; + driver_state.dir_table_buf.table[cluster_table].filesize += 2048; } else { driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; - driver_state.dir_table_buf.table[cluster_table].filesize = request.buffer_size - (CLUSTER_SIZE * i); + driver_state.dir_table_buf.table[cluster_table].filesize += request.buffer_size - (CLUSTER_SIZE * i); } write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); - write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); + write_clusters(driver_state.fat_table.cluster_map,1,1); } - + driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } diff --git a/src/kernel.c b/src/kernel.c index 6fdcaef..0750e13 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -59,17 +59,23 @@ void kernel_setup(void) { request.parent_cluster_number = 4; write(request); // Create fragmented file "daijoubu" - // struct ClusterBuffer readcbuf; - // read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER+1, 1); - // // If read properly, readcbuf should filled with 'a' - - // request.buffer_size = CLUSTER_SIZE; - // int8_t debug01 = read(request); // Failed read due not enough buffer size - // request.buffer_size = 5*CLUSTER_SIZE; - // int8_t debug02 = read(request); // Success read on file "daijoubu" + for (uint32_t i = 0; i < 5; i++) + for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + cbuf[i].buf[j] = '0'; + + request.buf = cbuf; + + struct ClusterBuffer readcbuf; + read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER + 3, 1); + // If read properly, readcbuf should filled with 'a' + + request.buffer_size = CLUSTER_SIZE; + int8_t debug01 = read(request); // Failed read due not enough buffer size + request.buffer_size = 5*CLUSTER_SIZE; + int8_t debug02 = read(request); // Success read on file "daijoubu" while (TRUE) { - // debug01 += debug02; + debug01 += debug02; } } From 3a82b035d9831c1c8e829e032020f498f0e05238 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 16:21:53 +0700 Subject: [PATCH 053/176] fixing read size bug --- src/fat32.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 75a237f..82d09e9 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -239,7 +239,15 @@ int8_t write(struct FAT32DriverRequest request){ if (total_cluster * CLUSTER_SIZE < request.buffer_size){ total_cluster += 1; } - + cluster_table = 0; + while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ + cluster_table++; // Ini index + } + memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); + memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); + driver_state.dir_table_buf.table[cluster_table].attribute = 0; + driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; + driver_state.dir_table_buf.table[cluster_table].cluster_low = cluster; for (uint32_t i = 0; i < total_cluster + 1; i++){ cluster = 0; @@ -253,18 +261,6 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.fat_table.cluster_map[clusterNext] != 0){ clusterNext++; // Ini index } - - cluster_table = 0; - - while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ - cluster_table++; // Ini index - } - - - memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); - memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); - driver_state.dir_table_buf.table[cluster_table].attribute = 0; - driver_state.dir_table_buf.table[cluster_table].cluster_low = cluster; if (i < total_cluster - 1){ driver_state.fat_table.cluster_map[cluster] = clusterNext; @@ -275,10 +271,8 @@ int8_t write(struct FAT32DriverRequest request){ } write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); - write_clusters(driver_state.fat_table.cluster_map,1,1); } - driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } From ab9569050adb28e4d61e32a96ebb873a7e9e57d4 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 16:39:36 +0700 Subject: [PATCH 054/176] fix write final (maybe) --- src/fat32.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 82d09e9..4f0497f 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -198,13 +198,15 @@ int8_t read(struct FAT32DriverRequest request){ int8_t write(struct FAT32DriverRequest request){ read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); read_clusters(&driver_state.fat_table, 1, 1); + if (driver_state.fat_table.cluster_map[request.parent_cluster_number] != FAT32_FAT_END_OF_FILE){ + return 2; + } uint16_t cluster = 0; uint16_t clusterNext = 0; uint16_t cluster_table = 0; while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } - // TODO : Request wajib memberikan request.parent_cluster_number yang valid (cluster tersebut berisikan directory). for (int i = 0; i < 64; i++){ if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ @@ -287,18 +289,18 @@ int8_t write(struct FAT32DriverRequest request){ * @param request buf and buffer_size is unused * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ -// int8_t delete(struct FAT32DriverRequest request){ -// read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); -// read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); -// for (int i = 0; i < 64; i++){ -// if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ -// if (driver_state.dir_table_buf.table[i].attribute == 1){ -// return 2; -// } -// driver_state.dir_table_buf.table[i].name[0] = 0xE5; -// write_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); -// break; -// } -// } -// return 0; -// } \ No newline at end of file +int8_t delete(struct FAT32DriverRequest request){ + read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + if (driver_state.dir_table_buf.table[i].attribute == 1){ + return 2; + } + driver_state.dir_table_buf.table[i].name[0] = 0xE5; + write_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + break; + } + } + return 1; +} \ No newline at end of file From 91691cc619101ca3eda4b32cb872d7168712ca0b Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 16:59:31 +0700 Subject: [PATCH 055/176] feat(kernel): add set up for kernel debugging --- src/kernel.c | 81 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 0750e13..7b3458f 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -13,32 +13,42 @@ void write_splash_screen3(); -// void kernel_setup(void) { -// enter_protected_mode(&_gdt_gdtr); -// pic_remap(); -// initialize_idt(); -// framebuffer_clear(); -// framebuffer_set_cursor(0,0); -// write_blocks(fs_signature, 0, 1); -// } - void kernel_setup(void) { + + /* Enter protected mode */ enter_protected_mode(&_gdt_gdtr); + + + /* Remap PIC */ pic_remap(); - activate_keyboard_interrupt(); initialize_idt(); - // activate_keyboard_interrupt(); framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); - // while (TRUE) - // keyboard_state_activate(); + + /* Initialize keyboard */ + activate_keyboard_interrupt(); + + + /* Initialize cbuf for debugging */ struct ClusterBuffer cbuf[5]; for (uint32_t i = 0; i < 5; i++) for (uint32_t j = 0; j < CLUSTER_SIZE; j++) cbuf[i].buf[j] = i + 'a'; + + /* Initialize cbufs for debugging */ + struct ClusterBuffer cbufs[6]; + for (uint32_t i = 0; i < 5; i++) + for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + cbufs[i].buf[j] = i + '1'; + cbufs[5].buf[0] = 'E'; + cbufs[5].buf[1] = 'N'; + cbufs[5].buf[2] = 'D'; + + + /* Initialize request for debugging */ struct FAT32DriverRequest request = { .buf = cbuf, .name = "ikanaide", @@ -47,35 +57,74 @@ void kernel_setup(void) { .buffer_size = 0, } ; + + /* Folder ikanaide attached to ROOT */ write(request); // Create folder "ikanaide" + + + /* Folder kano1 attached to folder ikanaide */ request.parent_cluster_number = 3; memcpy(request.name, "kano1\0\0\0", 8); write(request); // Create folder "kano1" + + + /* Delete debug */ // memcpy(request.name, "ikanaide", 8); // delete(request); // Delete first folder, thus creating hole in FS + + /* File daijoubu attached to folder kanol */ memcpy(request.name, "daijoubu", 8); request.buffer_size = 5*CLUSTER_SIZE; request.parent_cluster_number = 4; write(request); // Create fragmented file "daijoubu" + + /* File perusak attached to folder kanol */ + request.buf = cbufs; + memcpy(request.name, "perusak", 8); + request.buffer_size = 5*CLUSTER_SIZE + 3; + write(request); // Create fragmented file "perusak" + + + /* Reset request.buf */ for (uint32_t i = 0; i < 5; i++) for (uint32_t j = 0; j < CLUSTER_SIZE; j++) cbuf[i].buf[j] = '0'; + cbufs[5].buf[0] = 'E'; + cbufs[5].buf[1] = 'N'; + cbufs[5].buf[2] = 'D'; + request.buf = cbufs; - request.buf = cbuf; + /* Read file perusak */ struct ClusterBuffer readcbuf; - read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER + 3, 1); + read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER + 10, 1); // If read properly, readcbuf should filled with 'a' + + /* Test read FAIL due not enough buffer size */ + request.parent_cluster_number = 4; request.buffer_size = CLUSTER_SIZE; int8_t debug01 = read(request); // Failed read due not enough buffer size + + + /* Test read FAIL due not valid parent_cluster */ + request.parent_cluster_number = 20; + request.buffer_size = CLUSTER_SIZE; + int8_t debug03 = read(request); // Failed read due not valid parent_cluster + + + /* Test read SUCCESS */ request.buffer_size = 5*CLUSTER_SIZE; int8_t debug02 = read(request); // Success read on file "daijoubu" + + /* Buat unused variable saja */ + write_splash_screen3(); while (TRUE) { - debug01 += debug02; + keyboard_state_activate(); + debug01 += debug02 + debug03; } } From a44c5d45f604b11b9dd12759f0102e14c232a072 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 19:20:20 +0700 Subject: [PATCH 056/176] feat: add another debugger for kernel --- src/kernel.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 7b3458f..0357c33 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -62,6 +62,29 @@ void kernel_setup(void) { write(request); // Create folder "ikanaide" + /* Folder BRO attached to ROOT */ + memcpy(request.name, "BRO\0\0\0\0\0", 8); + write(request); // Create folder "ikatwo" + + + /* Folder brother */ + request.parent_cluster_number = 4; + memcpy(request.name, "brother\0", 8); + write(request); // Create folder "brother" + + + /* Folder b420 */ + request.parent_cluster_number = 4; + memcpy(request.name, "b420---\0", 8); + write(request); // Create folder "b420" + + + /* Folder destroys */ + request.parent_cluster_number = 2; + memcpy(request.name, "destroys", 8); + write(request); // Create folder "destroys" + + /* Folder kano1 attached to folder ikanaide */ request.parent_cluster_number = 3; memcpy(request.name, "kano1\0\0\0", 8); @@ -69,20 +92,20 @@ void kernel_setup(void) { /* Delete debug */ - // memcpy(request.name, "ikanaide", 8); - // delete(request); // Delete first folder, thus creating hole in FS + memcpy(request.name, "destroys", 8); + delete(request); // Delete first folder, thus creating hole in FS /* File daijoubu attached to folder kanol */ memcpy(request.name, "daijoubu", 8); request.buffer_size = 5*CLUSTER_SIZE; - request.parent_cluster_number = 4; + request.parent_cluster_number = 8; write(request); // Create fragmented file "daijoubu" /* File perusak attached to folder kanol */ request.buf = cbufs; - memcpy(request.name, "perusak", 8); + memcpy(request.name, "perusak-", 8); request.buffer_size = 5*CLUSTER_SIZE + 3; write(request); // Create fragmented file "perusak" @@ -121,10 +144,10 @@ void kernel_setup(void) { /* Buat unused variable saja */ + debug01 += debug02 + debug03; write_splash_screen3(); while (TRUE) { - keyboard_state_activate(); - debug01 += debug02 + debug03; + keyboard_state_activate(); } } From edb129c4630919673f713d7c1641491aa7f50dbb Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 19:44:22 +0700 Subject: [PATCH 057/176] fix: handle multiple file or folder with same name --- src/fat32.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 4f0497f..0bf4c4c 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -208,13 +208,15 @@ int8_t write(struct FAT32DriverRequest request){ cluster++; // Ini index } - for (int i = 0; i < 64; i++){ - if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ - return 1; - } - } if (request.buffer_size == 0){ + + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ + return 1; + } + } + driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; write_clusters(driver_state.fat_table.cluster_map,1,1); @@ -229,22 +231,32 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ cluster_table++; // Ini index } + driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); - } else if (request.buffer_size > 0){ - + + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && + memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + return 1; + } + } + uint32_t total_cluster = request.buffer_size / CLUSTER_SIZE; if (total_cluster * CLUSTER_SIZE < request.buffer_size){ total_cluster += 1; } + cluster_table = 0; + while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ cluster_table++; // Ini index } + memcpy(driver_state.dir_table_buf.table[cluster_table].name, request.name, 8); memcpy(driver_state.dir_table_buf.table[cluster_table].ext, request.ext, 3); driver_state.dir_table_buf.table[cluster_table].attribute = 0; @@ -275,6 +287,7 @@ int8_t write(struct FAT32DriverRequest request){ write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); write_clusters(driver_state.fat_table.cluster_map,1,1); } + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } From 47e087e24aa8b98f5967514def131388b914d995 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 19:44:53 +0700 Subject: [PATCH 058/176] feat: add another debugger for multple folder name --- src/kernel.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 0357c33..bd82997 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -64,7 +64,7 @@ void kernel_setup(void) { /* Folder BRO attached to ROOT */ memcpy(request.name, "BRO\0\0\0\0\0", 8); - write(request); // Create folder "ikatwo" + write(request); // Create folder "BRO" /* Folder brother */ @@ -92,8 +92,8 @@ void kernel_setup(void) { /* Delete debug */ - memcpy(request.name, "destroys", 8); - delete(request); // Delete first folder, thus creating hole in FS + // memcpy(request.name, "destroys", 8); + // delete(request); // Delete first folder, thus creating hole in FS /* File daijoubu attached to folder kanol */ @@ -110,7 +110,16 @@ void kernel_setup(void) { write(request); // Create fragmented file "perusak" + /* File duplicate Folder BRO attached to ROOT */ + request.buffer_size = 0; + request.parent_cluster_number = ROOT_CLUSTER_NUMBER; + memcpy(request.name, "BRO\0\0\0\0\0", 8); + memcpy(request.ext, "uwO", 3); + uint8_t test = write(request); // Create folder "BRO" + test += 3; // Buat unused variable + /* Reset request.buf */ + memcpy(request.ext, "uwu", 3); for (uint32_t i = 0; i < 5; i++) for (uint32_t j = 0; j < CLUSTER_SIZE; j++) cbuf[i].buf[j] = '0'; From 7534d1b3e01b7b05e3dff5f8580ca89577d1eccd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 29 Mar 2023 19:53:27 +0700 Subject: [PATCH 059/176] feat: add delete test case --- src/kernel.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index bd82997..565c7fe 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -91,9 +91,11 @@ void kernel_setup(void) { write(request); // Create folder "kano1" - /* Delete debug */ + /* Delete debug for folder destroys (should be success) */ // memcpy(request.name, "destroys", 8); - // delete(request); // Delete first folder, thus creating hole in FS + // request.buffer_size = 0; + // request.parent_cluster_number = 2; + // delete(request); /* File daijoubu attached to folder kanol */ @@ -106,10 +108,25 @@ void kernel_setup(void) { /* File perusak attached to folder kanol */ request.buf = cbufs; memcpy(request.name, "perusak-", 8); - request.buffer_size = 5*CLUSTER_SIZE + 3; + request.buffer_size = 5 * CLUSTER_SIZE + 3; write(request); // Create fragmented file "perusak" + /* Delete debug for file perusak (should be success) */ + // memcpy(request.name, "perusak-", 8); + // memcpy(request.ext, "uwu", 3); + // request.buffer_size = 6 * CLUSTER_SIZE; + // request.parent_cluster_number = 8; + // delete(request); + + + /* Delete debug for folder kanol (should be fail) */ + // memcpy(request.name, "kanol", 8); + // request.buffer_size = 0; + // request.parent_cluster_number = 3; + // delete(request); + + /* File duplicate Folder BRO attached to ROOT */ request.buffer_size = 0; request.parent_cluster_number = ROOT_CLUSTER_NUMBER; @@ -118,6 +135,7 @@ void kernel_setup(void) { uint8_t test = write(request); // Create folder "BRO" test += 3; // Buat unused variable + /* Reset request.buf */ memcpy(request.ext, "uwu", 3); for (uint32_t i = 0; i < 5; i++) @@ -158,6 +176,7 @@ void kernel_setup(void) { while (TRUE) { keyboard_state_activate(); } + } From 34219f12d1db984447fc1a14c5b12c7b76ab8cfe Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 20:08:56 +0700 Subject: [PATCH 060/176] del del del --- src/fat32.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 0bf4c4c..329ac6b 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -303,17 +303,44 @@ int8_t write(struct FAT32DriverRequest request){ * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ int8_t delete(struct FAT32DriverRequest request){ + struct FAT32DirectoryEntry temp_ent; + struct FAT32DirectoryTable temp_tab; + uint32_t location = 0; + uint16_t cluster_temp = 0; + bool flag = 0; read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); - read_clusters(&driver_state.fat_table, request.parent_cluster_number, 1); - for (int i = 0; i < 64; i++){ - if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ - if (driver_state.dir_table_buf.table[i].attribute == 1){ + read_clusters(&driver_state.fat_table, 1, 1); + read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + if (request.buffer_size == 0){ + for (int i = 1; i < 64; i++){ + if (driver_state.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ return 2; } - driver_state.dir_table_buf.table[i].name[0] = 0xE5; - write_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); - break; + } + if (memcmp(request.name, "ROOT", 8)){ + return -1; + } + // delete folder + + } else { + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + driver_state.dir_table_buf.table[i] = temp_ent; + do + { + if (driver_state.fat_table.cluster_map[location] == FAT32_FAT_END_OF_FILE){ + driver_state.fat_table.cluster_map[location] = 0; + flag = 1; + } else { + cluster_temp = location; + location = driver_state.fat_table.cluster_map[location]; + driver_state.fat_table.cluster_map[cluster_temp] = 0; + } + } while (!flag); + return 0; } } return 1; + } } \ No newline at end of file From 93d31cd7dc26ddae331ebee2639c0963234371c6 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 20:56:17 +0700 Subject: [PATCH 061/176] add delete file --- src/fat32.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 329ac6b..be1f3f3 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -303,25 +303,36 @@ int8_t write(struct FAT32DriverRequest request){ * @return Error code: 0 success - 1 not found - 2 folder is not empty - -1 unknown */ int8_t delete(struct FAT32DriverRequest request){ - struct FAT32DirectoryEntry temp_ent; - struct FAT32DirectoryTable temp_tab; + struct FAT32DirectoryEntry temp_ent = {0}; + struct FAT32DirectoryTable temp_tab = {0}; uint32_t location = 0; uint16_t cluster_temp = 0; bool flag = 0; read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); read_clusters(&driver_state.fat_table, 1, 1); - read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + read_clusters(&temp_tab, request.parent_cluster_number, 1); if (request.buffer_size == 0){ for (int i = 1; i < 64; i++){ - if (driver_state.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ + if (temp_tab.table[i].user_attribute == UATTR_NOT_EMPTY){ return 2; } } if (memcmp(request.name, "ROOT", 8)){ return -1; } + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + driver_state.dir_table_buf.table[i] = temp_ent; + driver_state.fat_table.cluster_map[location] = 0; + break; + } + } + write_clusters(driver_state.fat_table.cluster_map,1,1); + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); + + return 0; // delete folder - } else { for (int i = 0; i < 64; i++){ if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0 && memcmp(driver_state.dir_table_buf.table[i].ext, request.ext, 3) == 0){ @@ -338,6 +349,8 @@ int8_t delete(struct FAT32DriverRequest request){ driver_state.fat_table.cluster_map[cluster_temp] = 0; } } while (!flag); + write_clusters(driver_state.fat_table.cluster_map,1,1); + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); return 0; } } From 98c4168536f71f091ca650cd5f57e07385f8d86c Mon Sep 17 00:00:00 2001 From: Darmodar Date: Wed, 29 Mar 2023 22:14:03 +0700 Subject: [PATCH 062/176] Delete bismillah final --- src/fat32.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index be1f3f3..9efd394 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -7,6 +7,7 @@ // static struct FAT32DirectoryEntry root_dir_entry; // static struct FAT32DirectoryTable root_dir_table; struct FAT32DriverState driver_state; + // static struct FAT32DriverRequest driver_request; const uint8_t fs_signature[BLOCK_SIZE] = { @@ -308,26 +309,36 @@ int8_t delete(struct FAT32DriverRequest request){ uint32_t location = 0; uint16_t cluster_temp = 0; bool flag = 0; + int index = 0; read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); read_clusters(&driver_state.fat_table, 1, 1); - read_clusters(&temp_tab, request.parent_cluster_number, 1); + temp_tab = driver_state.dir_table_buf; if (request.buffer_size == 0){ + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + index = i; + break; + } + } + read_clusters(&temp_tab.table, location, 1); for (int i = 1; i < 64; i++){ if (temp_tab.table[i].user_attribute == UATTR_NOT_EMPTY){ return 2; } } - if (memcmp(request.name, "ROOT", 8)){ + if (memcmp(request.name, "ROOT", 8) == 0){ return -1; } - for (int i = 0; i < 64; i++){ - if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ - location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; - driver_state.dir_table_buf.table[i] = temp_ent; - driver_state.fat_table.cluster_map[location] = 0; - break; - } - } + driver_state.dir_table_buf.table[index] = temp_ent; + driver_state.fat_table.cluster_map[location] = 0; + // for (int i = 0; i < 64; i++){ + // if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ + // location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + + // break; + // } + // } write_clusters(driver_state.fat_table.cluster_map,1,1); write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); From d54beb836e1f88aeb014854e73db734fc8f1ddc8 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 30 Mar 2023 13:47:23 +0700 Subject: [PATCH 063/176] Add read directory --- src/fat32.c | 50 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 9efd394..8c076be 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -16,6 +16,34 @@ const uint8_t fs_signature[BLOCK_SIZE] = { 'L', 'a', 'b', ' ', 'S', 'i', 's', 't', 'e', 'r', ' ', 'I', 'T', 'B', ' ', ' ', 'M', 'a', 'd', 'e', ' ', 'w', 'i', 't', 'h', ' ', '<', '3', ' ', ' ', ' ', ' ', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '2', '0', '2', '3', '\n', + [BLOCK_SIZE-200] = 'F', + [BLOCK_SIZE-199] = 'A', + [BLOCK_SIZE-198] = 'C', + [BLOCK_SIZE-197] = 'T', + [BLOCK_SIZE-196] = '{', + [BLOCK_SIZE-195] = 'c', + [BLOCK_SIZE-194] = 'h', + [BLOCK_SIZE-193] = '1', + [BLOCK_SIZE-192] = '2', + [BLOCK_SIZE-191] = 'u', + [BLOCK_SIZE-190] = 'r', + [BLOCK_SIZE-189] = 'u', + [BLOCK_SIZE-188] = '_', + [BLOCK_SIZE-187] = '1', + [BLOCK_SIZE-186] = '5', + [BLOCK_SIZE-185] = '_', + [BLOCK_SIZE-184] = 'b', + [BLOCK_SIZE-183] = '3', + [BLOCK_SIZE-182] = '5', + [BLOCK_SIZE-181] = 't', + [BLOCK_SIZE-180] = '_', + [BLOCK_SIZE-179] = '6', + [BLOCK_SIZE-178] = '1', + [BLOCK_SIZE-177] = 'r', + [BLOCK_SIZE-176] = 'l', + [BLOCK_SIZE-175] = ':', + [BLOCK_SIZE-174] = 'D', + [BLOCK_SIZE-173] = '}', [BLOCK_SIZE-2] = 'O', [BLOCK_SIZE-1] = 'k', }; @@ -144,9 +172,23 @@ void read_clusters(void *ptr, uint32_t cluster_number, uint8_t cluster_count){ * @return Error code: 0 success - 1 not a folder - 2 not found - -1 unknown */ -// int8_t read_directory(struct FAT32DriverRequest request){ - -// } +int8_t read_directory(struct FAT32DriverRequest request){ + uint32_t location; + read_clusters(&driver_state.dir_table_buf, request.parent_cluster_number, 1); + for (int i = 0; i < 64; i++){ + if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ + if (request.buffer_size < driver_state.dir_table_buf.table[i].filesize) { + return 2; + } else if (driver_state.dir_table_buf.table[i].attribute == 1){ + return 1; + } + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + read_clusters(request.buf + CLUSTER_SIZE, location, 1); + break; + } + } + return 0; +} /** @@ -208,8 +250,6 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } - - if (request.buffer_size == 0){ for (int i = 0; i < 64; i++){ From 165f49f94d4151c09f2648cac1edba21001b6ea6 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 15:19:49 +0700 Subject: [PATCH 064/176] feat: add keyboard wait time --- src/keyboard.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index d56915a..5636190 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7,6 +7,7 @@ static int row = 0; static char antiDouble = -1; static int holding = 0; static char charHold = -1; +static bool isHolding = FALSE; static int backspaceLine[25] = { 0,0,0,0,0, 0,0,0,0,0, @@ -73,11 +74,13 @@ bool is_keyboard_blocking(void){ * after calling `keyboard_state_activate();` */ void keyboard_isr(void) { + uint16_t holdWait = 0; if (!keyboard_state.keyboard_input_on){ keyboard_state.buffer_index = 0; framebuffer_write(21,11,'L',0xa,0); } else { + while (is_keyboard_blocking()){ uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; if (mapped_char != antiDouble){ @@ -106,6 +109,7 @@ void keyboard_isr(void) { } else { row++; } + keyboard_state_deactivate(); } else if (mapped_char !=0){ framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); if (keyboard_state.buffer_index >= 79){ @@ -134,15 +138,29 @@ void keyboard_isr(void) { } else { if (mapped_char == charHold){ holding++; + isHolding = TRUE; } else { charHold = mapped_char; holding = 0; + isHolding = FALSE; } + + if (holding < 1){ + holdWait = 8000; + } else if (holding < 150) { + holdWait = 9960; + } else { + holdWait = 9990; + } + antiDouble = -1; - for (int i = 0; i < 550000 - holding * 40000; i++) - io_wait(); + if (isHolding || holding > -1){ + for (int i = 0; i < 10000000 - (holdWait * 1000); i++){ + io_wait(); + } + } } - + } } pic_ack(IRQ_KEYBOARD); } From d564fd56b29a1bc4089def196a5af2e12c0dcd19 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 16:15:14 +0700 Subject: [PATCH 065/176] fix: handle hold keyboard error --- src/keyboard.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 5636190..80f0efa 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7,7 +7,6 @@ static int row = 0; static char antiDouble = -1; static int holding = 0; static char charHold = -1; -static bool isHolding = FALSE; static int backspaceLine[25] = { 0,0,0,0,0, 0,0,0,0,0, @@ -74,7 +73,7 @@ bool is_keyboard_blocking(void){ * after calling `keyboard_state_activate();` */ void keyboard_isr(void) { - uint16_t holdWait = 0; + int16_t holdWait = 0; if (!keyboard_state.keyboard_input_on){ keyboard_state.buffer_index = 0; framebuffer_write(21,11,'L',0xa,0); @@ -138,26 +137,22 @@ void keyboard_isr(void) { } else { if (mapped_char == charHold){ holding++; - isHolding = TRUE; } else { charHold = mapped_char; holding = 0; - isHolding = FALSE; } - if (holding < 1){ - holdWait = 8000; - } else if (holding < 150) { - holdWait = 9960; + if (holding == 0){ + holdWait = -5000; + } else if (holding < 100) { + holdWait = 4200; } else { - holdWait = 9990; + holdWait = 5000; } antiDouble = -1; - if (isHolding || holding > -1){ - for (int i = 0; i < 10000000 - (holdWait * 1000); i++){ - io_wait(); - } + for (int i = 0; i < 550000 - (holdWait * 100); i++){ + io_wait(); } } } From 2a7ba35062877a2a6b9c1990176782a330b1c35e Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 30 Mar 2023 22:46:51 +0700 Subject: [PATCH 066/176] Ultraman Cosmos --- src/fat32.c | 39 +++++++++++++++++++++++++++------------ src/lib-header/fat32.h | 26 +++++++++++++++++++++----- src/lib-header/portio.h | 5 +++++ src/portio.c | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 8c076be..08a315d 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -1,12 +1,15 @@ #include "lib-header/stdtype.h" #include "lib-header/fat32.h" #include "lib-header/stdmem.h" +#include "lib-header/portio.h" // static struct ClusterBuffer clusterBuffer; // static struct FAT32FileAllocationTable fat_table; // static struct FAT32DirectoryEntry root_dir_entry; // static struct FAT32DirectoryTable root_dir_table; struct FAT32DriverState driver_state; +struct Time time; +struct Date date; // static struct FAT32DriverRequest driver_request; @@ -69,12 +72,15 @@ uint32_t cluster_to_lba(uint32_t cluster){ */ void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ // dir_table->table[0].name[0] = '.'; + get_time(&time, &date); dir_table->table[0].cluster_high = (uint16_t)(parent_dir_cluster >> 16); dir_table->table[0].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); for (uint8_t i = 0; i < 8; i++){ dir_table->table[0].name[i] = name[i]; } dir_table->table[0].user_attribute = UATTR_NOT_EMPTY; + dir_table->table[0].create_date = date; + dir_table->table[0].create_time = time; // dir_table->table[1].name[0] = '.'; @@ -183,7 +189,10 @@ int8_t read_directory(struct FAT32DriverRequest request){ return 1; } location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; - read_clusters(request.buf + CLUSTER_SIZE, location, 1); + get_time(&time, &date); + driver_state.dir_table_buf.table[i].access_date = date; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); + read_clusters(request.buf, location, 1); break; } } @@ -222,6 +231,9 @@ int8_t read(struct FAT32DriverRequest request){ location = driver_state.fat_table.cluster_map[location]; } } + get_time(&time, &date); + driver_state.dir_table_buf.table[i].access_date = date; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } break; } @@ -260,10 +272,8 @@ int8_t write(struct FAT32DriverRequest request){ driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; write_clusters(driver_state.fat_table.cluster_map,1,1); - struct FAT32DirectoryTable new_dir = {0}; init_directory_table(&new_dir, request.name, cluster); - write_clusters(new_dir.table, cluster, 1); cluster_table = 0; @@ -272,8 +282,10 @@ int8_t write(struct FAT32DriverRequest request){ while (driver_state.dir_table_buf.table[cluster_table].user_attribute == UATTR_NOT_EMPTY){ cluster_table++; // Ini index } - driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; + get_time(&time, &date); + driver_state.dir_table_buf.table[0].modified_date = date; + driver_state.dir_table_buf.table[0].modified_time = time; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); @@ -328,7 +340,11 @@ int8_t write(struct FAT32DriverRequest request){ write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); write_clusters(driver_state.fat_table.cluster_map,1,1); } - + get_time(&time, &date); + driver_state.dir_table_buf.table[cluster_table].create_date = date; + driver_state.dir_table_buf.table[cluster_table].create_time = time; + driver_state.dir_table_buf.table[0].modified_date = date; + driver_state.dir_table_buf.table[0].modified_time = time; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } @@ -372,13 +388,9 @@ int8_t delete(struct FAT32DriverRequest request){ } driver_state.dir_table_buf.table[index] = temp_ent; driver_state.fat_table.cluster_map[location] = 0; - // for (int i = 0; i < 64; i++){ - // if (memcmp(driver_state.dir_table_buf.table[i].name, request.name, 8) == 0){ - // location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; - - // break; - // } - // } + get_time(&time, &date); + driver_state.dir_table_buf.table[0].modified_time = time; + driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.fat_table.cluster_map,1,1); write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); @@ -401,6 +413,9 @@ int8_t delete(struct FAT32DriverRequest request){ } } while (!flag); write_clusters(driver_state.fat_table.cluster_map,1,1); + get_time(&time, &date); + driver_state.dir_table_buf.table[0].modified_time = time; + driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); return 0; } diff --git a/src/lib-header/fat32.h b/src/lib-header/fat32.h index 54137b3..5b0ca19 100644 --- a/src/lib-header/fat32.h +++ b/src/lib-header/fat32.h @@ -57,6 +57,22 @@ struct FAT32FileAllocationTable { uint32_t cluster_map[CLUSTER_MAP_SIZE]; } __attribute__((packed)); + + +struct Time { + uint8_t jam; + uint8_t menit; + uint8_t detik; +} __attribute__((packed)); + +struct Date { + uint8_t tanggal; + uint8_t bulan; + uint8_t tahun; +} __attribute__((packed)); + + + /** * FAT32 standard 8.3 format - 32 bytes DirectoryEntry, Some detail can be found at: * https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Directory_entry, and click show table. @@ -84,13 +100,13 @@ struct FAT32DirectoryEntry { uint8_t user_attribute; bool undelete; - uint16_t create_time; - uint16_t create_date; - uint16_t access_date; + struct Time create_time; + struct Date create_date; + struct Date access_date; uint16_t cluster_high; - uint16_t modified_time; - uint16_t modified_date; + struct Time modified_time; + struct Date modified_date; uint16_t cluster_low; uint32_t filesize; } __attribute__((packed)); diff --git a/src/lib-header/portio.h b/src/lib-header/portio.h index 5610ddd..efd069c 100644 --- a/src/lib-header/portio.h +++ b/src/lib-header/portio.h @@ -2,6 +2,7 @@ #define _PORTIO_H #include "stdtype.h" +#include "fat32.h" /** out: * Sends the given data to the given I/O port @@ -23,4 +24,8 @@ uint16_t in16(uint16_t port); void out16(uint16_t port, uint16_t data); +void get_time(struct Time *time, struct Date *date); + +uint8_t cmos_read(uint8_t reg); + #endif \ No newline at end of file diff --git a/src/portio.c b/src/portio.c index e3a285f..6f3855d 100644 --- a/src/portio.c +++ b/src/portio.c @@ -1,5 +1,6 @@ #include "lib-header/stdtype.h" #include "lib-header/portio.h" +#include "lib-header/fat32.h" /** x86 inb/outb: * @param dx target port @@ -40,4 +41,42 @@ uint16_t in16(uint16_t port) { : "Nd"(port) ); return result; -} \ No newline at end of file +} + +uint8_t cmos_read(uint8_t reg) { + __asm__ volatile ( + "outb %0, %1" + : + : "a"(reg), "Nd"(0x70)); + uint8_t data; + __asm__ volatile ( + "inb %1, %0" + : "=a"(data) + : "Nd"(0x71)); + return data; +} + +void get_time(struct Time *time, struct Date *date) { + // Read the current time from the CMOS registers + uint8_t jam_cmos = cmos_read(0x04); + uint8_t menit_cmos = cmos_read(0x02); + uint8_t detik_cmos = cmos_read(0x00); + uint8_t tanggal_cmos = cmos_read(0x07); + uint8_t bulan_cmos = cmos_read(0x08); + uint8_t tahun_cmos = cmos_read(0x09); + + // Convert BCD values to decimal + time->jam = ((jam_cmos & 0x0F) + ((jam_cmos >> 4) * 10)); + time->menit = ((menit_cmos & 0x0F) + ((menit_cmos >> 4) * 10)); + time->detik = ((detik_cmos & 0x0F) + ((detik_cmos >> 4) * 10)); + date->tanggal = ((tanggal_cmos & 0x0F) + ((tanggal_cmos >> 4) * 10)); + date->bulan = ((bulan_cmos & 0x0F) + ((bulan_cmos >> 4) * 10)); + date->tahun = ((tahun_cmos & 0x0F) + ((tahun_cmos >> 4) * 10)); + +} + + + + + + From a71feb8df5876a376abbae38d0eac1e2d668e4c1 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:16:18 +0700 Subject: [PATCH 067/176] feat: add altF4 mechanism --- src/lib-header/keyboard.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index f29c4a8..b9ba489 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -14,6 +14,8 @@ #define KEYBOARD_BUFFER_SIZE 256 +bool altF4(); + /** * keyboard_scancode_1_to_ascii_map[256], Convert scancode values that correspond to ASCII printables * How to use this array: ascii_char = k[scancode] From 9c0952cdf9831f4f1cb81dad9325d4478b0962d1 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:16:57 +0700 Subject: [PATCH 068/176] feat: add capslock setup mechanism --- src/keyboard.c | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 80f0efa..08f4b08 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -7,6 +7,8 @@ static int row = 0; static char antiDouble = -1; static int holding = 0; static char charHold = -1; +static bool altFour = FALSE; + static int backspaceLine[25] = { 0,0,0,0,0, 0,0,0,0,0, @@ -29,7 +31,7 @@ const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; @@ -58,6 +60,10 @@ bool is_keyboard_blocking(void){ return keyboard_state.keyboard_input_on; } +bool altF4(){ + return altFour; +} + /* -- Keyboard Interrupt Service Routine -- */ @@ -73,6 +79,8 @@ bool is_keyboard_blocking(void){ * after calling `keyboard_state_activate();` */ void keyboard_isr(void) { + bool capslock = FALSE; + bool shifted = FALSE; int16_t holdWait = 0; if (!keyboard_state.keyboard_input_on){ keyboard_state.buffer_index = 0; @@ -82,8 +90,11 @@ void keyboard_isr(void) { while (is_keyboard_blocking()){ uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + if (mapped_char != antiDouble){ antiDouble = mapped_char; + + /* Backspace */ if (mapped_char == '\b') { if (keyboard_state.buffer_index) { keyboard_state.buffer_index--; @@ -98,7 +109,10 @@ void keyboard_isr(void) { } framebuffer_write(row, keyboard_state.buffer_index, 0, 0x0c, 0); framebuffer_set_cursor(row, keyboard_state.buffer_index); - } else if (mapped_char=='\n') { + } + + /* Enter (deactivate keyboard) */ + else if (mapped_char=='\n') { keyboard_state.buffer_index=0; keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = 0; framebuffer_set_cursor(row + 1, keyboard_state.buffer_index); @@ -109,8 +123,26 @@ void keyboard_isr(void) { row++; } keyboard_state_deactivate(); - } else if (mapped_char !=0){ + } + + + /* Normal Write */ + else if (mapped_char !=0){ + if (capslock && !shifted){ // hanya capslock + if (mapped_char >= 'a' && mapped_char <= 'z'){ + mapped_char -= 32; + } + } else if (!capslock && shifted){ // hanya shift + if (mapped_char >= 'a' && mapped_char <= 'z'){ + mapped_char -= 32; + } + } else if (capslock && shifted){ // capslock dan shift + if (mapped_char >= 'A' && mapped_char <= 'Z'){ + mapped_char += 32; + } + } framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); + if (keyboard_state.buffer_index >= 79){ if (row >= 24) { row = 24; @@ -151,7 +183,7 @@ void keyboard_isr(void) { } antiDouble = -1; - for (int i = 0; i < 550000 - (holdWait * 100); i++){ + for (int i = 0; i < 600000 - (holdWait * 100); i++){ io_wait(); } } @@ -159,4 +191,3 @@ void keyboard_isr(void) { } pic_ack(IRQ_KEYBOARD); } - From 26db53856610cfd04bee4e5618fbb0e71c127792 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:17:39 +0700 Subject: [PATCH 069/176] feat: add up left down right mechanism --- src/keyboard.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/keyboard.c b/src/keyboard.c index 08f4b08..18a4a24 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -125,7 +125,52 @@ void keyboard_isr(void) { keyboard_state_deactivate(); } + /* Up Arrow (no holding) */ + else if (scancode == 0x48){ + if (row > 0){ + row--; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode != 0xc8); + } + } + + /* Down Arrow (no holding) */ + else if (scancode == 0x50){ + if (row < 24){ + row++; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode != 0xd0); + } + } + /* Left Arrow (no holding) */ + else if (scancode == 0x4b){ + if (keyboard_state.buffer_index > 0){ + keyboard_state.buffer_index--; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode != 0xcb); + } + } + + /* Right Arrow (no holding) */ + else if (scancode == 0x4d){ + if (keyboard_state.buffer_index < 79){ + keyboard_state.buffer_index++; + framebuffer_set_cursor(row, keyboard_state.buffer_index); + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode != 0xcd); + } + } + + + /* Normal Write */ else if (mapped_char !=0){ if (capslock && !shifted){ // hanya capslock From c2022717b2d48dba5e5487e4de3992122cd367bc Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:18:08 +0700 Subject: [PATCH 070/176] feat: add capslock keyboard mechanism --- src/keyboard.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 18a4a24..5776852 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -169,7 +169,15 @@ void keyboard_isr(void) { } } - + /* Caps Lock */ + else if (scancode == 0x3A){ + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode != 0xBA); + capslock = !capslock; + } + + /* Normal Write */ else if (mapped_char !=0){ From 7840428b930f0746855b1f967b1b0fd7a5722a0f Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:18:41 +0700 Subject: [PATCH 071/176] feat: add hold shift and release shift mechanism --- src/keyboard.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 5776852..8f81781 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -177,8 +177,26 @@ void keyboard_isr(void) { capslock = !capslock; } - + /* Shift */ + else if (scancode == 0x2A || scancode == 0x36){ + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x2A || scancode == 0x36); + if (scancode == 0xAA || scancode == 0xB6){ + continue; + } else { + shifted = TRUE; + mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + } + } + + /* Release shift */ + else if (scancode == 0xAA || scancode == 0xB6){ + shifted = FALSE; + } + + /* Normal Write */ else if (mapped_char !=0){ if (capslock && !shifted){ // hanya capslock From fc49a347caf67987a7d4a641af1d2106074e103f Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:19:35 +0700 Subject: [PATCH 072/176] feat: add Home and End keyboard mechanism --- src/keyboard.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 8f81781..503f880 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -196,7 +196,25 @@ void keyboard_isr(void) { shifted = FALSE; } - + + /* Home */ + else if (scancode == 0x47){ + framebuffer_set_cursor(row, 0); + keyboard_state.buffer_index = 0; + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x47); + } + + /* End */ + else if (scancode == 0x4F){ + framebuffer_set_cursor(row, 79); + keyboard_state.buffer_index = 79; + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x4F); + } + /* Normal Write */ else if (mapped_char !=0){ if (capslock && !shifted){ // hanya capslock From 064320927ef007ab0ad140ed81f70dc19208e0c9 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:20:12 +0700 Subject: [PATCH 073/176] feat: add Alt keyboard mechanism --- src/keyboard.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/keyboard.c b/src/keyboard.c index 503f880..98dd794 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -196,6 +196,19 @@ void keyboard_isr(void) { shifted = FALSE; } + + + /* Alt */ + else if (scancode == 0x38){ // alt + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x38); + + /* alt f4 */ + if (scancode == 0x3E){ + altFour = TRUE; + } + } /* Home */ else if (scancode == 0x47){ From ad4ca1a582afcb67e7925880bed895bc56624093 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:20:36 +0700 Subject: [PATCH 074/176] feat: add Ctrl keyboard mechanism --- src/keyboard.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 98dd794..795dd45 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -196,7 +196,27 @@ void keyboard_isr(void) { shifted = FALSE; } - + /* ctrl */ + else if (scancode == 0x1D){ // ctrl + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x1D); + + scancode = in(KEYBOARD_DATA_PORT); + /* Ctrl Home */ + if (scancode == 0x47){ + framebuffer_set_cursor(0, 0); + keyboard_state.buffer_index = 0; + row = 0; + } + + /* Ctrl End */ + else if (scancode == 0x4F){ + framebuffer_set_cursor(24, 79); + keyboard_state.buffer_index = 79; + row = 24; + } + } /* Alt */ else if (scancode == 0x38){ // alt From a836167a5f971cd34f8d0674da9b6357a7e723e7 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 30 Mar 2023 23:33:16 +0700 Subject: [PATCH 075/176] cosmosss --- src/portio.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/portio.c b/src/portio.c index 6f3855d..eca19a9 100644 --- a/src/portio.c +++ b/src/portio.c @@ -44,20 +44,12 @@ uint16_t in16(uint16_t port) { } uint8_t cmos_read(uint8_t reg) { - __asm__ volatile ( - "outb %0, %1" - : - : "a"(reg), "Nd"(0x70)); - uint8_t data; - __asm__ volatile ( - "inb %1, %0" - : "=a"(data) - : "Nd"(0x71)); - return data; + // 0x70 port out, 0x71 port in + out(0x70,reg); + return in(0x71); } void get_time(struct Time *time, struct Date *date) { - // Read the current time from the CMOS registers uint8_t jam_cmos = cmos_read(0x04); uint8_t menit_cmos = cmos_read(0x02); uint8_t detik_cmos = cmos_read(0x00); @@ -65,7 +57,7 @@ void get_time(struct Time *time, struct Date *date) { uint8_t bulan_cmos = cmos_read(0x08); uint8_t tahun_cmos = cmos_read(0x09); - // Convert BCD values to decimal + // Convert BCD time->jam = ((jam_cmos & 0x0F) + ((jam_cmos >> 4) * 10)); time->menit = ((menit_cmos & 0x0F) + ((menit_cmos >> 4) * 10)); time->detik = ((detik_cmos & 0x0F) + ((detik_cmos >> 4) * 10)); From d8aa2ec66bcd5c015a6b0eef82c60f1716b799a0 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:36:04 +0700 Subject: [PATCH 076/176] feat: add folder structure --- src/kernel.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index 565c7fe..ec3c038 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -13,6 +13,17 @@ void write_splash_screen3(); +/* Struktur folder * + * ROOT + * ikanaide + * kanol + * daijoubu + * perusak + * BRO + * brother + * b420 + * destroys + */ void kernel_setup(void) { /* Enter protected mode */ @@ -173,8 +184,12 @@ void kernel_setup(void) { /* Buat unused variable saja */ debug01 += debug02 + debug03; write_splash_screen3(); - while (TRUE) { + while (TRUE && !altF4()) { keyboard_state_activate(); + if (restoreSplashScreen()) { + write_splash_screen3(); + + } } } From fdcc0e3d89274f8efb37603dde9dd6ca7b0d9586 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Thu, 30 Mar 2023 23:36:49 +0700 Subject: [PATCH 077/176] feat: add restoreSplashScreen as Ctrl + Enter --- src/keyboard.c | 17 ++++++++++++++++- src/lib-header/keyboard.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index 795dd45..ec4e3ae 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -8,6 +8,7 @@ static char antiDouble = -1; static int holding = 0; static char charHold = -1; static bool altFour = FALSE; +static bool restoreSplash = FALSE; static int backspaceLine[25] = { 0,0,0,0,0, @@ -64,6 +65,10 @@ bool altF4(){ return altFour; } +bool restoreSplashScreen(){ + return restoreSplash; +} + /* -- Keyboard Interrupt Service Routine -- */ @@ -90,6 +95,7 @@ void keyboard_isr(void) { while (is_keyboard_blocking()){ uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + restoreSplash = FALSE; if (mapped_char != antiDouble){ antiDouble = mapped_char; @@ -209,7 +215,16 @@ void keyboard_isr(void) { keyboard_state.buffer_index = 0; row = 0; } - + + /* Ctrl Enter (restore splash screen)*/ + else if (scancode == 0x1C){ + framebuffer_set_cursor(0, 0); + keyboard_state.buffer_index = 0; + row = 0; + restoreSplash = TRUE; + keyboard_state_deactivate(); + } + /* Ctrl End */ else if (scancode == 0x4F){ framebuffer_set_cursor(24, 79); diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index b9ba489..c84098d 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -16,6 +16,8 @@ bool altF4(); +bool restoreSplashScreen(); + /** * keyboard_scancode_1_to_ascii_map[256], Convert scancode values that correspond to ASCII printables * How to use this array: ascii_char = k[scancode] From 26014ca3121da57b49c06db628938e76fde9fcc2 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Thu, 30 Mar 2023 23:42:33 +0700 Subject: [PATCH 078/176] chizuru is the best waifu undebateable --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index f0e8351..fa2b0f9 100644 --- a/makefile +++ b/makefile @@ -33,7 +33,7 @@ build: iso clean: rm -rf *.o *.iso $(OUTPUT_FOLDER)/kernel -kernel:disk +kernel: @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/kernel_loader.s -o $(OUTPUT_FOLDER)/kernel_loader.o @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/intsetup.s -o $(OUTPUT_FOLDER)/intsetup.o $(foreach file, $(wildcard $(SOURCE_FOLDER)/*.c), $(CC) $(CFLAGS) $(file) -o $(OUTPUT_FOLDER)/$(notdir $(file:.c=.o));) From fdf05882fbba737afe7147e4908f149cf951d922 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 18:32:37 +0700 Subject: [PATCH 079/176] feat: add set up for kernel.h (TODO struct) --- src/lib-header/paging.h | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/lib-header/paging.h diff --git a/src/lib-header/paging.h b/src/lib-header/paging.h new file mode 100644 index 0000000..53ba0ff --- /dev/null +++ b/src/lib-header/paging.h @@ -0,0 +1,93 @@ +#ifndef _PAGING_H +#define _PAGING_H + +#include "stdtype.h" + +#define PAGE_ENTRY_COUNT 1024 +#define PAGE_FRAME_SIZE (4*1024*1024) + +// Operating system page directory, using page size PAGE_FRAME_SIZE (4 MiB) +extern struct PageDirectory _paging_kernel_page_directory; + + + + +/** + * Page Directory Entry Flag, only first 8 bit + * + * @param present_bit Indicate whether this entry is exist or not + * ... + */ +struct PageDirectoryEntryFlag { + uint8_t present_bit : 1; + // TODO : Continue. Note: Only first 8 bit flags +} __attribute__((packed)); + +/** + * Page Directory Entry, for page size 4 MB. + * Check Intel Manual 3a - Ch 4 Paging - Figure 4-4 PDE: 4MB page + * + * @param flag Contain 8-bit page directory entry flag + * @param global_page Is this page translation global (also cannot be flushed) + * ... + */ +struct PageDirectoryEntry { + struct PageDirectoryEntryFlag flag; + uint16_t global_page : 1; + // TODO : Continue, Use uint16_t + bitfield here, Do not use uint8_t +} __attribute__((packed)); + +/** + * Page Directory, contain array of PageDirectoryEntry. + * Note: This data structure not only can be manipulated by kernel, + * MMU operation, TLB hit & miss also affecting this data structure (dirty, accessed bit, etc). + * Warning: Address must be aligned in 4 KB (listed on Intel Manual), use __attribute__((aligned(0x1000))), + * unaligned definition of PageDirectory will cause triple fault + * + * @param table Fixed-width array of PageDirectoryEntry with size PAGE_ENTRY_COUNT + */ +struct PageDirectory { + // TODO : Implement +} __attribute__((packed)); + +/** + * Containing page driver states + * + * @param last_available_physical_addr Pointer to last empty physical addr (multiple of 4 MiB) + */ +struct PageDriverState { + uint8_t *last_available_physical_addr; +} __attribute__((packed)); + + + + + +/** + * update_page_directory, + * Edit _paging_kernel_page_directory with respective parameter + * + * @param physical_addr Physical address to map + * @param virtual_addr Virtual address to map + * @param flag Page entry flags + */ +void update_page_directory(void *physical_addr, void *virtual_addr, struct PageDirectoryEntryFlag flag); + +/** + * flush_single_tlb, + * invalidate page that contain virtual address in parameter + * + * @param virtual_addr Virtual address to flush + */ +void flush_single_tlb(void *virtual_addr); + +/** + * Allocate user memory into specified virtual memory address. + * Multiple call on same virtual address will unmap previous physical address and change it into new one. + * + * @param virtual_addr Virtual address to be mapped + * @return int8_t 0 success, -1 for failed allocation + */ +int8_t allocate_single_user_page_frame(void *virtual_addr); + +#endif \ No newline at end of file From 984a77a7ef7cf760e156a85f4755c4902df17f4e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 18:33:59 +0700 Subject: [PATCH 080/176] feat: add paging setup (TODO alloc page direc entr --- src/paging.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/paging.c diff --git a/src/paging.c b/src/paging.c new file mode 100644 index 0000000..ee15558 --- /dev/null +++ b/src/paging.c @@ -0,0 +1,43 @@ + +#include "lib-header/paging.h" + +__attribute__((aligned(0x1000))) struct PageDirectory _paging_kernel_page_directory = { + .table = { + [0] = { + .flag.present_bit = 1, + .flag.write_bit = 1, + .lower_address = 0, + .flag.use_pagesize_4_mb = 1, + }, + [0x300] = { + .flag.present_bit = 1, + .flag.write_bit = 1, + .lower_address = 0, + .flag.use_pagesize_4_mb = 1, + }, + } +}; + +static struct PageDriverState page_driver_state = { + .last_available_physical_addr = (uint8_t*) 0 + PAGE_FRAME_SIZE, +}; + +void update_page_directory_entry(void *physical_addr, void *virtual_addr, struct PageDirectoryEntryFlag flag) { + uint32_t page_index = ((uint32_t) virtual_addr >> 22) & 0x3FF; + + _paging_kernel_page_directory.table[page_index].flag = flag; + _paging_kernel_page_directory.table[page_index].lower_address = ((uint32_t)physical_addr >> 22) & 0x3FF; + flush_single_tlb(virtual_addr); +} + +int8_t allocate_single_user_page_frame(void *virtual_addr) { + // Using default QEMU config (128 MiB max memory) + uint32_t last_physical_addr = (uint32_t) page_driver_state.last_available_physical_addr; + + // TODO : Allocate Page Directory Entry with user privilege + return -1; +} + +void flush_single_tlb(void *virtual_addr) { + asm volatile("invlpg (%0)" : /* */ : "b"(virtual_addr): "memory"); +} \ No newline at end of file From 52acf6da60abb363ef82378fb2b4b51b1a391a00 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 18:34:23 +0700 Subject: [PATCH 081/176] feat: add update for kernel_loader from kit --- src/kernel_loader.s | 97 ++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/src/kernel_loader.s b/src/kernel_loader.s index 6df0408..16ba590 100644 --- a/src/kernel_loader.s +++ b/src/kernel_loader.s @@ -1,58 +1,89 @@ -global loader ; the entry symbol for ELF -global enter_protected_mode ; go to protected mode -extern kernel_setup ; kernel +global loader ; the entry symbol for ELF +global enter_protected_mode ; go to protected mode +global set_tss_register ; set tss register to GDT entry +extern kernel_setup ; kernel C entrypoint +extern _paging_kernel_page_directory ; kernel page directory +KERNEL_VIRTUAL_BASE equ 0xC0000000 ; kernel virtual memory +KERNEL_STACK_SIZE equ 2097152 ; size of stack in bytes +MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant +FLAGS equ 0x0 ; multiboot flags +CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum + ; (magic number + checksum + flags should equal 0) -KERNEL_STACK_SIZE equ 2097152 ; size of stack in bytes -MAGIC_NUMBER equ 0x1BADB002 ; define the magic number constant -FLAGS equ 0x0 ; multiboot flags -CHECKSUM equ -MAGIC_NUMBER ; calculate the checksum - ; (magic number + checksum + flags should equal 0) - section .bss -align 4 ; align at 4 bytes -kernel_stack: ; label points to beginning of memory - resb KERNEL_STACK_SIZE ; reserve stack for the kernel +align 4 ; align at 4 bytes +kernel_stack: ; label points to beginning of memory + resb KERNEL_STACK_SIZE ; reserve stack for the kernel -section .multiboot ; start of the text (code) section -align 4 ; the code must be 4 byte aligned - dd MAGIC_NUMBER ; write the magic number to the machine code, - dd FLAGS ; the flags, - dd CHECKSUM ; and the checksum +section .multiboot ; GRUB multiboot header +align 4 ; the code must be 4 byte aligned + dd MAGIC_NUMBER ; write the magic number to the machine code, + dd FLAGS ; the flags, + dd CHECKSUM ; and the checksum -section .text -loader: ; the loader label (defined as entry point in linker script) - mov esp, kernel_stack + KERNEL_STACK_SIZE ; setup stack register to proper location + + +section .setup.text ; start of the text (code) section +loader equ (loader_entrypoint - KERNEL_VIRTUAL_BASE) +loader_entrypoint: ; the loader label (defined as entry point in linker script) + ; Set CR3 (CPU page register) + mov eax, _paging_kernel_page_directory - KERNEL_VIRTUAL_BASE + mov cr3, eax + + ; Use 4 MB paging + mov eax, cr4 + or eax, 0x00000010 ; PSE (4 MB paging) + mov cr4, eax + + ; Enable paging + mov eax, cr0 + or eax, 0x80000000 ; PG flag + mov cr0, eax + + ; Jump into higher half first, cannot use C because call stack is still not working + lea eax, [loader_virtual] + jmp eax + +loader_virtual: + mov dword [_paging_kernel_page_directory], 0 + invlpg [0] ; Delete identity mapping and invalidate TLB cache for first page + mov esp, kernel_stack + KERNEL_STACK_SIZE ; Setup stack register to proper location call kernel_setup .loop: - jmp .loop ; loop forever + jmp .loop ; loop forever + +section .text ; More details: https://en.wikibooks.org/wiki/X86_Assembly/Protected_Mode enter_protected_mode: + ; Load GDT from GDTDescriptor cli - mov eax, [esp+4] + mov eax, [esp+4] lgdt [eax] - ; TODO: Load GDT from GDTDescriptor - ; eax at this line will carry GDTR location, dont forget to use square bracket [eax] - + + ; Set Protection Enable bit-flag in Control Register 0 (CR0) + ; Or in other words: Switch to protected mode mov eax, cr0 - or eax, 0x1 ; Set the protection enable bit in eax - ; TODO: Set bit-0 (Protection Enable bit-flag) in Control Register 0 (CR0) - ; Set eax with above condition, eax will be copied to CR0 with next instruction + or eax, 1 mov cr0, eax ; Far jump to update cs register ; Warning: Invalid GDT will raise exception in any instruction below jmp 0x8:flush_cs flush_cs: - mov ax, 10h - mov ds, ax ; Set the data segment register DS - mov es, ax ; Set the data segment register ES ; Set the stack segment register SS - ; TODO: Set all data segment register with 0x10 - ; Segments register need to set with 0x10: ss, ds, es + ; Update all segment register + mov ax, 10h mov ss, ax + mov ds, ax + mov es, ax + + ret +set_tss_register: + mov ax, 0x28 | 0 ; GDT TSS Selector, ring 0 + ltr ax ret From fda0914c03ab052d022b1654aa2658d1a1e83b3e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 18:34:37 +0700 Subject: [PATCH 082/176] feat: add update for linker from guidebook --- src/linker.ld | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/linker.ld b/src/linker.ld index d6b81ab..fab9110 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -1,31 +1,45 @@ ENTRY(loader) /* the name of the entry label */ +/* relocation on address at 0xC001 0000, but load address (physical location) still at 0x100000 */ SECTIONS { - . = 0x00100000; /* the code should be loaded at 1 MB */ + . = 0xC0100000; /* use relocation address (memory references) at 0xC010 0000 */ - .multiboot : + /* Optional variable that can be used in kernel, starting address of kernel */ + _linker_kernel_virtual_addr_start = .; + _linker_kernel_physical_addr_start = . - 0xC0000000; + .multiboot ALIGN (0x1000) : AT (ADDR (.multiboot) - 0xC0000000) { - *(.multiboot) + *(.multiboot) /* put GRUB multiboot header at front */ } - .text ALIGN (0x1000) : /* align at 4 KB */ + .setup.text ALIGN (0x1000) : AT (ADDR (.setup.text) - 0xC0000000) + { + *(.setup.text) /* initial setup code */ + } + + .text ALIGN (0x1000) : AT (ADDR (.text) - 0xC0000000) { *(.text) /* all text sections from all files */ } - .rodata ALIGN (0x1000) : /* align at 4 KB */ + .rodata ALIGN (0x1000) : AT (ADDR (.rodata) - 0xC0000000) { *(.rodata*) /* all read-only data sections from all files */ } - .data ALIGN (0x1000) : /* align at 4 KB */ + .data ALIGN (0x1000) : AT (ADDR (.data) - 0xC0000000) { *(.data) /* all data sections from all files */ } - .bss ALIGN (0x1000) : /* align at 4 KB */ + .bss ALIGN (0x1000) : AT (ADDR (.bss) - 0xC0000000) { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ + kernel_loader.o(.bss) + _linker_kernel_stack_top = .; } + /* Optional variable that can be used in kernel, show end address of kernel */ + _linker_kernel_virtual_addr_end = .; + _linker_kernel_physical_addr_end = . - 0xC0000000; } From c27a5449d017ffc26191824728b0981896ff8d14 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 21:39:46 +0700 Subject: [PATCH 083/176] fix: change kernel_loader.o(.bss) --- src/linker.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linker.ld b/src/linker.ld index fab9110..78897f2 100644 --- a/src/linker.ld +++ b/src/linker.ld @@ -36,7 +36,7 @@ SECTIONS { { *(COMMON) /* all COMMON sections from all files */ *(.bss) /* all bss sections from all files */ - kernel_loader.o(.bss) + bin/kernel_loader.o(.bss) _linker_kernel_stack_top = .; } /* Optional variable that can be used in kernel, show end address of kernel */ From 5267e2997ce48f5ced40527de5848c869ca781d1 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 21:40:17 +0700 Subject: [PATCH 084/176] fix: change MEMORY_FRAMEBUFFER --- src/lib-header/framebuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib-header/framebuffer.h b/src/lib-header/framebuffer.h index c782ea1..d07b533 100644 --- a/src/lib-header/framebuffer.h +++ b/src/lib-header/framebuffer.h @@ -4,7 +4,7 @@ #include "stdtype.h" -#define MEMORY_FRAMEBUFFER (uint8_t *) 0xB8000 +#define MEMORY_FRAMEBUFFER (uint8_t *) 0xC00B8000 #define CURSOR_PORT_CMD 0x03D4 #define CURSOR_PORT_DATA 0x03D5 From 3e97222276025e756533ea66ac677768aa8861aa Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 21:41:09 +0700 Subject: [PATCH 085/176] feat!: ALL struct implement needed for paging --- src/lib-header/paging.h | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/lib-header/paging.h b/src/lib-header/paging.h index 53ba0ff..03222ff 100644 --- a/src/lib-header/paging.h +++ b/src/lib-header/paging.h @@ -16,10 +16,25 @@ extern struct PageDirectory _paging_kernel_page_directory; * Page Directory Entry Flag, only first 8 bit * * @param present_bit Indicate whether this entry is exist or not - * ... + * @param write_bit Read/write; if 0, writes may not be allowed to the 4-MByte page referenced by this entry + * @param userOrSupervisor User/supervisor; if 0, user-mode accesses are not allowed to the 4-MByte page referenced by this entry + * @param PWT Page-level write-through; indirectly determines the memory type used to access the 4-MByte page referenced by this entry + * @param PCD Page-level cache disable; indirectly determines the memory type used to access the 4-MByte page referenced by this entry + * @param accessed_bit Indicates whether software has accessed the 4-MByte page referenced by this entry + * @param dirty_bit Indicates whether software has written to the 4-MByte page referenced by this entry + * @param page_size Must be 1 to indicate a 4-MByte page + * */ -struct PageDirectoryEntryFlag { - uint8_t present_bit : 1; +struct PageDirectoryEntryFlag { + uint8_t present_bit : 1; + uint8_t write_bit : 1; + uint8_t userOrSupervisor : 1; + uint8_t PWT : 1; + uint8_t PCD : 1; + uint8_t accessed_bit : 1; + uint8_t dirty_bit : 1; + uint8_t use_pagesize_4_mb : 1; + // TODO : Continue. Note: Only first 8 bit flags } __attribute__((packed)); @@ -29,11 +44,21 @@ struct PageDirectoryEntryFlag { * * @param flag Contain 8-bit page directory entry flag * @param global_page Is this page translation global (also cannot be flushed) - * ... + * @param ignored Ignored + * @param PAT If the PAT is supported, indirectly determines the memory type used to access the 4-MByte page referenced by this entry + * @param lower_address ?????????????????????????? + * @param reserved Reserved tulisan di tabel itu must be 0 + * @param page_frame_4mb Bits 31:22 of physical address of the 4-MByte page referenced by this entry */ struct PageDirectoryEntry { struct PageDirectoryEntryFlag flag; uint16_t global_page : 1; + uint16_t ignored : 3; + uint16_t PAT : 1; + uint16_t lower_address : 4; // Agak bingung di tabel intel manual, ini apa? + uint16_t reserved : 5; + uint16_t page_frame_4mb : 10; + // TODO : Continue, Use uint16_t + bitfield here, Do not use uint8_t } __attribute__((packed)); @@ -48,6 +73,7 @@ struct PageDirectoryEntry { */ struct PageDirectory { // TODO : Implement + struct PageDirectoryEntry table[PAGE_ENTRY_COUNT]; } __attribute__((packed)); /** From f06ed64fcc55d056ddef73dc3fe514dc538410ae Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 31 Mar 2023 21:42:11 +0700 Subject: [PATCH 086/176] feat: implement allocate_supf; how cek bener salh? --- src/paging.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/paging.c b/src/paging.c index ee15558..7e42eca 100644 --- a/src/paging.c +++ b/src/paging.c @@ -33,7 +33,22 @@ void update_page_directory_entry(void *physical_addr, void *virtual_addr, struct int8_t allocate_single_user_page_frame(void *virtual_addr) { // Using default QEMU config (128 MiB max memory) uint32_t last_physical_addr = (uint32_t) page_driver_state.last_available_physical_addr; - + + struct PageDirectoryEntryFlag flag = { + .present_bit = 1, + .write_bit = 1, + .userOrSupervisor = 1, + .use_pagesize_4_mb = 1 + }; + + if (last_physical_addr >= 32 * PAGE_FRAME_SIZE) { + return -1; + } else { + update_page_directory_entry((void*) last_physical_addr, virtual_addr, flag); + page_driver_state.last_available_physical_addr += PAGE_FRAME_SIZE; + return 0; + } + // TODO : Allocate Page Directory Entry with user privilege return -1; } From 9ad32262ea39d1eaa6542777838176e402853f12 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 14:20:23 +0700 Subject: [PATCH 087/176] fix: PageDirectory --- src/lib-header/paging.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib-header/paging.h b/src/lib-header/paging.h index 03222ff..0f06ea4 100644 --- a/src/lib-header/paging.h +++ b/src/lib-header/paging.h @@ -55,7 +55,7 @@ struct PageDirectoryEntry { uint16_t global_page : 1; uint16_t ignored : 3; uint16_t PAT : 1; - uint16_t lower_address : 4; // Agak bingung di tabel intel manual, ini apa? + uint16_t lower_address : 4; uint16_t reserved : 5; uint16_t page_frame_4mb : 10; @@ -73,7 +73,7 @@ struct PageDirectoryEntry { */ struct PageDirectory { // TODO : Implement - struct PageDirectoryEntry table[PAGE_ENTRY_COUNT]; + struct PageDirectoryEntry table[PAGE_ENTRY_COUNT] __attribute__((aligned(0x1000))); } __attribute__((packed)); /** From 4f7ce449479ca2017f5e0fde9ffee25776b36906 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 14:21:12 +0700 Subject: [PATCH 088/176] feat: add kernel for 3.1 3.2 TODO: grub in qemu --- src/kernel.c | 273 +++++++++++++++++++++++++++++---------------------- 1 file changed, 153 insertions(+), 120 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index ec3c038..de43710 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -9,10 +9,43 @@ #include "lib-header/keyboard.h" #include "lib-header/interrupt.h" #include "lib-header/fat32.h" +#include "lib-header/paging.h" void write_splash_screen3(); +void kernel_setup(void) { + enter_protected_mode(&_gdt_gdtr); + pic_remap(); + initialize_idt(); + activate_keyboard_interrupt(); + framebuffer_clear(); + framebuffer_set_cursor(0, 0); + initialize_filesystem_fat32(); + // gdt_install_tss(); + // set_tss_register(); + + // Allocate first 4 MiB virtual memory + allocate_single_user_page_frame((uint8_t*) 0); + + // Write shell into memory (assuming shell is less than 1 MiB) + struct FAT32DriverRequest request = { + .buf = (uint8_t*) 0, + .name = "shell", + .ext = "\0\0\0", + .parent_cluster_number = ROOT_CLUSTER_NUMBER, + .buffer_size = 0x100000, + }; + read(request); + + // Set TSS $esp pointer and jump into shell + // set_tss_kernel_current_stack(); + // kernel_execute_user_program((uint8_t *) 0); + + while (TRUE); +} + + /* Struktur folder * * ROOT * ikanaide @@ -24,175 +57,175 @@ void write_splash_screen3(); * b420 * destroys */ -void kernel_setup(void) { +// void kernel_setup(void) { - /* Enter protected mode */ - enter_protected_mode(&_gdt_gdtr); +// /* Enter protected mode */ +// enter_protected_mode(&_gdt_gdtr); - /* Remap PIC */ - pic_remap(); - initialize_idt(); - framebuffer_clear(); - framebuffer_set_cursor(0, 0); - initialize_filesystem_fat32(); +// /* Remap PIC */ +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// framebuffer_set_cursor(0, 0); +// initialize_filesystem_fat32(); - /* Initialize keyboard */ - activate_keyboard_interrupt(); +// /* Initialize keyboard */ +// activate_keyboard_interrupt(); - /* Initialize cbuf for debugging */ - struct ClusterBuffer cbuf[5]; - for (uint32_t i = 0; i < 5; i++) - for (uint32_t j = 0; j < CLUSTER_SIZE; j++) - cbuf[i].buf[j] = i + 'a'; +// /* Initialize cbuf for debugging */ +// struct ClusterBuffer cbuf[5]; +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// cbuf[i].buf[j] = i + 'a'; - /* Initialize cbufs for debugging */ - struct ClusterBuffer cbufs[6]; - for (uint32_t i = 0; i < 5; i++) - for (uint32_t j = 0; j < CLUSTER_SIZE; j++) - cbufs[i].buf[j] = i + '1'; - cbufs[5].buf[0] = 'E'; - cbufs[5].buf[1] = 'N'; - cbufs[5].buf[2] = 'D'; +// /* Initialize cbufs for debugging */ +// struct ClusterBuffer cbufs[6]; +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// cbufs[i].buf[j] = i + '1'; +// cbufs[5].buf[0] = 'E'; +// cbufs[5].buf[1] = 'N'; +// cbufs[5].buf[2] = 'D'; - /* Initialize request for debugging */ - struct FAT32DriverRequest request = { - .buf = cbuf, - .name = "ikanaide", - .ext = "uwu", - .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = 0, - } ; +// /* Initialize request for debugging */ +// struct FAT32DriverRequest request = { +// .buf = cbuf, +// .name = "ikanaide", +// .ext = "uwu", +// .parent_cluster_number = ROOT_CLUSTER_NUMBER, +// .buffer_size = 0, +// } ; - /* Folder ikanaide attached to ROOT */ - write(request); // Create folder "ikanaide" +// /* Folder ikanaide attached to ROOT */ +// write(request); // Create folder "ikanaide" - /* Folder BRO attached to ROOT */ - memcpy(request.name, "BRO\0\0\0\0\0", 8); - write(request); // Create folder "BRO" +// /* Folder BRO attached to ROOT */ +// memcpy(request.name, "BRO\0\0\0\0\0", 8); +// write(request); // Create folder "BRO" - /* Folder brother */ - request.parent_cluster_number = 4; - memcpy(request.name, "brother\0", 8); - write(request); // Create folder "brother" +// /* Folder brother */ +// request.parent_cluster_number = 4; +// memcpy(request.name, "brother\0", 8); +// write(request); // Create folder "brother" - /* Folder b420 */ - request.parent_cluster_number = 4; - memcpy(request.name, "b420---\0", 8); - write(request); // Create folder "b420" +// /* Folder b420 */ +// request.parent_cluster_number = 4; +// memcpy(request.name, "b420---\0", 8); +// write(request); // Create folder "b420" - /* Folder destroys */ - request.parent_cluster_number = 2; - memcpy(request.name, "destroys", 8); - write(request); // Create folder "destroys" +// /* Folder destroys */ +// request.parent_cluster_number = 2; +// memcpy(request.name, "destroys", 8); +// write(request); // Create folder "destroys" - /* Folder kano1 attached to folder ikanaide */ - request.parent_cluster_number = 3; - memcpy(request.name, "kano1\0\0\0", 8); - write(request); // Create folder "kano1" +// /* Folder kano1 attached to folder ikanaide */ +// request.parent_cluster_number = 3; +// memcpy(request.name, "kano1\0\0\0", 8); +// write(request); // Create folder "kano1" - /* Delete debug for folder destroys (should be success) */ - // memcpy(request.name, "destroys", 8); - // request.buffer_size = 0; - // request.parent_cluster_number = 2; - // delete(request); +// /* Delete debug for folder destroys (should be success) */ +// // memcpy(request.name, "destroys", 8); +// // request.buffer_size = 0; +// // request.parent_cluster_number = 2; +// // delete(request); - /* File daijoubu attached to folder kanol */ - memcpy(request.name, "daijoubu", 8); - request.buffer_size = 5*CLUSTER_SIZE; - request.parent_cluster_number = 8; - write(request); // Create fragmented file "daijoubu" +// /* File daijoubu attached to folder kanol */ +// memcpy(request.name, "daijoubu", 8); +// request.buffer_size = 5*CLUSTER_SIZE; +// request.parent_cluster_number = 8; +// write(request); // Create fragmented file "daijoubu" - /* File perusak attached to folder kanol */ - request.buf = cbufs; - memcpy(request.name, "perusak-", 8); - request.buffer_size = 5 * CLUSTER_SIZE + 3; - write(request); // Create fragmented file "perusak" +// /* File perusak attached to folder kanol */ +// request.buf = cbufs; +// memcpy(request.name, "perusak-", 8); +// request.buffer_size = 5 * CLUSTER_SIZE + 3; +// write(request); // Create fragmented file "perusak" - /* Delete debug for file perusak (should be success) */ - // memcpy(request.name, "perusak-", 8); - // memcpy(request.ext, "uwu", 3); - // request.buffer_size = 6 * CLUSTER_SIZE; - // request.parent_cluster_number = 8; - // delete(request); +// /* Delete debug for file perusak (should be success) */ +// // memcpy(request.name, "perusak-", 8); +// // memcpy(request.ext, "uwu", 3); +// // request.buffer_size = 6 * CLUSTER_SIZE; +// // request.parent_cluster_number = 8; +// // delete(request); - /* Delete debug for folder kanol (should be fail) */ - // memcpy(request.name, "kanol", 8); - // request.buffer_size = 0; - // request.parent_cluster_number = 3; - // delete(request); +// /* Delete debug for folder kanol (should be fail) */ +// // memcpy(request.name, "kanol", 8); +// // request.buffer_size = 0; +// // request.parent_cluster_number = 3; +// // delete(request); - /* File duplicate Folder BRO attached to ROOT */ - request.buffer_size = 0; - request.parent_cluster_number = ROOT_CLUSTER_NUMBER; - memcpy(request.name, "BRO\0\0\0\0\0", 8); - memcpy(request.ext, "uwO", 3); - uint8_t test = write(request); // Create folder "BRO" - test += 3; // Buat unused variable +// /* File duplicate Folder BRO attached to ROOT */ +// request.buffer_size = 0; +// request.parent_cluster_number = ROOT_CLUSTER_NUMBER; +// memcpy(request.name, "BRO\0\0\0\0\0", 8); +// memcpy(request.ext, "uwO", 3); +// uint8_t test = write(request); // Create folder "BRO" +// test += 3; // Buat unused variable - /* Reset request.buf */ - memcpy(request.ext, "uwu", 3); - for (uint32_t i = 0; i < 5; i++) - for (uint32_t j = 0; j < CLUSTER_SIZE; j++) - cbuf[i].buf[j] = '0'; - cbufs[5].buf[0] = 'E'; - cbufs[5].buf[1] = 'N'; - cbufs[5].buf[2] = 'D'; - request.buf = cbufs; +// /* Reset request.buf */ +// memcpy(request.ext, "uwu", 3); +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// cbuf[i].buf[j] = '0'; +// cbufs[5].buf[0] = 'E'; +// cbufs[5].buf[1] = 'N'; +// cbufs[5].buf[2] = 'D'; +// request.buf = cbufs; - /* Read file perusak */ - struct ClusterBuffer readcbuf; - read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER + 10, 1); - // If read properly, readcbuf should filled with 'a' +// /* Read file perusak */ +// struct ClusterBuffer readcbuf; +// read_clusters(&readcbuf, ROOT_CLUSTER_NUMBER + 10, 1); +// // If read properly, readcbuf should filled with 'a' - /* Test read FAIL due not enough buffer size */ - request.parent_cluster_number = 4; - request.buffer_size = CLUSTER_SIZE; - int8_t debug01 = read(request); // Failed read due not enough buffer size +// /* Test read FAIL due not enough buffer size */ +// request.parent_cluster_number = 4; +// request.buffer_size = CLUSTER_SIZE; +// int8_t debug01 = read(request); // Failed read due not enough buffer size - /* Test read FAIL due not valid parent_cluster */ - request.parent_cluster_number = 20; - request.buffer_size = CLUSTER_SIZE; - int8_t debug03 = read(request); // Failed read due not valid parent_cluster +// /* Test read FAIL due not valid parent_cluster */ +// request.parent_cluster_number = 20; +// request.buffer_size = CLUSTER_SIZE; +// int8_t debug03 = read(request); // Failed read due not valid parent_cluster - /* Test read SUCCESS */ - request.buffer_size = 5*CLUSTER_SIZE; - int8_t debug02 = read(request); // Success read on file "daijoubu" +// /* Test read SUCCESS */ +// request.buffer_size = 5*CLUSTER_SIZE; +// int8_t debug02 = read(request); // Success read on file "daijoubu" - /* Buat unused variable saja */ - debug01 += debug02 + debug03; - write_splash_screen3(); - while (TRUE && !altF4()) { - keyboard_state_activate(); - if (restoreSplashScreen()) { - write_splash_screen3(); +// /* Buat unused variable saja */ +// debug01 += debug02 + debug03; +// write_splash_screen3(); +// while (TRUE && !altF4()) { +// keyboard_state_activate(); +// if (restoreSplashScreen()) { +// write_splash_screen3(); - } - } +// } +// } -} +// } // void kernel_setup(void) { From 99aacd906e3ec199ecdfdf348bde8f999962f1f9 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 14:21:31 +0700 Subject: [PATCH 089/176] feat: add inserter setup for 3.2 --- makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/makefile b/makefile index fa2b0f9..2539403 100644 --- a/makefile +++ b/makefile @@ -49,3 +49,9 @@ iso: kernel @echo Creating ISO image... @$(ISO) $(IFLAGS) -o $(OUTPUT_FOLDER)/$(ISO_NAME).iso $(OUTPUT_FOLDER)/iso @rm -r $(OUTPUT_FOLDER)/iso/ + +inserter: + @$(CC) -Wno-builtin-declaration-mismatch \ + $(SOURCE_FOLDER)/stdmem.c $(SOURCE_FOLDER)/fat32.c \ + $(SOURCE_FOLDER)/external-inserter.c \ + -o $(OUTPUT_FOLDER)/inserter \ No newline at end of file From 721fa239ba53111ad22b441876314aa1867556fd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:54:28 +0700 Subject: [PATCH 090/176] feat: add user,insert shell makefile (TODO insert) --- makefile | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 2539403..f3c03e5 100644 --- a/makefile +++ b/makefile @@ -54,4 +54,17 @@ inserter: @$(CC) -Wno-builtin-declaration-mismatch \ $(SOURCE_FOLDER)/stdmem.c $(SOURCE_FOLDER)/fat32.c \ $(SOURCE_FOLDER)/external-inserter.c \ - -o $(OUTPUT_FOLDER)/inserter \ No newline at end of file + -o $(OUTPUT_FOLDER)/inserter + +user-shell: + @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/user-entry.s -o user-entry.o + @$(CC) $(CFLAGS) -fno-pie $(SOURCE_FOLDER)/user-shell.c -o user-shell.o + @$(LIN) -T $(SOURCE_FOLDER)/user-linker.ld -melf_i386 \ + user-entry.o user-shell.o -o $(OUTPUT_FOLDER)/shell + @echo Linking object shell object files and generate flat binary... + @size --target=binary bin/shell + @rm -f *.o + +insert-shell: inserter user-shell + @echo Inserting shell into root directory... +# TODO : Insert shell into storage image From 1a6fb9b4bea700a9a43fd5756d094bb188828b5f Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:56:17 +0700 Subject: [PATCH 091/176] feat: add new synced GDT; feat: add gdtInstallTss; --- src/gdt.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/gdt.c b/src/gdt.c index a70e2c6..eb3cacf 100644 --- a/src/gdt.c +++ b/src/gdt.c @@ -1,5 +1,6 @@ #include "lib-header/stdtype.h" #include "lib-header/gdt.h" +#include "lib-header/interrupt.h" /** * global_descriptor_table, predefined GDT. @@ -59,6 +60,33 @@ struct GlobalDescriptorTable global_descriptor_table = { } }; + +static struct GlobalDescriptorTable global_descriptor_tables = { + .table = { + {/* Null Descriptor */}, + {/* Kernel Code Descriptor */}, + {/* Kernel Data Descriptor */}, + {/* User Code Descriptor */}, + {/* User Data Descriptor */}, + { + .segment_limit = (sizeof(struct TSSEntry) & (0xF << 16)) >> 16, + .segment_low = sizeof(struct TSSEntry), + .base_high = 0, + .base_mid = 0, + .base_low = 0, + .non_system = 0, // S bit + .type_bit = 0x9, + .DPL = 0, // DPL + .P = 1, // P bit + .D_B = 1, // D/B bit + .L = 0, // L bit + .G = 0, // G bit + }, + {0} + } +}; + + /** * _gdt_gdtr, predefined system GDTR. * GDT pointed by this variable is already set to point global_descriptor_table above. @@ -72,3 +100,11 @@ struct GDTR _gdt_gdtr = { // TODO : Implement, this GDTR will point to global_descriptor_table. // Use sizeof operator }; + + +void gdt_install_tss(void) { + uint32_t base = (uint32_t) &_interrupt_tss_entry; + global_descriptor_tables.table[5].base_high = (base & (0xFF << 24)) >> 24; + global_descriptor_tables.table[5].base_mid = (base & (0xFF << 16)) >> 16; + global_descriptor_tables.table[5].base_low = base & 0xFFFF; +} From 5740a22f20939f9faa764da736a0afd14692bc27 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:56:52 +0700 Subject: [PATCH 092/176] feat: add kernel-loader setup for milestone 3 --- src/kernel_loader.s | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/kernel_loader.s b/src/kernel_loader.s index 16ba590..7466740 100644 --- a/src/kernel_loader.s +++ b/src/kernel_loader.s @@ -74,6 +74,26 @@ enter_protected_mode: ; Far jump to update cs register ; Warning: Invalid GDT will raise exception in any instruction below jmp 0x8:flush_cs +global kernel_execute_user_program ; execute user program from kernel +kernel_execute_user_program: + mov eax, 0x20 | 0x3 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + mov ecx, [esp+4] ; Save this first (before pushing anything to stack) for last push + push eax ; Stack segment selector (GDT_USER_DATA_SELECTOR), user privilege + mov eax, ecx + add eax, 0x400000 - 4 + push eax ; User space stack pointer (esp), move it into last 4 MiB + pushf ; eflags register state, when jump inside user program + mov eax, 0x18 | 0x3 + push eax ; Code segment selector (GDT_USER_CODE_SELECTOR), user privilege + mov eax, ecx + push eax ; eip register to jump back + + iret flush_cs: ; Update all segment register mov ax, 10h From c62465fe9c6cb8820b418abb5fb010a32debbfa7 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:57:39 +0700 Subject: [PATCH 093/176] feat: add new setup for milestone 3.3 syscall --- src/interrupt.c | 77 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 8e030b8..977effb 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -1,5 +1,14 @@ #include "lib-header/interrupt.h" #include "lib-header/framebuffer.h" +#include "lib-header/gdt.h" +#include "lib-header/stdmem.h" + +struct TSSEntry _interrupt_tss_entry = { + .prev_tss = 0, + .esp0 = 0, + .ss0 = 0, +}; + void io_wait(void) { out(0x80, 0); @@ -42,19 +51,67 @@ void pic_remap(void) { out(PIC2_DATA, a2); } -void main_interrupt_handler( - __attribute__((unused)) struct CPURegister cpu, - uint32_t int_number, - __attribute__((unused)) struct InterruptStack info -) { +// void main_interrupt_handler( +// __attribute__((unused)) struct CPURegister cpu, +// uint32_t int_number, +// __attribute__((unused)) struct InterruptStack info +// ) { - switch (int_number) { - case (PIC1_OFFSET + IRQ_KEYBOARD): - keyboard_isr(); - } -} +// switch (int_number) { +// case (PIC1_OFFSET + IRQ_KEYBOARD): +// keyboard_isr(); +// } +// } void activate_keyboard_interrupt(void) { out(PIC1_DATA, PIC_DISABLE_ALL_MASK ^ (1 << IRQ_KEYBOARD)); out(PIC2_DATA, PIC_DISABLE_ALL_MASK); } + +void set_tss_kernel_current_stack(void) { + uint32_t stack_ptr; + // Reading base stack frame instead esp + __asm__ volatile ("mov %%ebp, %0": "=r"(stack_ptr) : /* */); + // Add 8 because 4 for ret address and other 4 is for stack_ptr variable + _interrupt_tss_entry.esp0 = stack_ptr + 8; +} + +// struct TSSEntry _interrupt_tss_entry = { +// .ss0 = GDT_KERNEL_DATA_SEGMENT_SELECTOR, +// }; + + +// TODO: implementasikan sendiri katanya +// void puts(char *str, uint32_t len, uint32_t color) { + +// } + + +void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { + if (cpu.eax == 0) { + struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + *((int8_t*) cpu.ecx) = read(request); + } else if (cpu.eax == 4) { + keyboard_state_activate(); + __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called + while (is_keyboard_blocking()); + char buf[KEYBOARD_BUFFER_SIZE]; + get_keyboard_buffer(buf); + memcpy((char *) cpu.ebx, buf, cpu.ecx); + } else if (cpu.eax == 5) { + // puts((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side + } +} + + +void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { + switch (int_number) { + case PIC1_OFFSET + IRQ_KEYBOARD: + keyboard_isr(); + break; + case 0x30: + syscall(cpu, info); + break; + } +} + From 4915ed54e06bfce661f552125d2ee1a22c57ac94 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:58:00 +0700 Subject: [PATCH 094/176] feat: add new user-linker.ld --- src/user-linker.ld | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/user-linker.ld diff --git a/src/user-linker.ld b/src/user-linker.ld new file mode 100644 index 0000000..545898c --- /dev/null +++ b/src/user-linker.ld @@ -0,0 +1,24 @@ +ENTRY(_start) +OUTPUT_FORMAT("binary") + +SECTIONS { + . = 0x00000000; /* Assuming OS will load this program at virtual address 0x00000000 */ + + .text ALIGN(4): + { + user-entry.o(.text) /* Put user-entry at front of executable */ + *(.text) + } + + .data ALIGN(4): + { + *(.data) + } + + .rodata ALIGN(4): + { + *(.rodata*) + } + _linker_user_program_end = .; + ASSERT ((_linker_user_program_end <= 1 * 1024 * 1024), "Error: User program linking result is more than 1 MiB") +} From 2ca70bd77103fd6778d7f6b54a829689521c4320 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:58:17 +0700 Subject: [PATCH 095/176] feat: add user-shell to test program --- src/user-shell.c | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/user-shell.c diff --git a/src/user-shell.c b/src/user-shell.c new file mode 100644 index 0000000..3b5a968 --- /dev/null +++ b/src/user-shell.c @@ -0,0 +1,7 @@ +#include "lib-header/stdtype.h" + +int main(void) { + __asm__ volatile("mov %0, %%eax" : /* */ : "r"(0xDEADBEEF)); + while (TRUE); + return 0; +} From a74c885f5d6e68351c4b37a599a724d5b36dc5c9 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:58:55 +0700 Subject: [PATCH 096/176] feat: add new define in gdt.h --- src/lib-header/gdt.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib-header/gdt.h b/src/lib-header/gdt.h index f0262ec..a9222be 100644 --- a/src/lib-header/gdt.h +++ b/src/lib-header/gdt.h @@ -4,6 +4,9 @@ #include "stdtype.h" #define GDT_MAX_ENTRY_COUNT 32 +#define GDT_USER_CODE_SEGMENT_SELECTOR 0x18 +#define GDT_USER_DATA_SEGMENT_SELECTOR 0x20 +#define GDT_TSS_SELECTOR 0x28 extern struct GDTR _gdt_gdtr; @@ -63,4 +66,7 @@ struct GDTR { } __attribute__((packed)); +// Set GDT_TSS_SELECTOR with proper TSS values, accessing _interrupt_tss_entry +void gdt_install_tss(void); + #endif \ No newline at end of file From 9fbe75a63c121125d4507e8e0c46012130a50030 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 19:59:42 +0700 Subject: [PATCH 097/176] feat: add struct TSSEntry --- src/lib-header/interrupt.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/lib-header/interrupt.h b/src/lib-header/interrupt.h index b3d7192..2b15b6e 100644 --- a/src/lib-header/interrupt.h +++ b/src/lib-header/interrupt.h @@ -95,7 +95,16 @@ struct InterruptStack { } __attribute__((packed)); - +/** + * TSSEntry, Task State Segment. Used when jumping back to ring 0 / kernel + */ +struct TSSEntry { + uint32_t prev_tss; // Previous TSS + uint32_t esp0; // Stack pointer to load when changing to kernel mode + uint32_t ss0; // Stack segment to load when changing to kernel mode + // Unused variables + uint32_t unused_register[23]; +} __attribute__((packed)); // Activate PIC mask for keyboard only @@ -124,4 +133,11 @@ void pic_remap(void); */ void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info); + +extern struct TSSEntry _interrupt_tss_entry; + + +// Set kernel stack in TSS +void set_tss_kernel_current_stack(void); + #endif \ No newline at end of file From 006691b1bdff7b097923f1ff0437c9f4404bb0d8 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 20:00:16 +0700 Subject: [PATCH 098/176] feat: add new kernel_loader.h setup --- src/lib-header/kernel_loader.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/lib-header/kernel_loader.h b/src/lib-header/kernel_loader.h index 65ae26e..c47e21d 100644 --- a/src/lib-header/kernel_loader.h +++ b/src/lib-header/kernel_loader.h @@ -1,6 +1,8 @@ #ifndef _KERNEL_LOADER #define _KERNEL_LOADER +#include "stdtype.h" + /** * Load GDT from gdtr and launch protected mode. This function defined in asm source code. * @@ -9,4 +11,25 @@ */ extern void enter_protected_mode(struct GDTR *gdtr); +// Optional linker variable : Pointing to kernel start & end address +// Note : Use & operator, example : a = (uint32_t) &_linker_kernel_stack_top; +extern uint32_t _linker_kernel_virtual_addr_start; +extern uint32_t _linker_kernel_virtual_addr_end; +extern uint32_t _linker_kernel_physical_addr_start; +extern uint32_t _linker_kernel_physical_addr_end; +extern uint32_t _linker_kernel_stack_top; + +/** + * Execute user program from kernel, one way jump. This function is defined in asm source code. + * + * @param virtual_addr Pointer into user program that already in memory + * @warning Assuming pointed memory is properly loaded + */ +extern void kernel_execute_user_program(void *virtual_addr); + +/** + * Set the tss register pointing to GDT_TSS_SELECTOR with ring 0 + */ +extern void set_tss_register(void); // Note : Already implemented in kernel_loader.asm + #endif \ No newline at end of file From f37132d5fa40eb4978360ca1c04506e127e90b13 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 1 Apr 2023 20:00:48 +0700 Subject: [PATCH 099/176] feat: add new UNUSED user-entry.s --- src/user-entry.s | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/user-entry.s diff --git a/src/user-entry.s b/src/user-entry.s new file mode 100644 index 0000000..8fdc8a2 --- /dev/null +++ b/src/user-entry.s @@ -0,0 +1,7 @@ +global _start +extern main + +section .text +_start: + call main + jmp $ \ No newline at end of file From 2c8d024f1e5f4b3608b17bd52bf50f5d390a6af5 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 13:45:37 +0700 Subject: [PATCH 100/176] fix: change PageDirectoryEntry struct Co-Authored-By: @Darmodar --- src/lib-header/paging.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib-header/paging.h b/src/lib-header/paging.h index 0f06ea4..d5ad2f6 100644 --- a/src/lib-header/paging.h +++ b/src/lib-header/paging.h @@ -44,22 +44,25 @@ struct PageDirectoryEntryFlag { * * @param flag Contain 8-bit page directory entry flag * @param global_page Is this page translation global (also cannot be flushed) + * * @param ignored Ignored * @param PAT If the PAT is supported, indirectly determines the memory type used to access the 4-MByte page referenced by this entry - * @param lower_address ?????????????????????????? + * @param phys_address ??????????????????????????????????????????????????????????????????????????????? * @param reserved Reserved tulisan di tabel itu must be 0 - * @param page_frame_4mb Bits 31:22 of physical address of the 4-MByte page referenced by this entry + * @param lower_address Bits 31:22 of physical address of the 4-MByte page referenced by this entry */ struct PageDirectoryEntry { struct PageDirectoryEntryFlag flag; uint16_t global_page : 1; - uint16_t ignored : 3; - uint16_t PAT : 1; - uint16_t lower_address : 4; - uint16_t reserved : 5; - uint16_t page_frame_4mb : 10; // TODO : Continue, Use uint16_t + bitfield here, Do not use uint8_t + uint16_t ignored : 3; + uint16_t PAT : 1; + uint16_t phys_address_paging : 4; + uint16_t reserved : 5; + uint16_t lower_address : 10; + + } __attribute__((packed)); /** From 1b3062b7cc612a959833c2920f1c0c9143c574a2 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 13:47:24 +0700 Subject: [PATCH 101/176] fix: change the new main_interrupt_handler --- src/interrupt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 977effb..bc606b7 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -57,9 +57,13 @@ void pic_remap(void) { // __attribute__((unused)) struct InterruptStack info // ) { -// switch (int_number) { -// case (PIC1_OFFSET + IRQ_KEYBOARD): +// switch (int_number) { +// case PAGE_FAULT: +// __asm__("hlt"); +// break; +// case PIC1_OFFSET + IRQ_KEYBOARD: // keyboard_isr(); +// break; // } // } @@ -106,6 +110,9 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { switch (int_number) { + case PAGE_FAULT: + __asm__("hlt"); + break; case PIC1_OFFSET + IRQ_KEYBOARD: keyboard_isr(); break; From 99135423fc343e082555cb1df6ce637a2ba08c7d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 14:54:25 +0700 Subject: [PATCH 102/176] fix: modify kernel_loader.s --- src/kernel_loader.s | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/kernel_loader.s b/src/kernel_loader.s index 7466740..5aadf6f 100644 --- a/src/kernel_loader.s +++ b/src/kernel_loader.s @@ -58,22 +58,6 @@ loader_virtual: section .text -; More details: https://en.wikibooks.org/wiki/X86_Assembly/Protected_Mode -enter_protected_mode: - ; Load GDT from GDTDescriptor - cli - mov eax, [esp+4] - lgdt [eax] - - ; Set Protection Enable bit-flag in Control Register 0 (CR0) - ; Or in other words: Switch to protected mode - mov eax, cr0 - or eax, 1 - mov cr0, eax - - ; Far jump to update cs register - ; Warning: Invalid GDT will raise exception in any instruction below - jmp 0x8:flush_cs global kernel_execute_user_program ; execute user program from kernel kernel_execute_user_program: mov eax, 0x20 | 0x3 @@ -94,6 +78,22 @@ kernel_execute_user_program: push eax ; eip register to jump back iret +; More details: https://en.wikibooks.org/wiki/X86_Assembly/Protected_Mode +enter_protected_mode: + ; Load GDT from GDTDescriptor + cli + mov eax, [esp+4] + lgdt [eax] + + ; Set Protection Enable bit-flag in Control Register 0 (CR0) + ; Or in other words: Switch to protected mode + mov eax, cr0 + or eax, 1 + mov cr0, eax + + ; Far jump to update cs register + ; Warning: Invalid GDT will raise exception in any instruction below + jmp 0x8:flush_cs flush_cs: ; Update all segment register mov ax, 10h From 6525c828aff83a14244d894340a04c7cc5632d30 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 14:55:50 +0700 Subject: [PATCH 103/176] feat: add GDT User Code Descriptor and User Data D --- src/gdt.c | 169 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 94 insertions(+), 75 deletions(-) diff --git a/src/gdt.c b/src/gdt.c index eb3cacf..e01ec1c 100644 --- a/src/gdt.c +++ b/src/gdt.c @@ -7,80 +7,98 @@ * Initial SegmentDescriptor already set properly according to GDT definition in Intel Manual & OSDev. * Table entry : [{Null Descriptor}, {Kernel Code}, {Kernel Data (variable, etc)}, ...]. */ -struct GlobalDescriptorTable global_descriptor_table = { - .table = { - { - .segment_low = 0, - .base_low = 0, - .base_mid = 0, - .type_bit = 0, - .non_system = 0, - .DPL = 0, - .P = 0, - .segment_limit = 0, - .AVL = 0, - .L = 0, - .D_B = 0, - .G = 0, - .base_high = 0 - - }, - { - .segment_low = 0xFFFF, - .base_low = 0, - .base_mid = 0, - .type_bit = 0xA, - .non_system = 1, - .DPL = 0, - .P = 1, - .segment_limit = 0xF, - .AVL = 0, - .L = 0, - .D_B = 1, - .G = 1, - .base_high = 0 - // TODO : Implement - }, - { - .segment_low = 0xFFFF, - .base_low = 0, - .base_mid = 0, - .type_bit = 0x2, - .non_system = 1, - .DPL = 0, - .P = 1, - .segment_limit = 0xF, - .AVL = 0, - .L = 0, - .D_B = 1, - .G = 1, - .base_high = 0 - // TODO : Implement - } - } -}; -static struct GlobalDescriptorTable global_descriptor_tables = { +static struct GlobalDescriptorTable global_descriptor_table = { .table = { - {/* Null Descriptor */}, - {/* Kernel Code Descriptor */}, - {/* Kernel Data Descriptor */}, - {/* User Code Descriptor */}, - {/* User Data Descriptor */}, + {/* TODO : Null Descriptor */ + .segment_low = 0, + .base_low = 0, + .base_mid = 0, + .type_bit = 0, + .non_system = 0, + .DPL = 0, + .P = 0, + .segment_limit = 0, + .AVL = 0, + .L = 0, + .D_B = 0, + .G = 0, + .base_high = 0 + }, + {/* TODO : Kernel Code Descriptor */ + .segment_low = 0xFFFF, + .base_low = 0, + .base_mid = 0, + .type_bit = 0xA, + .non_system = 1, + .DPL = 0, + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + }, + {/* TODO : Kernel Data Descriptor */ + .segment_low = 0xFFFF, + .base_low = 0, + .base_mid = 0, + .type_bit = 0x2, + .non_system = 1, + .DPL = 0, + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + }, + {/* TODO : User Code Descriptor */ + .segment_low = 0xFFFF, + .base_low = 0, + .base_mid = 0, + .type_bit = 0xA, + .non_system = 1, + .DPL = 0x3, // User Descriptor Privilege Level + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + }, + {/* TODO : User Data Descriptor */ + .segment_low = 0xFFFF, + .base_low = 0, + .base_mid = 0, + .type_bit = 0x2, + .non_system = 1, + .DPL = 0x3, // User Descriptor Privilege Level + .P = 1, + .segment_limit = 0xF, + .AVL = 0, + .L = 0, + .D_B = 1, + .G = 1, + .base_high = 0 + }, { - .segment_limit = (sizeof(struct TSSEntry) & (0xF << 16)) >> 16, - .segment_low = sizeof(struct TSSEntry), - .base_high = 0, - .base_mid = 0, - .base_low = 0, - .non_system = 0, // S bit - .type_bit = 0x9, - .DPL = 0, // DPL - .P = 1, // P bit - .D_B = 1, // D/B bit - .L = 0, // L bit - .G = 0, // G bit + .segment_limit = (sizeof(struct TSSEntry) & (0xF << 16)) >> 16, + .segment_low = sizeof(struct TSSEntry), + .base_high = 0, + .base_mid = 0, + .base_low = 0, + .non_system = 0, // S bit + .type_bit = 0x9, + .DPL = 0, // DPL + .P = 1, // P bit + .D_B = 1, // D/B bit + .L = 0, // L bit + .G = 0, // G bit }, {0} } @@ -94,17 +112,18 @@ static struct GlobalDescriptorTable global_descriptor_tables = { */ struct GDTR _gdt_gdtr = { + // TODO : Implement, this GDTR will point to global_descriptor_table. + // Use sizeof operator + .size = sizeof(struct GlobalDescriptorTable) - 1, .address = &global_descriptor_table - // TODO : Implement, this GDTR will point to global_descriptor_table. - // Use sizeof operator }; void gdt_install_tss(void) { uint32_t base = (uint32_t) &_interrupt_tss_entry; - global_descriptor_tables.table[5].base_high = (base & (0xFF << 24)) >> 24; - global_descriptor_tables.table[5].base_mid = (base & (0xFF << 16)) >> 16; - global_descriptor_tables.table[5].base_low = base & 0xFFFF; + global_descriptor_table.table[5].base_high = (base & (0xFF << 24)) >> 24; + global_descriptor_table.table[5].base_mid = (base & (0xFF << 16)) >> 16; + global_descriptor_table.table[5].base_low = base & 0xFFFF; } From b267534ccb8781e9ce523ba86f26e4de43dc6a48 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 14:56:25 +0700 Subject: [PATCH 104/176] style: activate debugger --- src/kernel.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index de43710..eb67e65 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -22,8 +22,8 @@ void kernel_setup(void) { framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); - // gdt_install_tss(); - // set_tss_register(); + gdt_install_tss(); + set_tss_register(); // Allocate first 4 MiB virtual memory allocate_single_user_page_frame((uint8_t*) 0); @@ -39,9 +39,10 @@ void kernel_setup(void) { read(request); // Set TSS $esp pointer and jump into shell - // set_tss_kernel_current_stack(); - // kernel_execute_user_program((uint8_t *) 0); - + set_tss_kernel_current_stack(); + kernel_execute_user_program((uint8_t *) 0); // kayaknya di sini salah + int i = 0; + i++; while (TRUE); } From 47007675f024660b8b5aa7c610d0f8d57eb728d6 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 15:00:29 +0700 Subject: [PATCH 105/176] fix: unfinished allocate_singl_ HELP BOOTLOOP T_T --- src/paging.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/paging.c b/src/paging.c index 7e42eca..2256173 100644 --- a/src/paging.c +++ b/src/paging.c @@ -30,29 +30,38 @@ void update_page_directory_entry(void *physical_addr, void *virtual_addr, struct flush_single_tlb(virtual_addr); } +/* Curiga salah di sini, help T_T BOOTLOOP */ int8_t allocate_single_user_page_frame(void *virtual_addr) { // Using default QEMU config (128 MiB max memory) uint32_t last_physical_addr = (uint32_t) page_driver_state.last_available_physical_addr; - struct PageDirectoryEntryFlag flag = { - .present_bit = 1, - .write_bit = 1, - .userOrSupervisor = 1, - .use_pagesize_4_mb = 1 - }; + // TODO : Allocate Page Directory Entry with user privilege - if (last_physical_addr >= 32 * PAGE_FRAME_SIZE) { + struct PageDirectoryEntry page_dir_entry = { + .flag.present_bit = 1, + .flag.write_bit = 1, + .flag.userOrSupervisor = 1, + .flag.PWT = 0, + .flag.PCD = 0, + .flag.accessed_bit = 0, + .flag.dirty_bit = 0, + .flag.use_pagesize_4_mb = 1, + .lower_address = last_physical_addr >> 22 & 0x3FF + }; + + if (last_physical_addr >= PAGE_FRAME_SIZE) { return -1; } else { - update_page_directory_entry((void*) last_physical_addr, virtual_addr, flag); + // Update page directory entry + update_page_directory_entry(&last_physical_addr, virtual_addr, page_dir_entry.flag); page_driver_state.last_available_physical_addr += PAGE_FRAME_SIZE; return 0; } - // TODO : Allocate Page Directory Entry with user privilege return -1; } + void flush_single_tlb(void *virtual_addr) { asm volatile("invlpg (%0)" : /* */ : "b"(virtual_addr): "memory"); } \ No newline at end of file From adad07a8ba98fd118c93fa51742a80282985efae Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 15:00:54 +0700 Subject: [PATCH 106/176] style: add define PAGE_FAULT --- src/lib-header/interrupt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib-header/interrupt.h b/src/lib-header/interrupt.h index 2b15b6e..1771dcc 100644 --- a/src/lib-header/interrupt.h +++ b/src/lib-header/interrupt.h @@ -59,6 +59,8 @@ #define IRQ_PRIMARY_ATA 14 #define IRQ_SECOND_ATA 15 +// Paging +#define PAGE_FAULT 0xe /** * CPURegister, store CPU registers that can be used for interrupt handler / ISRs From 0ec4e078ba1cffee2d22c015e934d61f08f8142b Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 22:15:58 +0700 Subject: [PATCH 107/176] fix: update modified time and disable create fat32 Hasil Asistensi --- src/fat32.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 08a315d..66c844e 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -132,7 +132,7 @@ void initialize_filesystem_fat32(void){ if (is_empty_storage()){ create_fat32(); } else { - create_fat32(); + // create_fat32(); read_clusters(driver_state.fat_table.cluster_map, 1, 1); } } @@ -284,8 +284,8 @@ int8_t write(struct FAT32DriverRequest request){ } driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; get_time(&time, &date); - driver_state.dir_table_buf.table[0].modified_date = date; - driver_state.dir_table_buf.table[0].modified_time = time; + // driver_state.dir_table_buf.table[0].modified_date = date; + // driver_state.dir_table_buf.table[0].modified_time = time; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); @@ -343,8 +343,8 @@ int8_t write(struct FAT32DriverRequest request){ get_time(&time, &date); driver_state.dir_table_buf.table[cluster_table].create_date = date; driver_state.dir_table_buf.table[cluster_table].create_time = time; - driver_state.dir_table_buf.table[0].modified_date = date; - driver_state.dir_table_buf.table[0].modified_time = time; + // driver_state.dir_table_buf.table[0].modified_date = date; + // driver_state.dir_table_buf.table[0].modified_time = time; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } @@ -389,8 +389,8 @@ int8_t delete(struct FAT32DriverRequest request){ driver_state.dir_table_buf.table[index] = temp_ent; driver_state.fat_table.cluster_map[location] = 0; get_time(&time, &date); - driver_state.dir_table_buf.table[0].modified_time = time; - driver_state.dir_table_buf.table[0].modified_date = date; + // driver_state.dir_table_buf.table[0].modified_time = time; + // driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.fat_table.cluster_map,1,1); write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); @@ -414,8 +414,8 @@ int8_t delete(struct FAT32DriverRequest request){ } while (!flag); write_clusters(driver_state.fat_table.cluster_map,1,1); get_time(&time, &date); - driver_state.dir_table_buf.table[0].modified_time = time; - driver_state.dir_table_buf.table[0].modified_date = date; + // driver_state.dir_table_buf.table[0].modified_time = time; + // driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); return 0; } From 50f569d9c10d9a93a27bea23da97ab00ad5f4e66 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 22:17:14 +0700 Subject: [PATCH 108/176] fix: interrupt.c, update sso in TSSEntry Hasil Asistensi --- src/interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interrupt.c b/src/interrupt.c index bc606b7..688cd20 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -6,7 +6,7 @@ struct TSSEntry _interrupt_tss_entry = { .prev_tss = 0, .esp0 = 0, - .ss0 = 0, + .ss0 = 0x10, }; From 8810f818be2b2f07cc38b5aaa2bebcb41d9a19ab Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 22:19:26 +0700 Subject: [PATCH 109/176] fix: paging.c update allocate_single_user_page_frm --- src/paging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/paging.c b/src/paging.c index 2256173..92c4879 100644 --- a/src/paging.c +++ b/src/paging.c @@ -49,11 +49,11 @@ int8_t allocate_single_user_page_frame(void *virtual_addr) { .lower_address = last_physical_addr >> 22 & 0x3FF }; - if (last_physical_addr >= PAGE_FRAME_SIZE) { + if (last_physical_addr >= 32 * PAGE_FRAME_SIZE) { return -1; } else { // Update page directory entry - update_page_directory_entry(&last_physical_addr, virtual_addr, page_dir_entry.flag); + update_page_directory_entry((void *) last_physical_addr, virtual_addr, page_dir_entry.flag); page_driver_state.last_available_physical_addr += PAGE_FRAME_SIZE; return 0; } From ace1d702c2f648406f7a401ec797aa623647267a Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 22:20:55 +0700 Subject: [PATCH 110/176] fix: kernel.c update kernel for debugging --- src/kernel.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index eb67e65..6f5b775 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -19,24 +19,25 @@ void kernel_setup(void) { pic_remap(); initialize_idt(); activate_keyboard_interrupt(); + keyboard_state_activate(); framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); gdt_install_tss(); set_tss_register(); - + framebuffer_write(0,0,sizeof(struct FAT32DirectoryEntry),0xe, 0); // Allocate first 4 MiB virtual memory allocate_single_user_page_frame((uint8_t*) 0); // Write shell into memory (assuming shell is less than 1 MiB) struct FAT32DriverRequest request = { .buf = (uint8_t*) 0, - .name = "shell", + .name = "shells", .ext = "\0\0\0", .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = 0x100000, + .buffer_size = 0x1000, }; - read(request); + write(request); // Set TSS $esp pointer and jump into shell set_tss_kernel_current_stack(); From e606983431b5fd53a95e011dd74a54d42119aa19 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 3 Apr 2023 22:21:30 +0700 Subject: [PATCH 111/176] fix: fat32.h update modified_time Hasil Asistensi --- src/lib-header/fat32.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib-header/fat32.h b/src/lib-header/fat32.h index 5b0ca19..e235344 100644 --- a/src/lib-header/fat32.h +++ b/src/lib-header/fat32.h @@ -105,10 +105,11 @@ struct FAT32DirectoryEntry { struct Date access_date; uint16_t cluster_high; - struct Time modified_time; - struct Date modified_date; + // struct Time modified_time; + // struct Date modified_date; uint16_t cluster_low; uint32_t filesize; + char last; } __attribute__((packed)); // FAT32 DirectoryTable, containing directory entry table - @param table Table of DirectoryEntry that span within 1 cluster From 7f1baadcdc5c150fe5554e671de15225f055c6a1 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 12:28:13 +0700 Subject: [PATCH 112/176] fix: insert-shell makefile; style: inserter makefi --- makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index f3c03e5..6909be2 100644 --- a/makefile +++ b/makefile @@ -52,8 +52,10 @@ iso: kernel inserter: @$(CC) -Wno-builtin-declaration-mismatch \ - $(SOURCE_FOLDER)/stdmem.c $(SOURCE_FOLDER)/fat32.c \ - $(SOURCE_FOLDER)/external-inserter.c \ + $(SOURCE_FOLDER)/stdmem.c \ + $(SOURCE_FOLDER)/portio.c \ + $(SOURCE_FOLDER)/fat32.c \ + $(SOURCE_FOLDER)/external/external-inserter.c \ -o $(OUTPUT_FOLDER)/inserter user-shell: @@ -67,4 +69,5 @@ user-shell: insert-shell: inserter user-shell @echo Inserting shell into root directory... -# TODO : Insert shell into storage image + @cd $(OUTPUT_FOLDER); ./inserter shell 2 $(DISK_NAME).bin + From a5d6cced28836baba220c57d350286eb78a5fe85 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 12:29:23 +0700 Subject: [PATCH 113/176] feat: add external-inserter default Note: still Segmentation Fault while creating insert-shell --- src/external/external-inserter.c | 98 ++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/external/external-inserter.c diff --git a/src/external/external-inserter.c b/src/external/external-inserter.c new file mode 100644 index 0000000..db6cbfc --- /dev/null +++ b/src/external/external-inserter.c @@ -0,0 +1,98 @@ +#include +#include + +// Usual gcc fixed width integer type +typedef u_int32_t uint32_t; +typedef u_int8_t uint8_t; + +// Manual import from fat32.h, disk.h, & stdmem.h due some issue with size_t +#define BLOCK_SIZE 512 + +struct FAT32DriverRequest { + void *buf; + char name[8]; + char ext[3]; + uint32_t parent_cluster_number; + uint32_t buffer_size; +} __attribute__((packed)); + +void* memcpy(void* restrict dest, const void* restrict src, size_t n); + +void initialize_filesystem_fat32(void); +int8_t read(struct FAT32DriverRequest request); +int8_t read_directory(struct FAT32DriverRequest request); +int8_t write(struct FAT32DriverRequest request); +int8_t delete(struct FAT32DriverRequest request); + + + + +// Global variable +uint8_t *image_storage; +uint8_t *file_buffer; + +void read_blocks(void *ptr, uint32_t logical_block_address, uint8_t block_count) { + for (int i = 0; i < block_count; i++) + memcpy((uint8_t*) ptr + BLOCK_SIZE*i, image_storage + BLOCK_SIZE*(logical_block_address+i), BLOCK_SIZE); +} + +void write_blocks(const void *ptr, uint32_t logical_block_address, uint8_t block_count) { + for (int i = 0; i < block_count; i++) + memcpy(image_storage + BLOCK_SIZE*(logical_block_address+i), (uint8_t*) ptr + BLOCK_SIZE*i, BLOCK_SIZE); +} + + +int main(int argc, char *argv[]) { + if (argc < 4) { + fprintf(stderr, "inserter: ./inserter \n"); + exit(1); + } + + // Read storage into memory, requiring 4 MB memory + image_storage = malloc(4*1024*1024); + file_buffer = malloc(4*1024*1024); + FILE *fptr = fopen(argv[3], "r"); + fread(image_storage, 4*1024*1024, 1, fptr); + fclose(fptr); + + // Read target file, assuming file is less than 4 MiB + FILE *fptr_target = fopen(argv[1], "r"); + size_t filesize = 0; + if (fptr_target == NULL) + filesize = 0; + else { + fread(file_buffer, 4*1024*1024, 1, fptr_target); + fseek(fptr_target, 0, SEEK_END); + filesize = ftell(fptr_target); + fclose(fptr_target); + } + + printf("Filename : %s\n", argv[1]); + printf("Filesize : %ld bytes\n", filesize); + + // FAT32 operations + initialize_filesystem_fat32(); + struct FAT32DriverRequest request = { + .buf = file_buffer, + .ext = "\0\0\0", + .buffer_size = filesize, + }; + sscanf(argv[2], "%u", &request.parent_cluster_number); + sscanf(argv[1], "%8s", request.name); + int retcode = write(request); + if (retcode == 0) + puts("Write success"); + else if (retcode == 1) + puts("Error: File/folder name already exist"); + else if (retcode == 2) + puts("Error: Invalid parent cluster"); + else + puts("Error: Unknown error"); + + // Write image in memory into original, overwrite them + fptr = fopen(argv[3], "w"); + fwrite(image_storage, 4*1024*1024, 1, fptr); + fclose(fptr); + + return 0; +} \ No newline at end of file From c601ebb4558be1e855fd74f817293be4ce7ce95e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 12:33:18 +0700 Subject: [PATCH 114/176] fix: move user-shell to external --- makefile | 2 +- src/{ => external}/user-shell.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{ => external}/user-shell.c (78%) diff --git a/makefile b/makefile index 6909be2..363460e 100644 --- a/makefile +++ b/makefile @@ -60,7 +60,7 @@ inserter: user-shell: @$(ASM) $(AFLAGS) $(SOURCE_FOLDER)/user-entry.s -o user-entry.o - @$(CC) $(CFLAGS) -fno-pie $(SOURCE_FOLDER)/user-shell.c -o user-shell.o + @$(CC) $(CFLAGS) -fno-pie $(SOURCE_FOLDER)/external/user-shell.c -o user-shell.o @$(LIN) -T $(SOURCE_FOLDER)/user-linker.ld -melf_i386 \ user-entry.o user-shell.o -o $(OUTPUT_FOLDER)/shell @echo Linking object shell object files and generate flat binary... diff --git a/src/user-shell.c b/src/external/user-shell.c similarity index 78% rename from src/user-shell.c rename to src/external/user-shell.c index 3b5a968..4a2cd39 100644 --- a/src/user-shell.c +++ b/src/external/user-shell.c @@ -1,4 +1,4 @@ -#include "lib-header/stdtype.h" +#include "../lib-header/stdtype.h" int main(void) { __asm__ volatile("mov %0, %%eax" : /* */ : "r"(0xDEADBEEF)); From 50f35eebb3bd4fd93f4101d9d0f46adb4eb7e722 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 20:44:50 +0700 Subject: [PATCH 115/176] fix: disable time in fat32.c Note: ini dimatiin dulu buat inserter, nanti dinyalain lagi kalau aman --- src/fat32.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 66c844e..30c1414 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -72,7 +72,7 @@ uint32_t cluster_to_lba(uint32_t cluster){ */ void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uint32_t parent_dir_cluster){ // dir_table->table[0].name[0] = '.'; - get_time(&time, &date); + // get_time(&time, &date); dir_table->table[0].cluster_high = (uint16_t)(parent_dir_cluster >> 16); dir_table->table[0].cluster_low = (uint16_t)(parent_dir_cluster & 0xFFFF); for (uint8_t i = 0; i < 8; i++){ @@ -189,7 +189,7 @@ int8_t read_directory(struct FAT32DriverRequest request){ return 1; } location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; - get_time(&time, &date); + // get_time(&time, &date); driver_state.dir_table_buf.table[i].access_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); read_clusters(request.buf, location, 1); @@ -231,7 +231,7 @@ int8_t read(struct FAT32DriverRequest request){ location = driver_state.fat_table.cluster_map[location]; } } - get_time(&time, &date); + // get_time(&time, &date); driver_state.dir_table_buf.table[i].access_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } @@ -283,7 +283,7 @@ int8_t write(struct FAT32DriverRequest request){ cluster_table++; // Ini index } driver_state.dir_table_buf.table[cluster_table] = new_dir.table[0]; - get_time(&time, &date); + // get_time(&time, &date); // driver_state.dir_table_buf.table[0].modified_date = date; // driver_state.dir_table_buf.table[0].modified_time = time; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); @@ -340,7 +340,7 @@ int8_t write(struct FAT32DriverRequest request){ write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); write_clusters(driver_state.fat_table.cluster_map,1,1); } - get_time(&time, &date); + // get_time(&time, &date); driver_state.dir_table_buf.table[cluster_table].create_date = date; driver_state.dir_table_buf.table[cluster_table].create_time = time; // driver_state.dir_table_buf.table[0].modified_date = date; @@ -388,7 +388,7 @@ int8_t delete(struct FAT32DriverRequest request){ } driver_state.dir_table_buf.table[index] = temp_ent; driver_state.fat_table.cluster_map[location] = 0; - get_time(&time, &date); + // get_time(&time, &date); // driver_state.dir_table_buf.table[0].modified_time = time; // driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.fat_table.cluster_map,1,1); @@ -413,7 +413,7 @@ int8_t delete(struct FAT32DriverRequest request){ } } while (!flag); write_clusters(driver_state.fat_table.cluster_map,1,1); - get_time(&time, &date); + // get_time(&time, &date); // driver_state.dir_table_buf.table[0].modified_time = time; // driver_state.dir_table_buf.table[0].modified_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); From 41b381cf635b1e60306704a24da7535316f7a8f7 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 20:45:28 +0700 Subject: [PATCH 116/176] fix: disable run portio in inserter makefile --- makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/makefile b/makefile index 363460e..5be1af8 100644 --- a/makefile +++ b/makefile @@ -53,7 +53,6 @@ iso: kernel inserter: @$(CC) -Wno-builtin-declaration-mismatch \ $(SOURCE_FOLDER)/stdmem.c \ - $(SOURCE_FOLDER)/portio.c \ $(SOURCE_FOLDER)/fat32.c \ $(SOURCE_FOLDER)/external/external-inserter.c \ -o $(OUTPUT_FOLDER)/inserter From 6b72e52b4087f90e5e2faa07c6f8206113297e0b Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 20:48:01 +0700 Subject: [PATCH 117/176] style: add minor set up for shell in interrupt.c --- src/interrupt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/interrupt.c b/src/interrupt.c index 688cd20..8bdb2c2 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -2,11 +2,13 @@ #include "lib-header/framebuffer.h" #include "lib-header/gdt.h" #include "lib-header/stdmem.h" +#include "lib-header/idt.h" struct TSSEntry _interrupt_tss_entry = { .prev_tss = 0, .esp0 = 0, - .ss0 = 0x10, + .ss0 = GDT_KERNEL_DATA_SEGMENT_SELECTOR, + .unused_register = {0}, }; From fe85fbed3a1c910c0e19723084a57f3e4d91da2e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 20:49:09 +0700 Subject: [PATCH 118/176] style: update kernel to default milstone 3 setting --- src/kernel.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 6f5b775..33778c9 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -19,35 +19,34 @@ void kernel_setup(void) { pic_remap(); initialize_idt(); activate_keyboard_interrupt(); - keyboard_state_activate(); framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); gdt_install_tss(); set_tss_register(); - framebuffer_write(0,0,sizeof(struct FAT32DirectoryEntry),0xe, 0); + // Allocate first 4 MiB virtual memory allocate_single_user_page_frame((uint8_t*) 0); - // Write shell into memory (assuming shell is less than 1 MiB) + // Write shell into memory struct FAT32DriverRequest request = { .buf = (uint8_t*) 0, - .name = "shells", + .name = "shell", .ext = "\0\0\0", .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = 0x1000, + .buffer_size = 0x100000, }; - write(request); + read(request); // Set TSS $esp pointer and jump into shell set_tss_kernel_current_stack(); - kernel_execute_user_program((uint8_t *) 0); // kayaknya di sini salah - int i = 0; - i++; + kernel_execute_user_program((uint8_t*) 0); + while (TRUE); } + /* Struktur folder * * ROOT * ikanaide From 45ae0751acf901b1b6bda7bdaa0c70704f4c4edc Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 20:56:25 +0700 Subject: [PATCH 119/176] feat!: Edit initialize_idt() priv_lvl 0x3 Note: Masuk PageFault --- src/idt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/idt.c b/src/idt.c index 10558c1..bc6f1a1 100644 --- a/src/idt.c +++ b/src/idt.c @@ -20,7 +20,10 @@ void initialize_idt(void) { * Privilege: 0 */ for (int i = 0; i < ISR_STUB_TABLE_LIMIT; i++) { - set_interrupt_gate(i, isr_stub_table[i], GDT_KERNEL_CODE_SEGMENT_SELECTOR, 0); + if (i >= 0x30 && i <= 0x3F) + set_interrupt_gate(i, isr_stub_table[i], GDT_KERNEL_CODE_SEGMENT_SELECTOR, 0x3); + else + set_interrupt_gate(i, isr_stub_table[i], GDT_KERNEL_CODE_SEGMENT_SELECTOR, 0x0); } __asm__ volatile("lidt %0" : : "m"(_idt_idtr)); __asm__ volatile("sti"); From fd86e7721314bf9dbb3b7f55492c9169cbaf1497 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Tue, 4 Apr 2023 21:07:49 +0700 Subject: [PATCH 120/176] feat: add implementation for puts --- src/interrupt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 8bdb2c2..37e5ad0 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -87,10 +87,12 @@ void set_tss_kernel_current_stack(void) { // }; -// TODO: implementasikan sendiri katanya -// void puts(char *str, uint32_t len, uint32_t color) { - -// } +// TODO: implement puts using framebuffer +void puts(char *str, uint32_t len, uint32_t color) { + for (uint32_t i = 0; i < len; i++) { + framebuffer_write(0, i, str[i], color, 0); + } +} void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { @@ -105,7 +107,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta get_keyboard_buffer(buf); memcpy((char *) cpu.ebx, buf, cpu.ecx); } else if (cpu.eax == 5) { - // puts((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side + puts((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side } } From 658d7586299123d5cc9cbd7a0d5884469567bf96 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 5 Apr 2023 12:22:54 +0700 Subject: [PATCH 121/176] style: disable page fault (???) --- src/interrupt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 37e5ad0..d77d3c0 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -114,9 +114,9 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { switch (int_number) { - case PAGE_FAULT: - __asm__("hlt"); - break; + // case PAGE_FAULT: + // __asm__("hlt"); + // break; case PIC1_OFFSET + IRQ_KEYBOARD: keyboard_isr(); break; From 06e553d532e1abcc7ef93ef0130c80c08fbaaa5d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 5 Apr 2023 12:23:29 +0700 Subject: [PATCH 122/176] feat: update user-shell.c for testing syscall --- src/external/user-shell.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 4a2cd39..f9de72b 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -1,7 +1,35 @@ #include "../lib-header/stdtype.h" +#include "../lib-header/fat32.h" + +void syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { + __asm__ volatile("mov %0, %%ebx" : /* */ : "r"(ebx)); + __asm__ volatile("mov %0, %%ecx" : /* */ : "r"(ecx)); + __asm__ volatile("mov %0, %%edx" : /* */ : "r"(edx)); + __asm__ volatile("mov %0, %%eax" : /* */ : "r"(eax)); + // Note : gcc usually use %eax as intermediate register, + // so it need to be the last one to mov + __asm__ volatile("int $0x30"); +} int main(void) { - __asm__ volatile("mov %0, %%eax" : /* */ : "r"(0xDEADBEEF)); - while (TRUE); + struct ClusterBuffer cl = {0}; + struct FAT32DriverRequest request = { + .buf = &cl, + .name = "ikanaide", + .ext = "\0\0\0", + .parent_cluster_number = ROOT_CLUSTER_NUMBER, + .buffer_size = CLUSTER_SIZE, + }; + int32_t retcode; + syscall(0, (uint32_t) &request, (uint32_t) &retcode, 0); + if (retcode == 0) + syscall(5, (uint32_t) "owo\n", 4, 0xF); + + char buf[16]; + while (TRUE) { + syscall(4, (uint32_t) buf, 16, 0); + syscall(5, (uint32_t) buf, 16, 0xF); + } + return 0; } From dedfd089b485feb8e713f974050bd37af221c1fa Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Wed, 5 Apr 2023 12:24:13 +0700 Subject: [PATCH 123/176] refactor: change function name update_pdt --- src/lib-header/paging.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib-header/paging.h b/src/lib-header/paging.h index d5ad2f6..210aa42 100644 --- a/src/lib-header/paging.h +++ b/src/lib-header/paging.h @@ -100,7 +100,7 @@ struct PageDriverState { * @param virtual_addr Virtual address to map * @param flag Page entry flags */ -void update_page_directory(void *physical_addr, void *virtual_addr, struct PageDirectoryEntryFlag flag); +void update_page_directory_entry(void *physical_addr, void *virtual_addr, struct PageDirectoryEntryFlag flag); /** * flush_single_tlb, From 7b012059be8f0837469832d4d5cc5980c1055d64 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 7 Apr 2023 20:54:44 +0700 Subject: [PATCH 124/176] feat: add ctrl + shift + esc mechanism in keyboard Sedang menunggu ide untuk milestone 3 --- src/keyboard.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/keyboard.c b/src/keyboard.c index ec4e3ae..fbce64b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -17,6 +17,7 @@ static int backspaceLine[25] = { 0,0,0,0,0, 0,0,0,0,0 }; + const char keyboard_scancode_1_to_ascii_map[256] = { 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', @@ -231,6 +232,42 @@ void keyboard_isr(void) { keyboard_state.buffer_index = 79; row = 24; } + + /* Ctrl Shift */ + else if (scancode == 0x2A || scancode == 0x36){ + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x2A || scancode == 0x36); + + if (scancode == 0xAA || scancode == 0xB6){ + continue; + /* Ctrl Shift Esc */ + } else if (scancode == 0x01){ + framebuffer_write(24,0,'N',0x0c,0); + framebuffer_write(24,1,'O',0x0c,0); + framebuffer_write(24,3,'T',0x0c,0); + framebuffer_write(24,4,'A',0x0c,0); + framebuffer_write(24,5,'S',0x0c,0); + framebuffer_write(24,6,'K',0x0c,0); + framebuffer_write(24,8,'M',0x0c,0); + framebuffer_write(24,9,'A',0x0c,0); + framebuffer_write(24,10,'N',0x0c,0); + framebuffer_write(24,11,'A',0x0c,0); + framebuffer_write(24,12,'G',0x0c,0); + framebuffer_write(24,13,'E',0x0c,0); + framebuffer_write(24,14,'R',0x0c,0); + framebuffer_write(24,16,'L',0x0d,0); + framebuffer_write(24,17,'O',0x0d,0); + framebuffer_write(24,18,'L',0x0d,0); + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x01); + + for (int i = 0; i < 19; i++){ + framebuffer_write(24, i, ' ', 0x0c, 0); + } + } + } } /* Alt */ From c0300f10bec46875f6d5fe288797b042f85401a4 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 7 Apr 2023 21:46:49 +0700 Subject: [PATCH 125/176] feat: add Ctrl + Alt + Backspace to reset --- src/keyboard.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index fbce64b..d3d13b3 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -262,12 +262,132 @@ void keyboard_isr(void) { do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode == 0x01); - + for (int i = 0; i < 19; i++){ framebuffer_write(24, i, ' ', 0x0c, 0); } } } + + /* Ctrl Alt Backspace */ + /* Karena Ctrl Alt Delete memengaruhi OS aslinya */ + else if (scancode == 0x38){ + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x38); + framebuffer_write(24,2,mapped_char,0x0c,0); + + if (scancode == 0x0e){ + for (int i = 3; i < 20; i == 6 ? i += 10 : i++){ + framebuffer_write(i,0,'S',0x0c,0); + framebuffer_write(i,1,'Y',0x0c,0); + framebuffer_write(i,2,'S',0x0c,0); + framebuffer_write(i,3,'T',0x0c,0); + framebuffer_write(i,4,'E',0x0c,0); + framebuffer_write(i,5,'M',0x0c,0); + framebuffer_write(i,6,' ',0x0c,0); + framebuffer_write(i,7,'R',0x0c,0); + framebuffer_write(i,8,'E',0x0c,0); + framebuffer_write(i,9,'S',0x0c,0); + framebuffer_write(i,10,'E',0x0c,0); + framebuffer_write(i,11,'T',0x0c,0); + framebuffer_write(i,12,'I',0x0c,0); + framebuffer_write(i,13,'N',0x0c,0); + framebuffer_write(i,14,'G',0x0c,0); + framebuffer_write(i,15,' ',0x0c,0); + framebuffer_write(i,16,'P',0x0c,0); + framebuffer_write(i,17,'R',0x0c,0); + framebuffer_write(i,18,'O',0x0c,0); + framebuffer_write(i,19,'G',0x0c,0); + framebuffer_write(i,20,'R',0x0c,0); + framebuffer_write(i,21,'A',0x0c,0); + framebuffer_write(i,22,'M',0x0c,0); + framebuffer_write(i,23,'.',0x0c,0); + framebuffer_write(i,24,'.',0x0c,0); + framebuffer_write(i,25,'.',0x0c,0); + } + for (int i = 0; i < 80; i++){ + + for (int j = 9; j < 14; j++){ + framebuffer_write(j, i, '/', 0x0c, 0); + } + + for (int j = 0; j < 120000; j++){ + io_wait(); + } + + for (int j = 9; j < 14; j++){ + framebuffer_write(j, i, '\\', 0x0c, 0x0); + } + + for (int j = 0; j < 120000; j++){ + io_wait(); + } + + for (int j = 9; j < 14; j++){ + framebuffer_write(j, i, '-', 0x0c, 0x0); + } + + for (int j = 0; j < 120000; j++){ + io_wait(); + } + if (i != 0){ + for (int j = 9; j < 14; j++){ + framebuffer_write(j, i-1, ' ', 0x0c, 0x0c); + } + } + if (i == 79){ + for (int j = 9; j < 14; j++){ + framebuffer_write(j, i, ' ', 0x0c, 0x0c); + } + for (int l = 0; l < 80; l++){ + for (int m = 0; m < 25; m == 8 ? m += 7: m++){ + framebuffer_write(m, l, ' ', 0x0, 0x0); + } + } + for (int j = 0; j < 80; j++){ + for (int l = 8; l < 15; l++){ + framebuffer_write(l, j, ' ', 0x09, 0x09); + } + + for (int k = 0; k < 70000; k++){ + io_wait(); + } + } + for (int j = 10; j < 13; j++){ + framebuffer_write(j, 38, 'S', 0x0, 0x09); + framebuffer_write(j, 39, 'U', 0x0, 0x09); + framebuffer_write(j, 40, 'C', 0x0, 0x09); + framebuffer_write(j, 41, 'C', 0x0, 0x09); + framebuffer_write(j, 42, 'E', 0x0, 0x09); + framebuffer_write(j, 43, 'S', 0x0, 0x09); + framebuffer_write(j, 44, 'S', 0x0, 0x09); + } + + for (int k = 0; k < 5000000; k++){ + io_wait(); + } + + for (int l = 0; l < 40; l++){ + for (int m = 0; m < 25; m++){ + framebuffer_write(m, l, ' ', 0x0, 0x0); + framebuffer_write(m, 80-l, ' ', 0x0, 0x0); + } + for (int k = 0; k < 70000; k++){ + io_wait(); + } + } + + + framebuffer_clear(); + } + } + + } + + } + + } /* Alt */ From 66821e02c27c038a02e5b3bd35014e44b40a6c48 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 7 Apr 2023 22:01:24 +0700 Subject: [PATCH 126/176] fix: update for loop in keyboard to save memory --- src/keyboard.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index d3d13b3..042254b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -278,7 +278,7 @@ void keyboard_isr(void) { framebuffer_write(24,2,mapped_char,0x0c,0); if (scancode == 0x0e){ - for (int i = 3; i < 20; i == 6 ? i += 10 : i++){ + for (uint8_t i = 3; i < 20; i == 6 ? i += 10 : i++){ framebuffer_write(i,0,'S',0x0c,0); framebuffer_write(i,1,'Y',0x0c,0); framebuffer_write(i,2,'S',0x0c,0); @@ -306,55 +306,55 @@ void keyboard_isr(void) { framebuffer_write(i,24,'.',0x0c,0); framebuffer_write(i,25,'.',0x0c,0); } - for (int i = 0; i < 80; i++){ + for (uint8_t i = 0; i < 80; i++){ - for (int j = 9; j < 14; j++){ + for (uint8_t j = 9; j < 14; j++){ framebuffer_write(j, i, '/', 0x0c, 0); } - for (int j = 0; j < 120000; j++){ + for (uint32_t j = 0; j < 120000; j++){ io_wait(); } - for (int j = 9; j < 14; j++){ + for (uint8_t j = 9; j < 14; j++){ framebuffer_write(j, i, '\\', 0x0c, 0x0); } - for (int j = 0; j < 120000; j++){ + for (uint32_t j = 0; j < 120000; j++){ io_wait(); } - for (int j = 9; j < 14; j++){ + for (uint8_t j = 9; j < 14; j++){ framebuffer_write(j, i, '-', 0x0c, 0x0); } - for (int j = 0; j < 120000; j++){ + for (uint32_t j = 0; j < 120000; j++){ io_wait(); } if (i != 0){ - for (int j = 9; j < 14; j++){ + for (uint8_t j = 9; j < 14; j++){ framebuffer_write(j, i-1, ' ', 0x0c, 0x0c); } } if (i == 79){ - for (int j = 9; j < 14; j++){ + for (uint8_t j = 9; j < 14; j++){ framebuffer_write(j, i, ' ', 0x0c, 0x0c); } - for (int l = 0; l < 80; l++){ + for (uint8_t l = 0; l < 80; l++){ for (int m = 0; m < 25; m == 8 ? m += 7: m++){ framebuffer_write(m, l, ' ', 0x0, 0x0); } } - for (int j = 0; j < 80; j++){ - for (int l = 8; l < 15; l++){ + for (uint8_t j = 0; j < 80; j++){ + for (uint8_t l = 8; l < 15; l++){ framebuffer_write(l, j, ' ', 0x09, 0x09); } - for (int k = 0; k < 70000; k++){ + for (uint32_t k = 0; k < 70000; k++){ io_wait(); } } - for (int j = 10; j < 13; j++){ + for (uint8_t j = 10; j < 13; j++){ framebuffer_write(j, 38, 'S', 0x0, 0x09); framebuffer_write(j, 39, 'U', 0x0, 0x09); framebuffer_write(j, 40, 'C', 0x0, 0x09); @@ -364,16 +364,16 @@ void keyboard_isr(void) { framebuffer_write(j, 44, 'S', 0x0, 0x09); } - for (int k = 0; k < 5000000; k++){ + for (uint32_t k = 0; k < 5000000; k++){ io_wait(); } - for (int l = 0; l < 40; l++){ - for (int m = 0; m < 25; m++){ + for (uint8_t l = 0; l < 40; l++){ + for (uint8_t m = 0; m < 25; m++){ framebuffer_write(m, l, ' ', 0x0, 0x0); framebuffer_write(m, 80-l, ' ', 0x0, 0x0); } - for (int k = 0; k < 70000; k++){ + for (uint32_t k = 0; k < 70000; k++){ io_wait(); } } From f907a5fe1f33030e7ee2cf649f87a3af772abcc5 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 8 Apr 2023 17:39:33 +0700 Subject: [PATCH 127/176] fix: fix write bug for small file size number --- src/fat32.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 30c1414..6dd1ed7 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -8,8 +8,8 @@ // static struct FAT32DirectoryEntry root_dir_entry; // static struct FAT32DirectoryTable root_dir_table; struct FAT32DriverState driver_state; -struct Time time; -struct Date date; +// struct Time time; +// struct Date date; // static struct FAT32DriverRequest driver_request; @@ -79,8 +79,8 @@ void init_directory_table(struct FAT32DirectoryTable *dir_table, char *name, uin dir_table->table[0].name[i] = name[i]; } dir_table->table[0].user_attribute = UATTR_NOT_EMPTY; - dir_table->table[0].create_date = date; - dir_table->table[0].create_time = time; + // dir_table->table[0].create_date = date; + // dir_table->table[0].create_time = time; // dir_table->table[1].name[0] = '.'; @@ -190,7 +190,7 @@ int8_t read_directory(struct FAT32DriverRequest request){ } location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; // get_time(&time, &date); - driver_state.dir_table_buf.table[i].access_date = date; + // driver_state.dir_table_buf.table[i].access_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); read_clusters(request.buf, location, 1); break; @@ -232,7 +232,7 @@ int8_t read(struct FAT32DriverRequest request){ } } // get_time(&time, &date); - driver_state.dir_table_buf.table[i].access_date = date; + // driver_state.dir_table_buf.table[i].access_date = date; write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } break; @@ -315,7 +315,7 @@ int8_t write(struct FAT32DriverRequest request){ driver_state.dir_table_buf.table[cluster_table].attribute = 0; driver_state.dir_table_buf.table[cluster_table].user_attribute = UATTR_NOT_EMPTY; driver_state.dir_table_buf.table[cluster_table].cluster_low = cluster; - for (uint32_t i = 0; i < total_cluster + 1; i++){ + for (uint32_t i = 0; i < total_cluster; i++){ cluster = 0; @@ -333,6 +333,7 @@ int8_t write(struct FAT32DriverRequest request){ driver_state.fat_table.cluster_map[cluster] = clusterNext; driver_state.dir_table_buf.table[cluster_table].filesize += 2048; } else { + driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; driver_state.dir_table_buf.table[cluster_table].filesize += request.buffer_size - (CLUSTER_SIZE * i); } @@ -341,10 +342,11 @@ int8_t write(struct FAT32DriverRequest request){ write_clusters(driver_state.fat_table.cluster_map,1,1); } // get_time(&time, &date); - driver_state.dir_table_buf.table[cluster_table].create_date = date; - driver_state.dir_table_buf.table[cluster_table].create_time = time; + // driver_state.dir_table_buf.table[cluster_table].create_date = date; + // driver_state.dir_table_buf.table[cluster_table].create_time = time; // driver_state.dir_table_buf.table[0].modified_date = date; // driver_state.dir_table_buf.table[0].modified_time = time; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } From f057250bb752254b7b9bc147740c93e052cdcefa Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 8 Apr 2023 18:10:50 +0700 Subject: [PATCH 128/176] fix: handle bug when req buf size < 32 --- src/fat32.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 6dd1ed7..757269e 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -259,6 +259,7 @@ int8_t write(struct FAT32DriverRequest request){ uint16_t cluster = 0; uint16_t clusterNext = 0; uint16_t cluster_table = 0; + while (driver_state.fat_table.cluster_map[cluster] != 0){ cluster++; // Ini index } @@ -332,14 +333,20 @@ int8_t write(struct FAT32DriverRequest request){ if (i < total_cluster - 1){ driver_state.fat_table.cluster_map[cluster] = clusterNext; driver_state.dir_table_buf.table[cluster_table].filesize += 2048; - } else { + write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); // rawan + } else { driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; driver_state.dir_table_buf.table[cluster_table].filesize += request.buffer_size - (CLUSTER_SIZE * i); + uint8_t temp[request.buffer_size - (CLUSTER_SIZE * i)]; + memcpy(temp, request.buf + CLUSTER_SIZE * i, request.buffer_size - (CLUSTER_SIZE * i)); + write_clusters(temp, cluster, 1); // rawan + } - - write_clusters(request.buf + CLUSTER_SIZE * i, cluster, 1); + write_clusters(driver_state.fat_table.cluster_map,1,1); + + } // get_time(&time, &date); // driver_state.dir_table_buf.table[cluster_table].create_date = date; @@ -347,6 +354,7 @@ int8_t write(struct FAT32DriverRequest request){ // driver_state.dir_table_buf.table[0].modified_date = date; // driver_state.dir_table_buf.table[0].modified_time = time; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } From e562e9cea5b57858bf66ab0e4e7848bdff84dc0e Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 8 Apr 2023 20:37:42 +0700 Subject: [PATCH 129/176] feat: update launch.json and makefile (user-shell) --- .vscode/launch.json | 6 +++++- makefile | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ca6c8fc..06592b4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -31,11 +31,15 @@ "text": "symbol-file kernel", "description": "Get kernel symbols" }, + { + "text": "add-symbol-file shell_elf", + "description": "Get shell symbols" + }, { "text": "set output-radix 16", "description": "Use hexadecimal output" } - ], + ], "avoidWindowsConsoleRedirection": true }, ] diff --git a/makefile b/makefile index 5be1af8..7c24a59 100644 --- a/makefile +++ b/makefile @@ -63,6 +63,9 @@ user-shell: @$(LIN) -T $(SOURCE_FOLDER)/user-linker.ld -melf_i386 \ user-entry.o user-shell.o -o $(OUTPUT_FOLDER)/shell @echo Linking object shell object files and generate flat binary... + @$(LIN) -T $(SOURCE_FOLDER)/user-linker.ld -melf_i386 --oformat=elf32-i386\ + user-entry.o user-shell.o -o $(OUTPUT_FOLDER)/shell_elf + @echo Linking object shell object files and generate ELF32 for debugging... @size --target=binary bin/shell @rm -f *.o From cc34151a367845f0e31733d582a249d41141f565 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 07:11:49 +0700 Subject: [PATCH 130/176] fix: fix error read in fat32 --- src/fat32.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/fat32.c b/src/fat32.c index 757269e..3cb014a 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -221,20 +221,21 @@ int8_t read(struct FAT32DriverRequest request){ total_cluster = driver_state.dir_table_buf.table[i].filesize / CLUSTER_SIZE; if (total_cluster * CLUSTER_SIZE < driver_state.dir_table_buf.table[i].filesize){ total_cluster += 1; - } else { - location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; - for (uint32_t j = 0; j < total_cluster; j++){ - if (j == 0){ - read_clusters(request.buf + CLUSTER_SIZE * j, location, 1); - } else { - read_clusters(request.buf + CLUSTER_SIZE * j, driver_state.fat_table.cluster_map[location], 1); - location = driver_state.fat_table.cluster_map[location]; - } + } + + location = (driver_state.dir_table_buf.table[i].cluster_high << 16) | driver_state.dir_table_buf.table[i].cluster_low; + for (uint32_t j = 0; j < total_cluster; j++){ + if (j == 0){ + read_clusters(request.buf + CLUSTER_SIZE * j, location, 1); + } else { + read_clusters(request.buf + CLUSTER_SIZE * j, driver_state.fat_table.cluster_map[location], 1); + location = driver_state.fat_table.cluster_map[location]; } - // get_time(&time, &date); - // driver_state.dir_table_buf.table[i].access_date = date; - write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); } + // get_time(&time, &date); + // driver_state.dir_table_buf.table[i].access_date = date; + write_clusters(driver_state.dir_table_buf.table, request.parent_cluster_number,1); + break; } From 18cf06ca2541c8eb6ccdf71df89e9ede7c492829 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 07:42:33 +0700 Subject: [PATCH 131/176] fix: write, temp tadinya gadiisi jadi ada fs sign --- src/fat32.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fat32.c b/src/fat32.c index 3cb014a..6388be5 100644 --- a/src/fat32.c +++ b/src/fat32.c @@ -339,8 +339,11 @@ int8_t write(struct FAT32DriverRequest request){ } else { driver_state.fat_table.cluster_map[cluster] = FAT32_FAT_END_OF_FILE; driver_state.dir_table_buf.table[cluster_table].filesize += request.buffer_size - (CLUSTER_SIZE * i); - uint8_t temp[request.buffer_size - (CLUSTER_SIZE * i)]; + uint8_t temp[CLUSTER_SIZE]; memcpy(temp, request.buf + CLUSTER_SIZE * i, request.buffer_size - (CLUSTER_SIZE * i)); + for (int j = request.buffer_size - (CLUSTER_SIZE * i); j < CLUSTER_SIZE; j++){ + temp[j] = 0; + } write_clusters(temp, cluster, 1); // rawan } From 438a85fa08190cf640066f526e35d075311aa7a6 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 14:08:18 +0700 Subject: [PATCH 132/176] fix: Keyboard Error - fixed keyboard indexing error - fixed keyboard state buffer not sync --- src/keyboard.c | 61 +++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 042254b..b13b07f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4,6 +4,7 @@ #include "lib-header/framebuffer.h" static struct KeyboardDriverState keyboard_state; static int row = 0; +static int col = 0; static char antiDouble = -1; static int holding = 0; static char charHold = -1; @@ -93,6 +94,8 @@ void keyboard_isr(void) { framebuffer_write(21,11,'L',0xa,0); } else { + keyboard_state.buffer_index = 0; + col = 14; while (is_keyboard_blocking()){ uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; @@ -103,26 +106,26 @@ void keyboard_isr(void) { /* Backspace */ if (mapped_char == '\b') { - if (keyboard_state.buffer_index) { + if (col) { keyboard_state.buffer_index--; + col--; backspaceLine[row]--; - } else if (keyboard_state.buffer_index == 0){ + } else if (col == 0){ if (row <= 0) { row = 0; } else { row--; - keyboard_state.buffer_index = backspaceLine[row]; + col = backspaceLine[row]; } } - framebuffer_write(row, keyboard_state.buffer_index, 0, 0x0c, 0); - framebuffer_set_cursor(row, keyboard_state.buffer_index); + framebuffer_write(row, col, 0, 0x0c, 0); + framebuffer_set_cursor(row, col); } /* Enter (deactivate keyboard) */ else if (mapped_char=='\n') { keyboard_state.buffer_index=0; - keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = 0; - framebuffer_set_cursor(row + 1, keyboard_state.buffer_index); + framebuffer_set_cursor(row + 1, col); mapped_char = 0; if (row >= 24) { row = 24; @@ -136,7 +139,7 @@ void keyboard_isr(void) { else if (scancode == 0x48){ if (row > 0){ row--; - framebuffer_set_cursor(row, keyboard_state.buffer_index); + framebuffer_set_cursor(row, col); do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode != 0xc8); @@ -147,7 +150,7 @@ void keyboard_isr(void) { else if (scancode == 0x50){ if (row < 24){ row++; - framebuffer_set_cursor(row, keyboard_state.buffer_index); + framebuffer_set_cursor(row, col); do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode != 0xd0); @@ -156,9 +159,10 @@ void keyboard_isr(void) { /* Left Arrow (no holding) */ else if (scancode == 0x4b){ - if (keyboard_state.buffer_index > 0){ + if (col > 0){ keyboard_state.buffer_index--; - framebuffer_set_cursor(row, keyboard_state.buffer_index); + col--; + framebuffer_set_cursor(row, col); do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode != 0xcb); @@ -167,9 +171,10 @@ void keyboard_isr(void) { /* Right Arrow (no holding) */ else if (scancode == 0x4d){ - if (keyboard_state.buffer_index < 79){ + if (col < 79){ keyboard_state.buffer_index++; - framebuffer_set_cursor(row, keyboard_state.buffer_index); + col++; + framebuffer_set_cursor(row, col); do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode != 0xcd); @@ -214,6 +219,7 @@ void keyboard_isr(void) { if (scancode == 0x47){ framebuffer_set_cursor(0, 0); keyboard_state.buffer_index = 0; + col = 0; row = 0; } @@ -221,6 +227,7 @@ void keyboard_isr(void) { else if (scancode == 0x1C){ framebuffer_set_cursor(0, 0); keyboard_state.buffer_index = 0; + col = 0; row = 0; restoreSplash = TRUE; keyboard_state_deactivate(); @@ -229,7 +236,8 @@ void keyboard_isr(void) { /* Ctrl End */ else if (scancode == 0x4F){ framebuffer_set_cursor(24, 79); - keyboard_state.buffer_index = 79; + keyboard_state.buffer_index = 79; //z + col = 79; row = 24; } @@ -405,7 +413,7 @@ void keyboard_isr(void) { /* Home */ else if (scancode == 0x47){ framebuffer_set_cursor(row, 0); - keyboard_state.buffer_index = 0; + col = 0; do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode == 0x47); @@ -414,7 +422,7 @@ void keyboard_isr(void) { /* End */ else if (scancode == 0x4F){ framebuffer_set_cursor(row, 79); - keyboard_state.buffer_index = 79; + col = 79; do { scancode = in(KEYBOARD_DATA_PORT); } while (scancode == 0x4F); @@ -435,27 +443,34 @@ void keyboard_isr(void) { mapped_char += 32; } } - framebuffer_write(row, keyboard_state.buffer_index, mapped_char, 0x0c, 0); + + keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; + // framebuffer_write(20, col, keyboard_state.keyboard_buffer[keyboard_state.buffer_index], 0x0c, 0); + keyboard_state.buffer_index++; + framebuffer_write(row, col, mapped_char, 0x0c, 0); + - if (keyboard_state.buffer_index >= 79){ + if (col >= 79){ if (row >= 24) { row = 24; } else { row++; } - keyboard_state.buffer_index = 0; + col = 0; } else { - keyboard_state.buffer_index++; + col++; backspaceLine[row]++; - keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; } - if (keyboard_state.buffer_index >= 79 && row < 24){ + + if (col >= 79 && row < 24){ framebuffer_set_cursor(row + 1, 0); } else if (row >= 24){ framebuffer_set_cursor(24, 0); } else { - framebuffer_set_cursor(row, keyboard_state.buffer_index); + framebuffer_set_cursor(row, col); } + + } else { } From dd53bb4b84d88d0da48240b2cbb176b4c9f982f4 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 14:14:56 +0700 Subject: [PATCH 133/176] feat: add set up for shell - default qemu state added - add template after every enter --- src/interrupt.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index d77d3c0..945ad54 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -4,6 +4,8 @@ #include "lib-header/stdmem.h" #include "lib-header/idt.h" +uint8_t row_shell = 0; + struct TSSEntry _interrupt_tss_entry = { .prev_tss = 0, .esp0 = 0, @@ -90,16 +92,33 @@ void set_tss_kernel_current_stack(void) { // TODO: implement puts using framebuffer void puts(char *str, uint32_t len, uint32_t color) { for (uint32_t i = 0; i < len; i++) { - framebuffer_write(0, i, str[i], color, 0); + framebuffer_write(row_shell, i, str[i], color, 0); } } +void puts2(char *str, uint32_t len, uint32_t color) { + for (uint32_t i = 0; i < len; i++) { + framebuffer_write(24, i, str[i], color, 0); + } +} + +void template(void){ + puts("Brother420/", 11, 0x0a); + framebuffer_write(row_shell, 11, ':', 0x01, 0); + framebuffer_write(row_shell, 12, '$', 0x0F, 0); + framebuffer_set_cursor(row_shell, 14); + row_shell++; +} void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; *((int8_t*) cpu.ecx) = read(request); + // if (*((int8_t*) cpu.ecx) == 0){ + // puts(request.buf, request.buffer_size, 0x0e); + // } } else if (cpu.eax == 4) { + template(); keyboard_state_activate(); __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called while (is_keyboard_blocking()); @@ -107,16 +126,15 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta get_keyboard_buffer(buf); memcpy((char *) cpu.ebx, buf, cpu.ecx); } else if (cpu.eax == 5) { - puts((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side + // ini berarti di-enter dari syscall 4 + + puts2((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side } } -void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { - switch (int_number) { - // case PAGE_FAULT: - // __asm__("hlt"); - // break; +void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { switch (int_number) { + case PIC1_OFFSET + IRQ_KEYBOARD: keyboard_isr(); break; From 882e286695d6a00e6b60d3bd51dbd32240893acc Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 14:37:10 +0700 Subject: [PATCH 134/176] feat: add command reader input - getCommandInput will return value based on user input - cd ls mkdir cat cp rm mv and whereis can be detected --- src/interrupt.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index 945ad54..ce59a12 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -110,6 +110,37 @@ void template(void){ row_shell++; } +/** + * cd - Mengganti current working directory (termasuk .. untuk naik) + * ls - Menuliskan isi current working directory + * mkdir - Membuat sebuah folder kosong baru + * cat - Menuliskan sebuah file sebagai text file ke layar (Gunakan format LF newline) + * cp - Mengcopy suatu file + * rm - Menghapus suatu file atau folder kosong + * mv - Memindah dan merename lokasi file/folder + * whereis - Mencari file/folder dengan nama yang sama diseluruh file system + + * @return 0 cd (spasi) + * @return 1 ls + * @return 2 mkdir (spasi) + * @return 3 cat (spasi) + * @return 4 cp (spasi) + * @return 5 rm (spasi) + * @return 6 mv (spasi) + * @return 7 whereis (spasi) +*/ +uint8_t getCommandInput(char *input, uint8_t len){ + char *command[] = {"cd ", "ls", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis "}; + uint8_t command_len[] = {3, 2, 6, 4, 3, 3, 3, 8}; + for (uint8_t i = 0; i < 8; i++){ + if (len >= command_len[i] && memcmp(input, command[i], command_len[i]) == 0){ + return i; + } + framebuffer_write(23, i, input[i], 0x0f, 0); + } + return 255; +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -128,6 +159,48 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta } else if (cpu.eax == 5) { // ini berarti di-enter dari syscall 4 + uint8_t command = getCommandInput((char *) cpu.ebx, cpu.ecx); + + switch (command){ + case 0: + // cd + framebuffer_write(0, 70, '0', 0x0f, 0); + break; + case 1: + // ls + framebuffer_write(0, 70, '1', 0x0f, 0); + break; + case 2: + // mkdir + framebuffer_write(0, 70, '2', 0x0f, 0); + break; + case 3: + // cat + framebuffer_write(0, 70, '3', 0x0f, 0); + break; + case 4: + // cp + framebuffer_write(0, 70, '4', 0x0f, 0); + break; + case 5: + // rm + framebuffer_write(0, 70, '5', 0x0f, 0); + break; + case 6: + // mv + framebuffer_write(0, 70, '6', 0x0f, 0); + break; + case 7: + // whereis + framebuffer_write(0, 70, '7', 0x0f, 0); + break; + default: + // command not found + framebuffer_write(0, 70, 'x', 0x0f, 0); + break; + } + + puts2((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side } } From 1243ff44098858b69315f5813d784d31d5d25ff6 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 14:38:16 +0700 Subject: [PATCH 135/176] style: easier method to run - 'make dsr' to run make disk, make insert-shell, and make run --- makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/makefile b/makefile index 7c24a59..73af3e1 100644 --- a/makefile +++ b/makefile @@ -73,3 +73,6 @@ insert-shell: inserter user-shell @echo Inserting shell into root directory... @cd $(OUTPUT_FOLDER); ./inserter shell 2 $(DISK_NAME).bin +ds: disk insert-shell + +dsr: ds run From 66b8cc42b96697d0b296bc5f4a4358675ddfc1e8 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 15:38:18 +0700 Subject: [PATCH 136/176] feat: add implement for ls file changed: - interrupt.c - keyboard.h - keyboard.c ls command will write all folder and file in dir issue: - sometimes keyboard will be disabled forever after enter --- src/interrupt.c | 35 +++++++++++++++++++++++++++++++++++ src/keyboard.c | 5 +++++ src/lib-header/keyboard.h | 5 +++++ 3 files changed, 45 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index ce59a12..db6ecb5 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -5,6 +5,7 @@ #include "lib-header/idt.h" uint8_t row_shell = 0; +int current_directory_cluster = ROOT_CLUSTER_NUMBER; struct TSSEntry _interrupt_tss_entry = { .prev_tss = 0, @@ -141,6 +142,39 @@ uint8_t getCommandInput(char *input, uint8_t len){ return 255; } +void puts_line(char *input, int row, int col, int length, int color){ + for (int i = 0; i < length; i++){ + framebuffer_write(row, col + i, input[i], color, 0); + } +} + + +void command_call_ls(void){ + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + + int col = 0; + int row_add_needed = 1; + + for (int i = 1; i < 64; i++){ + + if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ + if (col == 5){ + col = 0; + row_shell++; + row_add_needed++; + } + puts_line(state_driver.dir_table_buf.table[i].name, row_shell, col*16, 8, 0x0f); + col++; + } + } + row_shell++; + + addRow(row_add_needed); + +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -169,6 +203,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 1: // ls framebuffer_write(0, 70, '1', 0x0f, 0); + command_call_ls(); break; case 2: // mkdir diff --git a/src/keyboard.c b/src/keyboard.c index b13b07f..c38d3f2 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -63,6 +63,11 @@ bool is_keyboard_blocking(void){ return keyboard_state.keyboard_input_on; } +// Add more row +void addRow(int n){ + row += n; +} + bool altF4(){ return altFour; } diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index c84098d..5daffef 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -75,4 +75,9 @@ bool is_keyboard_blocking(void); */ void keyboard_isr(void); +/** + * Menambahkan row pada keyboard +*/ +void addRow(int row); + #endif \ No newline at end of file From e7850ecb5c401763346bb75e93383bb1ad84dc03 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 15:39:42 +0700 Subject: [PATCH 137/176] style: add debugger for shell file changed: - kernel.c - user-shell.c easiest way to run shell is to do 'make dsr' --- src/external/user-shell.c | 4 +- src/kernel.c | 109 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index f9de72b..d2f200b 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -18,12 +18,12 @@ int main(void) { .name = "ikanaide", .ext = "\0\0\0", .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = CLUSTER_SIZE, + .buffer_size = 20, }; int32_t retcode; syscall(0, (uint32_t) &request, (uint32_t) &retcode, 0); if (retcode == 0) - syscall(5, (uint32_t) "owo\n", 4, 0xF); + syscall(5, (uint32_t) "eswoss\n", 4, 0xF); char buf[16]; while (TRUE) { diff --git a/src/kernel.c b/src/kernel.c index 33778c9..d668d0b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -22,6 +22,24 @@ void kernel_setup(void) { framebuffer_clear(); framebuffer_set_cursor(0, 0); initialize_filesystem_fat32(); + + struct ClusterBuffer cbuf[5]; + for (uint32_t i = 0; i < 5; i++) + for (uint32_t j = 0; j < CLUSTER_SIZE; j++) + cbuf[i].buf[j] = i + 'a'; + + struct FAT32DriverRequest requester = { + .buf = cbuf, + .name = "ikanaide", + .ext = "\0\0\0", + .parent_cluster_number = ROOT_CLUSTER_NUMBER, + .buffer_size = 20, + }; + for (uint32_t i = 0; i < 15; i++){ + write(requester); + requester.name[0]++; + } + gdt_install_tss(); set_tss_register(); @@ -46,6 +64,97 @@ void kernel_setup(void) { } +// void kernel_setup(void){ +// enter_protected_mode(&_gdt_gdtr); +// /* Remap PIC */ +// pic_remap(); +// initialize_idt(); +// framebuffer_clear(); +// framebuffer_set_cursor(0, 0); +// initialize_filesystem_fat32(); + +// /* Initialize keyboard */ +// activate_keyboard_interrupt(); + +// /* Initialize cbuf for debugging */ +// struct ClusterBuffer cbuf[5]; +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// cbuf[i].buf[j] = i + 'a'; + +// struct ClusterBuffer ebuf[5]; +// for (uint32_t i = 0; i < 5; i++) +// for (uint32_t j = 0; j < CLUSTER_SIZE; j++) +// ebuf[i].buf[j] = i + 'A'; + +// /* Initialize request for debugging */ +// struct FAT32DriverRequest request = { +// .buf = cbuf, +// .name = "ikanaide", +// .ext = "\0\0\0", +// .parent_cluster_number = ROOT_CLUSTER_NUMBER, +// .buffer_size = 20, +// }; + +// /* Folder ikanaide attached to ROOT */ +// write(request); +// request.buf = ebuf; +// request.buffer_size = 19; +// read(request); // Create folder "ikanaide" +// int i = 0; +// i++; +// while (TRUE); +// } + +// void kernel_setup(void) { +// enter_protected_mode(&_gdt_gdtr); +// pic_remap(); +// initialize_idt(); +// activate_keyboard_interrupt(); +// keyboard_state_activate(); +// framebuffer_clear(); +// framebuffer_set_cursor(0, 0); +// initialize_filesystem_fat32(); +// gdt_install_tss(); +// set_tss_register(); + +// // Allocate first 4 MiB virtual memory +// allocate_single_user_page_frame((uint8_t*) 0); + +// // Write shell into memory +// struct FAT32DriverRequest request = { +// .buf = (uint8_t*) 0, +// .name = "shell", +// .ext = "\0\0\0", +// .parent_cluster_number = ROOT_CLUSTER_NUMBER, +// .buffer_size = 0x100000, +// }; +// read(request); + +// struct ClusterBuffer cbuf[1]; +// cbuf->buf[0] = 't'; +// cbuf->buf[1] = 'e'; +// cbuf->buf[2] = 's'; +// cbuf->buf[3] = 't'; +// cbuf->buf[4] = 'e'; +// cbuf->buf[5] = 'r'; + +// request.buf = cbuf; +// memcpy(request.name, "ikanaide", 8); +// memcpy(request.ext, "\0\0\0", 3); +// request.parent_cluster_number = ROOT_CLUSTER_NUMBER; +// request.buffer_size = 6; + +// write(request); + +// // Set TSS $esp pointer and jump into shell +// set_tss_kernel_current_stack(); +// kernel_execute_user_program((uint8_t*) 0); + +// while (TRUE); +// } + + /* Struktur folder * * ROOT From 931c1fb20acca119dfd9f4e6c35e2a7db2933ed7 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 16:14:35 +0700 Subject: [PATCH 138/176] feat: add mkdir implement file changed: - interrupt.c mkdir will make folder with name input example: mkdir hello issue: - invalid name for folder - name too long or too short --- src/interrupt.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index db6ecb5..2e5b770 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -175,6 +175,20 @@ void command_call_ls(void){ } +void command_call_mkdir(char *dirCommandName){ + + struct FAT32DriverRequest request = { + .buf = 0, + .ext = "\0\0\0", + .parent_cluster_number = current_directory_cluster, + .buffer_size = 0, + }; + for (int i = 6; i < 14; i++){ + request.name[i-6] = dirCommandName[i]; + } + write(request); +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -208,6 +222,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 2: // mkdir framebuffer_write(0, 70, '2', 0x0f, 0); + command_call_mkdir((char *) cpu.ebx); break; case 3: // cat From ed4bdd709bb5c5af4f2ddc4a99e5209c18c044cc Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 17:53:56 +0700 Subject: [PATCH 139/176] feat: add cp implement files changed: - interrupt.c - kernel.c - user-shell.c commit information: - changing ext ikanaide in kernel to uwu - changing ecx input while calling syscall - add implementation for copy file mechanism - to call this you can do "cp file.ext new_file.ext" - example: cp ikanaide.uwu ikan.txt issue: - after calling cp, the program crash - sometimes keyboard totally disabled after enter --- src/external/user-shell.c | 4 +- src/interrupt.c | 115 +++++++++++++++++++++++++++++++++++++- src/kernel.c | 2 +- 3 files changed, 116 insertions(+), 5 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index d2f200b..f243619 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -27,8 +27,8 @@ int main(void) { char buf[16]; while (TRUE) { - syscall(4, (uint32_t) buf, 16, 0); - syscall(5, (uint32_t) buf, 16, 0xF); + syscall(4, (uint32_t) buf, 0x20, 0); + syscall(5, (uint32_t) buf, 0x20, 0xF); } return 0; diff --git a/src/interrupt.c b/src/interrupt.c index 2e5b770..4a8463c 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -189,6 +189,113 @@ void command_call_mkdir(char *dirCommandName){ write(request); } +void command_call_cp(char *cpCommandName){ + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((cpCommandName[i+3] != '.') && (cpCommandName[i+3] != ' ') && (i < 8)){ + request.name[i] = cpCommandName[i+3]; + i++; + } + + if (cpCommandName[i+3] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (i == 8 && cpCommandName[i+3] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + while ((cpCommandName[j+3] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = cpCommandName[j+3]; + j++; + } + + if (j-i-1 == 3 && cpCommandName[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + read(request); + break; + } + } + } + + uint8_t k = 0; + uint8_t l = 0; + while ((cpCommandName[j+4] != '.') && (cpCommandName[j+4] != ' ') && (k < 8)){ + request.name[k] = cpCommandName[j+4]; + k++; + j++; + } + + if (cpCommandName[j+4] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (k == 8 && cpCommandName[j+4] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + if (k < 8){ + for (int z = k; z < 8; z++){ + request.name[z] = '\0'; + } + } + + while ((cpCommandName[l+j+5] != ' ') && cpCommandName[l+j+5] != '\0' && (l < 3)){ + request.ext[l] = cpCommandName[l+j+5]; + l++; + } + + if (l == 3 && ((cpCommandName[l+j+5] != ' ') && (cpCommandName[l+j+5] != '\0'))){ + // Error karena extensi terlalu panjang + return; + } + + if (l < 3){ + for (int z = l; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + write(request); + + +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -231,6 +338,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 4: // cp framebuffer_write(0, 70, '4', 0x0f, 0); + command_call_cp((char *) cpu.ebx); break; case 5: // rm @@ -256,7 +364,9 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta } -void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { switch (int_number) { +void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct InterruptStack info) { + + switch (int_number) { case PIC1_OFFSET + IRQ_KEYBOARD: keyboard_isr(); @@ -264,6 +374,7 @@ void main_interrupt_handler(struct CPURegister cpu, uint32_t int_number, struct case 0x30: syscall(cpu, info); break; - } + + }; } diff --git a/src/kernel.c b/src/kernel.c index d668d0b..1102d8a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -31,7 +31,7 @@ void kernel_setup(void) { struct FAT32DriverRequest requester = { .buf = cbuf, .name = "ikanaide", - .ext = "\0\0\0", + .ext = "uwu", .parent_cluster_number = ROOT_CLUSTER_NUMBER, .buffer_size = 20, }; From 658857287312d4dd6af4c7924bd7f53a4ba597d8 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 19:06:03 +0700 Subject: [PATCH 140/176] feat: add rm implement file changed: - interrupt.c information: - rm can remove file or empty folder - to test rm you can do "rm file.ext" - example: rm vkanaide.uwu issue: - sometimes keyboard totally disabled after enter --- src/interrupt.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index 4a8463c..7bf2f83 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -296,6 +296,76 @@ void command_call_cp(char *cpCommandName){ } + +void command_call_rm(char *rmCommandName){ + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + bool isFolder = FALSE; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((rmCommandName[i+3] != '.') && (rmCommandName[i+3] != ' ') && (i < 8)){ + request.name[i] = rmCommandName[i+3]; + i++; + } + + if (rmCommandName[i+3] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (rmCommandName[i+3] == '\0'){ + // berarti folder + isFolder = TRUE; + for (int z = 0; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + if (!isFolder){ + j = i+1; + while ((rmCommandName[j+3] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = rmCommandName[j+3]; + j++; + } + + if (j-i-1 == 3 && rmCommandName[j+3] != '\0' && rmCommandName[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + } + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + delete(request); + break; + } + } + } +} + + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -343,6 +413,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 5: // rm framebuffer_write(0, 70, '5', 0x0f, 0); + command_call_rm((char *) cpu.ebx); break; case 6: // mv From c80812a26d3d6c67d1e8ae949baf4280680ffdcd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 20:38:54 +0700 Subject: [PATCH 141/176] feat: add cat implement files changed: - interrupt.c - kernel.c info: - add new file that has ikanaide song in it - add implementation for show file to qemu mechanism - to call this you can do "cat file.ext" - example: cat ikanaide.uwu - to run program you can do "make dsr" issue: - after calling cat, the program crash - sometimes keyboard totally disabled after enter --- src/interrupt.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++ src/kernel.c | 22 ++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/src/interrupt.c b/src/interrupt.c index 7bf2f83..490d589 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -103,6 +103,28 @@ void puts2(char *str, uint32_t len, uint32_t color) { } } +void puts_long_text(char *str, uint32_t len, uint32_t color) { + uint8_t j = 0; + uint8_t k = 0; + for (uint32_t i = 0; i < len; i++) { + if (j == 80) { + row_shell++; + j = 0; + k++; + } + if (str[i] == '\n') { + row_shell++; + j = 0; + k++; + continue; + } + framebuffer_write(row_shell, j, str[i], color, 0); + j++; + } + addRow(k); +} + + void template(void){ puts("Brother420/", 11, 0x0a); framebuffer_write(row_shell, 11, ':', 0x01, 0); @@ -366,6 +388,71 @@ void command_call_rm(char *rmCommandName){ } +void command_call_cat(char *rmCommandName){ + // asumsi file only + + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((rmCommandName[i+4] != '.') && (rmCommandName[i+4] != ' ') && (i < 8)){ + request.name[i] = rmCommandName[i+4]; + i++; + } + + if (rmCommandName[i+4] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + while ((rmCommandName[j+4] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = rmCommandName[j+4]; + j++; + } + + if (j-i-1 == 4 && rmCommandName[j+4] != '\0' && rmCommandName[j+4] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + read(request); + break; + } + } + } + + puts_long_text(request.buf, request.buffer_size, 0x0e); + + framebuffer_write(23, 79, 'L', 0x0F, 0x00); + +} + + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -404,6 +491,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 3: // cat framebuffer_write(0, 70, '3', 0x0f, 0); + command_call_cat((char *) cpu.ebx); break; case 4: // cp diff --git a/src/kernel.c b/src/kernel.c index 1102d8a..c6cbda5 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -36,9 +36,29 @@ void kernel_setup(void) { .buffer_size = 20, }; for (uint32_t i = 0; i < 15; i++){ - write(requester); requester.name[0]++; + write(requester); } + delete(requester); + + struct ClusterBuffer ebuf = { + "Nandemonai to kuchi o tsugunda\n" + "Honto wa chotto ashi o tometakute\n" + "Dakedomo kimi wa hayaashi de sutto mae o iku kara\n" + "Boku wa sore o mitsumeteru\n" + + "saishuubin kimi wa noru boku o oitette\n" + "Hashiridasu yukkuri to\n" + "Jimen ga zureteiku\n" + "Naicha dame naicha dame\n" + "Demo honto wa iitai yo\n" + "Ikanaide\n" + }; + + requester.name[0] = 'i'; + requester.buffer_size = 0x120; + requester.buf = &ebuf; + write(requester); gdt_install_tss(); set_tss_register(); From 858a39fcfd2c6ff3c58e4e61477e4e5a6efd4a1c Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 22:12:49 +0700 Subject: [PATCH 142/176] feat: add directorystack header files changed: - directorystack.h info: - add new file that i directorystack.h - directorystack.h is a header to get dir name stack issue: - hard to test --- src/lib-header/directorystack.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/lib-header/directorystack.h diff --git a/src/lib-header/directorystack.h b/src/lib-header/directorystack.h new file mode 100644 index 0000000..c78a6f5 --- /dev/null +++ b/src/lib-header/directorystack.h @@ -0,0 +1,26 @@ +#ifndef _DIRECTORSTACK_H +#define _DIRECTORSTACK_H + +struct DIR_STACK_NAME { + char name[8]; +}; + +struct DIR_STACK { + struct DIR_STACK_NAME stack[256]; + int top; +}; + +void init_dir_stack(struct DIR_STACK *stack); + +void push_dir(struct DIR_STACK * ds, char name[8]); + +char* pop_dir(struct DIR_STACK * ds); + +char* get_top_dir(struct DIR_STACK * ds); + +void reverse_dir(struct DIR_STACK * ds); + +struct DIR_STACK get_dir_stack(char * request, int * validate); + + +#endif \ No newline at end of file From 3234a06aa9e22fbba995597a654c52682556b338 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 22:17:32 +0700 Subject: [PATCH 143/176] feat: add implementation of directorystack.h files changed: - directorystack.c info: - init_dir_stack is to initialize new stack - push_dir is to push string with len = 8 to stack - pop_dir is to pop the stack and return the popped value - get_top_dir is to get the top value of the stack - reverse_dir is to reverse the stack, needed after every process - get_dir_stack is to get the directory stack by accepting full direct issue: - has only been tested using , library --- src/directorystack.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/directorystack.c diff --git a/src/directorystack.c b/src/directorystack.c new file mode 100644 index 0000000..84509fe --- /dev/null +++ b/src/directorystack.c @@ -0,0 +1,69 @@ +#include "lib-header/directorystack.h" +#include "lib-header/stdtype.h" +#include "lib-header/stdmem.h" + +void init_dir_stack(struct DIR_STACK *stack) { + stack->top = -1; +} + +void push_dir(struct DIR_STACK * ds, char name[8]){ + ds->top++; + memcpy(ds->stack[ds->top].name, name, 8); +} + +char * pop_dir(struct DIR_STACK * ds){ + if (ds->top == -1) + return "\0"; + char * name = ds->stack[ds->top].name; + ds->top--; + return name; +} + +char* get_top_dir(struct DIR_STACK * ds){ + return ds->stack[ds->top].name; +} + +void reverse_dir(struct DIR_STACK * ds){ + int i = 0; + int j = ds->top; + while (i < j){ + char temp[8]; + memcpy(temp, ds->stack[i].name, 8); + memcpy(ds->stack[i].name, ds->stack[j].name, 8); + memcpy(ds->stack[j].name, temp, 8); + i++; + j--; + } +} + + +struct DIR_STACK get_dir_stack(char * request, int * validate){ + struct DIR_STACK ds; + init_dir_stack(&ds); + int i = 0; + + while (request[i] != '\0'){ + if (request[i] == '/'){ + i++; + continue; + } + char name[8]; + int j = 0; + while (request[i] != '/' && request[i] != '\0'){ + name[j] = request[i]; + i++; + j++; + } + if (j > 8){ + *validate = 0; + return ds; + } + while (j < 8){ + name[j] = '\0'; + j++; + } + push_dir(&ds, name); + } + + return ds; +} \ No newline at end of file From 5626d4c647fdcc6ea0c12895acd13187422ae4fd Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sun, 9 Apr 2023 22:19:23 +0700 Subject: [PATCH 144/176] feat: add directorystack tester files changed: - testDir.c info: - to test this, you need to modify memcpy in the directorystack.c issue: - need to modify some function to test it --- src/external/testDir.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/external/testDir.c diff --git a/src/external/testDir.c b/src/external/testDir.c new file mode 100644 index 0000000..bf4c9d2 --- /dev/null +++ b/src/external/testDir.c @@ -0,0 +1,22 @@ +// #include "stdmem.c" + +#include +#include +#include "../directorystack.c" + +int main() { + char * request = "/home/abc/def/ghi"; + int validate = 1; + struct DIR_STACK ds = get_dir_stack(request, &validate); + if (validate == 0){ + printf("Invalid request\n"); + return 0; + } + reverse_dir(&ds); + char * name = pop_dir(&ds); + while (name[0] != '\0'){ + printf("%s\n", name); + name = pop_dir(&ds); + } + return 0; +} \ No newline at end of file From f57e20dd4c5e7e9c8d0f1a4b49e8920bd0386cc3 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 08:03:29 +0700 Subject: [PATCH 145/176] feat: add cd implement files changed: - interrupt.c info: - add implementation for changing directory - to call this you can do "cd folder" - example: cd akanaide - do "ls" to check if it is success - to run program you can do "make dsr" issue: - cd .. is not yet finished - sometimes keyboard totally disabled after enter --- src/interrupt.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index 490d589..973cd04 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -452,6 +452,40 @@ void command_call_cat(char *rmCommandName){ } +/** + * Command cd dilakukan untuk pindah ke direktori path + * @param path direktori tujuan yang hanya satu kata + * @return 0 jika berhasil, 1 jika gagal +*/ +uint8_t command_call_cd(char *path){ + // for one time only + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + + char path_name[8]; + char path_ext[3]; + memcpy(path_name, path, 8); + memcpy(path_ext, "\0\0\0", 3); + + if (memcmp(path, "..", 2) == 0){ + // Pindah ke parent directory + current_directory_cluster = state_driver.dir_table_buf.table[0].cluster_high << 16 | state_driver.dir_table_buf.table[0].cluster_low; + return 0; + } + + for (int i = 0; i < 64; i++){ + if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[i].name, path_name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[i].ext, path_ext, 3) == 0){ + // Folder ditemukan + current_directory_cluster = state_driver.dir_table_buf.table[i].cluster_high << 16 | state_driver.dir_table_buf.table[i].cluster_low; + return 0; + } + } + } + return 1; +} void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { @@ -477,6 +511,8 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 0: // cd framebuffer_write(0, 70, '0', 0x0f, 0); + uint8_t cd_res = command_call_cd(((char *) cpu.ebx) + 3); + cd_res = cd_res; break; case 1: // ls From 478209b946a26c2e74afc1e05a4aa9dbd5334495 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 08:17:49 +0700 Subject: [PATCH 146/176] test: add more test case file changed: - kernel.c info: - add new file and folder in folder to test debug - to run program you can do "make dsr" issue: - sometimes keyboard totally disabled after enter --- src/kernel.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index c6cbda5..7d7dd30 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -33,14 +33,37 @@ void kernel_setup(void) { .name = "ikanaide", .ext = "uwu", .parent_cluster_number = ROOT_CLUSTER_NUMBER, - .buffer_size = 20, + .buffer_size = 0, }; + + requester.name[0] = 'a'; + write(requester); + + requester.name[0] = 'b'; + write(requester); + + requester.name[0] = 'c'; + requester.parent_cluster_number = 5; + write(requester); + + requester.buffer_size = 0x14; + requester.parent_cluster_number = ROOT_CLUSTER_NUMBER; + requester.name[0] = 'j'; for (uint32_t i = 0; i < 15; i++){ + if (i == 4){ + requester.parent_cluster_number = 5; + } else if (i == 8){ + requester.parent_cluster_number = 6; + } else if (i == 12){ + requester.parent_cluster_number = 7; + } requester.name[0]++; write(requester); } delete(requester); + + struct ClusterBuffer ebuf = { "Nandemonai to kuchi o tsugunda\n" "Honto wa chotto ashi o tometakute\n" From 5f966f63b109c5b1bd3b046e84aba2d9099890fa Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 08:32:43 +0700 Subject: [PATCH 147/176] feat: add stack for current directory files changed: - currentdirectorystack.h info: - add new file that is currentdirectorystack.h - currentdirectorystack.h is a header to get current directory stack - the very bottom of the stack should be ROOT_CLUSTER_NUMBER issue: - hard to test --- src/lib-header/currentdirectorystack.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/lib-header/currentdirectorystack.h diff --git a/src/lib-header/currentdirectorystack.h b/src/lib-header/currentdirectorystack.h new file mode 100644 index 0000000..07d2663 --- /dev/null +++ b/src/lib-header/currentdirectorystack.h @@ -0,0 +1,21 @@ +#ifndef _CURRENT_DIRECTORY_STACK_H_ +#define _CURRENT_DIRECTORY_STACK_H_ + + +struct CURRENT_DIR_STACK { + int cd_stack[256]; + int top; +}; + +void init_current_dir_stack(struct CURRENT_DIR_STACK *cds); + +void push_current_dir(struct CURRENT_DIR_STACK * cds, int dir); + +char* pop_current_dir(struct CURRENT_DIR_STACK * cds); + +char* get_top_current_dir(struct CURRENT_DIR_STACK * cds); + +void reverse_current_dir(struct CURRENT_DIR_STACK * cds); + + +#endif \ No newline at end of file From 37fe192dc894f4653c87cedc051d4dcb626de6ff Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 08:41:22 +0700 Subject: [PATCH 148/176] feat: add currentdirectorystack implement files changed: - currentdirectorystack.h - currentdirectorystack.c info: - changed some of the return value - init_current_dir_stack is to initialize new stack, start with root cn - push_current_dir is to push cluster number to stack - pop_current_dir is to pop the stack and return the popped value - get_top_current_dir is to get the top value of the stack - reverse_current_dir is to reverse the stack, --- src/currentdirectorystack.c | 33 ++++++++++++++++++++++++++ src/lib-header/currentdirectorystack.h | 4 ++-- 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/currentdirectorystack.c diff --git a/src/currentdirectorystack.c b/src/currentdirectorystack.c new file mode 100644 index 0000000..f4d6beb --- /dev/null +++ b/src/currentdirectorystack.c @@ -0,0 +1,33 @@ +#include "lib-header/currentdirectorystack.h" + +void init_current_dir_stack(struct CURRENT_DIR_STACK *cds){ + cds->top = 0; + cds->cd_stack[0] = 2; +} + +void push_current_dir(struct CURRENT_DIR_STACK * cds, int dir){ + cds->top++; + cds->cd_stack[cds->top] = dir; +} + +int pop_current_dir(struct CURRENT_DIR_STACK * cds){ + int dir = cds->cd_stack[cds->top]; + cds->top--; + return dir; +} + +int get_top_current_dir(struct CURRENT_DIR_STACK * cds){ + return cds->cd_stack[cds->top]; +} + +void reverse_current_dir(struct CURRENT_DIR_STACK * cds){ + int i = 0; + int j = cds->top; + while (i < j){ + int temp = cds->cd_stack[i]; + cds->cd_stack[i] = cds->cd_stack[j]; + cds->cd_stack[j] = temp; + i++; + j--; + } +} \ No newline at end of file diff --git a/src/lib-header/currentdirectorystack.h b/src/lib-header/currentdirectorystack.h index 07d2663..0b31423 100644 --- a/src/lib-header/currentdirectorystack.h +++ b/src/lib-header/currentdirectorystack.h @@ -11,9 +11,9 @@ void init_current_dir_stack(struct CURRENT_DIR_STACK *cds); void push_current_dir(struct CURRENT_DIR_STACK * cds, int dir); -char* pop_current_dir(struct CURRENT_DIR_STACK * cds); +int pop_current_dir(struct CURRENT_DIR_STACK * cds); -char* get_top_current_dir(struct CURRENT_DIR_STACK * cds); +int get_top_current_dir(struct CURRENT_DIR_STACK * cds); void reverse_current_dir(struct CURRENT_DIR_STACK * cds); From dd0cf5f0b470bf8405f71ea14de890e931fcc0ca Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 08:55:22 +0700 Subject: [PATCH 149/176] feat: update cd implement file changed: - interrupt.c info: - cd can now step up to parrent directory - to test you can do: -- ls -- cd akanaide -- ls -- cd .. -- ls issue: - for now, cd can only jump for ONE directory - sometimes keyboard totaly disabled after enter --- src/interrupt.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/interrupt.c b/src/interrupt.c index 973cd04..435ee8f 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -3,9 +3,13 @@ #include "lib-header/gdt.h" #include "lib-header/stdmem.h" #include "lib-header/idt.h" +#include "lib-header/currentdirectorystack.h" +#include "lib-header/directorystack.h" uint8_t row_shell = 0; int current_directory_cluster = ROOT_CLUSTER_NUMBER; +struct CURRENT_DIR_STACK current_dir_stack; +bool initialized_cd_stack = FALSE; struct TSSEntry _interrupt_tss_entry = { .prev_tss = 0, @@ -458,6 +462,11 @@ void command_call_cat(char *rmCommandName){ * @return 0 jika berhasil, 1 jika gagal */ uint8_t command_call_cd(char *path){ + if (!initialized_cd_stack){ + initialized_cd_stack = TRUE; + init_current_dir_stack(¤t_dir_stack); + } + // for one time only struct FAT32DriverState state_driver; read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); @@ -470,7 +479,11 @@ uint8_t command_call_cd(char *path){ if (memcmp(path, "..", 2) == 0){ // Pindah ke parent directory - current_directory_cluster = state_driver.dir_table_buf.table[0].cluster_high << 16 | state_driver.dir_table_buf.table[0].cluster_low; + if (current_directory_cluster == 2){ + return 1; + } + pop_current_dir(¤t_dir_stack); + current_directory_cluster = get_top_current_dir(¤t_dir_stack); return 0; } @@ -480,6 +493,7 @@ uint8_t command_call_cd(char *path){ memcmp(state_driver.dir_table_buf.table[i].ext, path_ext, 3) == 0){ // Folder ditemukan current_directory_cluster = state_driver.dir_table_buf.table[i].cluster_high << 16 | state_driver.dir_table_buf.table[i].cluster_low; + push_current_dir(¤t_dir_stack, current_directory_cluster); return 0; } } From 73b3e94742c3224025c97f32d39e551a6ccf7e0d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 11:36:24 +0700 Subject: [PATCH 150/176] feat: add mv implement files changed: - interrupt.c info: - add implementation for renaming file/folder - to call this you can do "mv file/folder newName" - example: mv akanaide fish - for now mv can only do folder issue: - cd with short name failled - sometimes keyboard totally disabled after enter - mv is not yet finished --- src/interrupt.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/src/interrupt.c b/src/interrupt.c index 435ee8f..c359a15 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -501,6 +501,150 @@ uint8_t command_call_cd(char *path){ return 1; } + +// char* get_file_name(char *path){ +// char file_name[8]; +// uint8_t i = 0; +// while ((path[i] != '.') && (path[i+3] != ' ') && (i < 8)){ +// file_name[i] = path[i+3]; +// i++; +// } +// return file_name; +// } + + +/** + * Command mv file/folder dilakukan untuk merename file/folder dan memindahkannya ke path + * @param path nama file/folder dan direktori tujuan yang MASIH satu kata +*/ +void command_call_mv(char *path){ + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + bool isFolder = FALSE; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + char new_name[8]; + char new_ext[3]; + bool fileFound = FALSE; + + uint8_t i = 0; + uint8_t j = 0; + while ((path[i] != '.') && (path[i] != ' ') && (i < 8)){ + request.name[i] = path[i]; + i++; + } + + if (i == 8 && path[i] != '.' && path[i] != ' '){ + // berarti kepanjangan + return; + } + + if (path[i] == ' '){ + // berarti folder + isFolder = TRUE; + for (int z = 0; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + + if (!isFolder){ + + while ((path[j] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = path[j+3]; + j++; + } + + if (j-i-1 == 3 && path[j+3] != '\0' && path[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + } + + // saat ini dah didapat mv file/folder + int m; + for (m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + fileFound = TRUE; + break; + } + } + } + + if (j + 1 == '/'){ + // TODO pindah direktori + } else { + uint8_t k = j; + while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0')){ + new_name[k-j] = path[k]; + k++; + } + + if (k-j == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + for (int z = k-j; z < 8; z++){ + new_name[z] = '\0'; + } + + if (isFolder){ + for (int z = 0; z < 3; z++){ + new_ext[z] = '\0'; + } + } else { + j = k+1; + while ((path[j] != ' ') && (j-k-1 < 3)){ + new_ext[j-k-1] = path[j]; + j++; + } + + if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-k-1 < 3){ + for (int z = j-k-1; z < 3; z++){ + new_ext[z] = '\0'; + } + } + } + + if (fileFound){ + memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); + memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); + write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + + } + + } + + +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -556,6 +700,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 6: // mv framebuffer_write(0, 70, '6', 0x0f, 0); + command_call_mv(((char *) cpu.ebx) + 3); break; case 7: // whereis From 932c1ffb8abeced7320bfb1d2f3a6cbd56c2d536 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 18:52:30 +0700 Subject: [PATCH 151/176] feat: add mv file implement files changed: - interrupt.c info: - add implementation for renaming file/folder - to call this you can do "mv file/folder newName" - example: mv akanaide fish - for now chaging dir not possible issue: - cd with short name failled - sometimes keyboard totally disabled after enter - mv is not yet finished --- src/interrupt.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index c359a15..a756786 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -530,6 +530,7 @@ void command_call_mv(char *path){ char new_name[8]; char new_ext[3]; bool fileFound = FALSE; + // bool validName = FALSE; uint8_t i = 0; uint8_t j = 0; @@ -562,11 +563,11 @@ void command_call_mv(char *path){ if (!isFolder){ while ((path[j] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = path[j+3]; + request.ext[j-i-1] = path[j]; j++; } - if (j-i-1 == 3 && path[j+3] != '\0' && path[j+3] != ' '){ + if (j-i-1 == 3 && path[j] != '\0' && path[j] != ' '){ // Error karena extensi terlalu panjang return; } @@ -595,18 +596,27 @@ void command_call_mv(char *path){ if (j + 1 == '/'){ // TODO pindah direktori } else { - uint8_t k = j; - while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0')){ - new_name[k-j] = path[k]; + + uint8_t k = isFolder ? j : j+1; + uint8_t l = 0; + + if (path[k] == '\0' || path[k] == ' '){ + // Error karena nama file tidak boleh kosong + return; + } + + while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0') && (path[k] != '.')){ + new_name[l] = path[k]; k++; + l++; } - if (k-j == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ + if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ // Error karena nama file terlalu panjang return; } - for (int z = k-j; z < 8; z++){ + for (uint8_t z = l; z < 8; z++){ new_name[z] = '\0'; } @@ -668,47 +678,47 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta switch (command){ case 0: // cd - framebuffer_write(0, 70, '0', 0x0f, 0); + framebuffer_write(0, 79, '0', 0x0f, 0); uint8_t cd_res = command_call_cd(((char *) cpu.ebx) + 3); cd_res = cd_res; break; case 1: // ls - framebuffer_write(0, 70, '1', 0x0f, 0); + framebuffer_write(0, 79, '1', 0x0f, 0); command_call_ls(); break; case 2: // mkdir - framebuffer_write(0, 70, '2', 0x0f, 0); + framebuffer_write(0, 79, '2', 0x0f, 0); command_call_mkdir((char *) cpu.ebx); break; case 3: // cat - framebuffer_write(0, 70, '3', 0x0f, 0); + framebuffer_write(0, 79, '3', 0x0f, 0); command_call_cat((char *) cpu.ebx); break; case 4: // cp - framebuffer_write(0, 70, '4', 0x0f, 0); + framebuffer_write(0, 79, '4', 0x0f, 0); command_call_cp((char *) cpu.ebx); break; case 5: // rm - framebuffer_write(0, 70, '5', 0x0f, 0); + framebuffer_write(0, 79, '5', 0x0f, 0); command_call_rm((char *) cpu.ebx); break; case 6: // mv - framebuffer_write(0, 70, '6', 0x0f, 0); + framebuffer_write(0, 79, '6', 0x0f, 0); command_call_mv(((char *) cpu.ebx) + 3); break; case 7: // whereis - framebuffer_write(0, 70, '7', 0x0f, 0); + framebuffer_write(0, 79, '7', 0x0f, 0); break; default: // command not found - framebuffer_write(0, 70, 'x', 0x0f, 0); + framebuffer_write(0, 79, 'x', 0x0f, 0); break; } From a529957314df02a19fce377adbe07d08ca980f84 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 21:15:54 +0700 Subject: [PATCH 152/176] fix: keyboard error files changed: - keyboard.h - keyboard.c info: - add clear_keyboard_buffer to clear keyboard state - fix backspace error (template can be deleted before) issue: - typing too fast might kill the keyboard --- src/keyboard.c | 11 ++++++++++- src/lib-header/keyboard.h | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/keyboard.c b/src/keyboard.c index c38d3f2..5aacd12 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -51,6 +51,13 @@ void keyboard_state_deactivate(void){ keyboard_state.keyboard_input_on=FALSE; } +// Clear keyboard buffer +void clear_keyboard_buffer(void){ + for (int i = 0; i < KEYBOARD_BUFFER_SIZE; i++) { + keyboard_state.keyboard_buffer[i] = 0; + } +} + // Get keyboard buffer values - @param buf Pointer to char buffer, recommended size at least KEYBOARD_BUFFER_SIZE void get_keyboard_buffer(char *buf){ for (int i = 0; i < KEYBOARD_BUFFER_SIZE; i++) { @@ -111,7 +118,9 @@ void keyboard_isr(void) { /* Backspace */ if (mapped_char == '\b') { - if (col) { + if (!keyboard_state.buffer_index) { + // nothing to delete + } else if (col) { keyboard_state.buffer_index--; col--; backspaceLine[row]--; diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index 5daffef..f1a3dee 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -59,6 +59,9 @@ void get_keyboard_buffer(char *buf); // Check whether keyboard ISR is active or not - @return Equal with keyboard_input_on value bool is_keyboard_blocking(void); +// Clear keyboard buffer +void clear_keyboard_buffer(void); + /* -- Keyboard Interrupt Service Routine -- */ From acfb4bf8931d4f01ef7a9f87abbea5492e5fda85 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 21:18:18 +0700 Subject: [PATCH 153/176] test: add test case file changed: - kernel.c info: - test file and folder have variance of name - to run the program do "make dsr" - to debug the program do "make ds" and f5 issue: - pagefault (0xe) for some cases --- src/kernel.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/kernel.c b/src/kernel.c index 7d7dd30..1b8f7ea 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -39,9 +39,10 @@ void kernel_setup(void) { requester.name[0] = 'a'; write(requester); - requester.name[0] = 'b'; + memcpy(requester.name + 4, "\0\0\0\0", 4); write(requester); + memcpy(requester.name + 4, "FFAA", 4); requester.name[0] = 'c'; requester.parent_cluster_number = 5; write(requester); @@ -49,12 +50,16 @@ void kernel_setup(void) { requester.buffer_size = 0x14; requester.parent_cluster_number = ROOT_CLUSTER_NUMBER; requester.name[0] = 'j'; + memcpy(requester.name + 4, "aide", 4); for (uint32_t i = 0; i < 15; i++){ if (i == 4){ + memcpy(requester.name + 4, "L\0\0\0", 4); requester.parent_cluster_number = 5; } else if (i == 8){ + memcpy(requester.name + 4, "Du\0\0", 4); requester.parent_cluster_number = 6; } else if (i == 12){ + memcpy(requester.name + 4, "HALO", 4); requester.parent_cluster_number = 7; } requester.name[0]++; From bb88226a9042f45861849cf40b34a79908edbdc8 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Mon, 10 Apr 2023 21:20:23 +0700 Subject: [PATCH 154/176] feat: add relative path mechanism for cd file changed: - interrupt.c info: - to test the program you can do cd path - you can find the example test run on issue section issue: - error handling is still weak --- src/interrupt.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index a756786..5f613cc 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -655,6 +655,33 @@ void command_call_mv(char *path){ } + +void command_call_multi_cd(char *path){ + struct FAT32DriverState state_driver; + read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + read_clusters(&state_driver.fat_table, 1, 1); + + uint8_t i = 0; + uint8_t j = 0; + while (path[i] != '\0'){ + if (path[i] == '/'){ + j = i; + } + i++; + } + + if (j == 0){ + // berarti hanya satu direktori + command_call_cd(path); + } else { + char new_path[64]; + memcpy(new_path+3, path, j); + new_path[j+3] = '\0'; + command_call_cd(new_path); + command_call_multi_cd(path+j+1); + } +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -664,6 +691,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta // } } else if (cpu.eax == 4) { template(); + clear_keyboard_buffer(); keyboard_state_activate(); __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called while (is_keyboard_blocking()); @@ -679,8 +707,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta case 0: // cd framebuffer_write(0, 79, '0', 0x0f, 0); - uint8_t cd_res = command_call_cd(((char *) cpu.ebx) + 3); - cd_res = cd_res; + command_call_multi_cd(((char *) cpu.ebx) + 3); break; case 1: // ls From f53c87606531f95f81e1da5dce985909d37e0aee Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <110533432+WildanGhaly@users.noreply.github.com> Date: Fri, 28 Apr 2023 14:31:08 +0700 Subject: [PATCH 155/176] feat: add new keyboard isr (#27) file changed: - keyboard.c info: - I am back after 3 weeks but nothing changed on repo -_- - Keyboard disable after some case is fixed - cat is not yet fixed --- src/keyboard.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) diff --git a/src/keyboard.c b/src/keyboard.c index 5aacd12..fbfceba 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -97,7 +97,7 @@ bool restoreSplashScreen(){ * This can be made into blocking input with `while (is_keyboard_blocking());` * after calling `keyboard_state_activate();` */ -void keyboard_isr(void) { +void keyboard_isrs(void) { bool capslock = FALSE; bool shifted = FALSE; int16_t holdWait = 0; @@ -512,5 +512,164 @@ void keyboard_isr(void) { } } } - pic_ack(IRQ_KEYBOARD); + } + + +/* -- Keyboard Interrupt Service Routine -- */ + +/** + * Handling keyboard interrupt & process scancodes into ASCII character. + * Will start listen and process keyboard scancode if keyboard_input_on. + * + * Will only print printable character into framebuffer. + * Stop processing when enter key (line feed) is pressed. + * + * Note that, with keyboard interrupt & ISR, keyboard reading is non-blocking. + * This can be made into blocking input with `while (is_keyboard_blocking());` + * after calling `keyboard_state_activate();` + */ +void keyboard_isr(void) { + bool alt = FALSE; + bool ctrl = FALSE; + bool shift = FALSE; + bool capslock = FALSE; + uint8_t scanTemp = 0; + + if (!keyboard_state.keyboard_input_on){ + keyboard_state.buffer_index = 0; + framebuffer_write(21,11,'L',0xa,0); + } else { + keyboard_state.buffer_index = 0; + col = 14; + while (is_keyboard_blocking()){ + uint8_t scancode = in(KEYBOARD_DATA_PORT); + char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; + + if (scancode == 0x3A){ + capslock = !capslock; + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x3A); + } + + if (scancode == 0x2A || scancode == 0x36){ + shift = TRUE; + } + + if (scancode == 0x1D){ + ctrl = TRUE; + } + + if (scancode == 0x38){ + alt = TRUE; + } + + if (scancode == 0x9D){ + ctrl = FALSE; + } + + if (scancode == 0xAA || scancode == 0xB6){ + shift = FALSE; + } + + if (scancode == 0xB8){ + alt = FALSE; + } + + if (scancode == 0x0E && shift && keyboard_state.buffer_index > 0 && keyboard_state.keyboard_buffer[keyboard_state.buffer_index - 1] != ' ') { + keyboard_state.buffer_index--; + col--; + backspaceLine[row]--; + framebuffer_write(row, col, 0, 0x0c, 0); + framebuffer_set_cursor(row, col); + mapped_char = 0; + } + + if (mapped_char == '\b') { + if (!keyboard_state.buffer_index) { + // nothing to delete + } else if (col) { + keyboard_state.buffer_index--; + col--; + backspaceLine[row]--; + } else if (col == 0){ + if (row <= 0) { + row = 0; + } else { + row--; + col = backspaceLine[row]; + } + } + framebuffer_write(row, col, 0, 0x0c, 0); + framebuffer_set_cursor(row, col); + mapped_char = 0; + do { + scancode = in(KEYBOARD_DATA_PORT); + } while (scancode == 0x0E); + } + + if (mapped_char=='\n') { + keyboard_state.buffer_index=0; + framebuffer_set_cursor(row + 1, col); + mapped_char = 0; + if (row >= 24) { + row = 24; + } else { + row++; + } + keyboard_state_deactivate(); + } + + if (mapped_char != 0) { + if (capslock && !shift){ // hanya capslock + if (mapped_char >= 'a' && mapped_char <= 'z'){ + mapped_char -= 32; + } + } else if (!capslock && shift){ // hanya shift + if (mapped_char >= 'a' && mapped_char <= 'z'){ + mapped_char -= 32; + } + } else if (capslock && shift){ // capslock dan shift + if (mapped_char >= 'A' && mapped_char <= 'Z'){ + mapped_char += 32; + } + } + + keyboard_state.keyboard_buffer[keyboard_state.buffer_index] = mapped_char; + keyboard_state.buffer_index++; + framebuffer_write(row, col, mapped_char, 0x0c, 0); + + + if (col >= 79){ + if (row >= 24) { + row = 24; + } else { + row++; + } + col = 0; + } else { + col++; + backspaceLine[row]++; + } + + if (col >= 79 && row < 24){ + framebuffer_set_cursor(row + 1, 0); + } else if (row >= 24){ + framebuffer_set_cursor(24, 0); + } else { + framebuffer_set_cursor(row, col); + } + + ctrl = alt; + alt = ctrl; + + do { + scanTemp = in(KEYBOARD_DATA_PORT); + } while (scanTemp == scancode); + } + } + } + + pic_ack(IRQ_KEYBOARD); +} \ No newline at end of file From 77cc77a627f37c7664b0a90fadb85fa20f2e5217 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <110533432+WildanGhaly@users.noreply.github.com> Date: Fri, 28 Apr 2023 21:03:57 +0700 Subject: [PATCH 156/176] Willy/shell implement (#28) * feat: add new keyboard isr file changed: - keyboard.c info: - I am back after 3 weeks but nothing changed on repo -_- - Keyboard disable after some case is fixed - cat is not yet fixed * style: add some comment line - nothing much change --- src/external/user-shell.c | 5 +++++ src/interrupt.c | 23 +++++++++++++++++++++++ src/kernel.c | 1 + 3 files changed, 29 insertions(+) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index f243619..12b564a 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -11,6 +11,8 @@ void syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { __asm__ volatile("int $0x30"); } +// TODO: pindahin semua fungsi dari interupt.c + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -28,6 +30,9 @@ int main(void) { char buf[16]; while (TRUE) { syscall(4, (uint32_t) buf, 0x20, 0); + // TODO: prosess + + syscall(5, (uint32_t) buf, 0x20, 0xF); } diff --git a/src/interrupt.c b/src/interrupt.c index 5f613cc..acb5ad3 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -101,6 +101,11 @@ void puts(char *str, uint32_t len, uint32_t color) { } } +/** + * @param str string to be printed + * @param len length of string + * @param color color of string +*/ void puts2(char *str, uint32_t len, uint32_t color) { for (uint32_t i = 0; i < len; i++) { framebuffer_write(24, i, str[i], color, 0); @@ -220,8 +225,11 @@ void command_call_cp(char *cpCommandName){ read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); read_clusters(&state_driver.fat_table, 1, 1); + struct ClusterBuffer cbuf[4]; + struct FAT32DriverRequest request = { .parent_cluster_number = current_directory_cluster, + .buf = cbuf, }; uint8_t i = 0; @@ -399,8 +407,11 @@ void command_call_cat(char *rmCommandName){ read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); read_clusters(&state_driver.fat_table, 1, 1); + struct ClusterBuffer cbuf[4]; + struct FAT32DriverRequest request = { .parent_cluster_number = current_directory_cluster, + .buf = cbuf, }; uint8_t i = 0; @@ -689,6 +700,18 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta // if (*((int8_t*) cpu.ecx) == 0){ // puts(request.buf, request.buffer_size, 0x0e); // } + } else if (cpu.eax == 1){ + // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + + + } else if (cpu.eax == 2) { + // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + + + } else if (cpu.eax == 3) { + // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + + } else if (cpu.eax == 4) { template(); clear_keyboard_buffer(); diff --git a/src/kernel.c b/src/kernel.c index 1b8f7ea..4768a90 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -81,6 +81,7 @@ void kernel_setup(void) { "Naicha dame naicha dame\n" "Demo honto wa iitai yo\n" "Ikanaide\n" + "Chizuru\n" }; requester.name[0] = 'i'; From 36a6e35d7ae2135b09c32d3f33f8b7228281537a Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 28 Apr 2023 23:20:22 +0700 Subject: [PATCH 157/176] feat: moving shell imlement to user-shell - add lots of new system calls - ls is done - cd is done --- src/external/user-shell.c | 206 +++++++++++++++++++++++++++++++++++++- src/interrupt.c | 99 ++++++++---------- 2 files changed, 243 insertions(+), 62 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 12b564a..65b0d61 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -1,5 +1,32 @@ #include "../lib-header/stdtype.h" #include "../lib-header/fat32.h" +#include "../lib-header/currentdirectorystack.h" + +uint8_t row_shell = 0; +int current_directory_cluster = ROOT_CLUSTER_NUMBER; +struct CURRENT_DIR_STACK current_dir_stack; +bool initialized_cd_stack = FALSE; + +void* memcpy(void* restrict dest, const void* restrict src, size_t n) { + uint8_t *dstbuf = (uint8_t*) dest; + const uint8_t *srcbuf = (const uint8_t*) src; + for (size_t i = 0; i < n; i++) + dstbuf[i] = srcbuf[i]; + return dstbuf; +} + +int memcmp(const void *s1, const void *s2, size_t n) { + const uint8_t *buf1 = (const uint8_t*) s1; + const uint8_t *buf2 = (const uint8_t*) s2; + for (size_t i = 0; i < n; i++) { + if (buf1[i] < buf2[i]) + return -1; + else if (buf1[i] > buf2[i]) + return 1; + } + + return 0; +} void syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { __asm__ volatile("mov %0, %%ebx" : /* */ : "r"(ebx)); @@ -13,6 +40,133 @@ void syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { // TODO: pindahin semua fungsi dari interupt.c +/** + * cd - Mengganti current working directory (termasuk .. untuk naik) + * ls - Menuliskan isi current working directory + * mkdir - Membuat sebuah folder kosong baru + * cat - Menuliskan sebuah file sebagai text file ke layar (Gunakan format LF newline) + * cp - Mengcopy suatu file + * rm - Menghapus suatu file atau folder kosong + * mv - Memindah dan merename lokasi file/folder + * whereis - Mencari file/folder dengan nama yang sama diseluruh file system + + * @return 0 cd (spasi) + * @return 1 ls + * @return 2 mkdir (spasi) + * @return 3 cat (spasi) + * @return 4 cp (spasi) + * @return 5 rm (spasi) + * @return 6 mv (spasi) + * @return 7 whereis (spasi) +*/ +uint8_t getCommandInput(char *input, uint8_t len){ + char *command[] = {"cd ", "ls", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis "}; + uint8_t command_len[] = {3, 2, 6, 4, 3, 3, 3, 8}; + for (uint8_t i = 0; i < 8; i++){ + if (len >= command_len[i] && memcmp(input, command[i], command_len[i]) == 0){ + return i; + } + } + return 255; +} + +void command_call_ls(void){ + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + int col = 0; + int row_add_needed = 1; + + for (int i = 1; i < 64; i++){ + + if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ + if (col == 5){ + col = 0; + row_shell++; + row_add_needed++; + } + syscall(6, (uint32_t) state_driver.dir_table_buf.table[i].name, row_shell, col*16); + col++; + } + } + row_shell++; + + syscall(7, row_add_needed, 0, 0); + +} + +/** + * Command cd dilakukan untuk pindah ke direktori path + * @param path direktori tujuan yang hanya satu kata + * @return 0 jika berhasil, 1 jika gagal +*/ +uint8_t command_call_cd(char *path){ + if (!initialized_cd_stack){ + initialized_cd_stack = TRUE; + // init_current_dir_stack(¤t_dir_stack); + syscall(9, (uint32_t) ¤t_dir_stack, 0, 0); + } + + // for one time only + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + char path_name[8]; + char path_ext[3]; + memcpy(path_name, path, 8); + memcpy(path_ext, "\0\0\0", 3); + + if (memcmp(path, "..", 2) == 0){ + // Pindah ke parent directory + if (current_directory_cluster == 2){ + return 1; + } + // pop_current_dir(¤t_dir_stack); + // current_directory_cluster = get_top_current_dir(¤t_dir_stack); + syscall(10, (uint32_t) ¤t_dir_stack, (uint32_t) ¤t_directory_cluster, 0); + return 0; + } + + for (int i = 0; i < 64; i++){ + if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[i].name, path_name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[i].ext, path_ext, 3) == 0){ + // Folder ditemukan + current_directory_cluster = state_driver.dir_table_buf.table[i].cluster_high << 16 | state_driver.dir_table_buf.table[i].cluster_low; + // push_current_dir(¤t_dir_stack, current_directory_cluster); + syscall(11, (uint32_t) ¤t_dir_stack, (uint32_t) current_directory_cluster, 0); + return 0; + } + } + } + return 1; +} + +void command_call_multi_cd(char *path){ + + uint8_t i = 0; + uint8_t j = 0; + while (path[i] != '\0'){ + if (path[i] == '/'){ + j = i; + } + i++; + } + + if (j == 0){ + // berarti hanya satu direktori + command_call_cd(path); + } else { + char new_path[64]; + memcpy(new_path, path, j); + new_path[j] = '\0'; + command_call_cd(new_path); + command_call_multi_cd(path+j+1); + } +} + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -28,10 +182,58 @@ int main(void) { syscall(5, (uint32_t) "eswoss\n", 4, 0xF); char buf[16]; + + uint8_t command; while (TRUE) { - syscall(4, (uint32_t) buf, 0x20, 0); - // TODO: prosess + syscall(4, (uint32_t) buf, 0x20, (uint32_t) row_shell); + row_shell++; + command = getCommandInput((char*) buf, 16); + // TODO: prosess + switch (command){ + case 0: + // cd + // framebuffer_write(0, 79, '0', 0x0f, 0); + command_call_multi_cd(((char *) buf) + 3); + break; + case 1: + // ls + command_call_ls(); + break; + case 2: + // mkdir + // framebuffer_write(0, 79, '2', 0x0f, 0); + // command_call_mkdir((char *) buf); + break; + case 3: + // cat + // framebuffer_write(0, 79, '3', 0x0f, 0); + // command_call_cat((char *) buf); + break; + case 4: + // cp + // framebuffer_write(0, 79, '4', 0x0f, 0); + // command_call_cp((char *) buf); + break; + case 5: + // rm + // framebuffer_write(0, 79, '5', 0x0f, 0); + // command_call_rm((char *) buf); + break; + case 6: + // mv + // framebuffer_write(0, 79, '6', 0x0f, 0); + // command_call_mv(((char *) buf) + 3); + break; + case 7: + // whereis + // framebuffer_write(0, 79, '7', 0x0f, 0); + break; + default: + // command not found + // framebuffer_write(0, 79, 'x', 0x0f, 0); + break; + } syscall(5, (uint32_t) buf, 0x20, 0xF); } diff --git a/src/interrupt.c b/src/interrupt.c index acb5ad3..1969386 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -95,9 +95,9 @@ void set_tss_kernel_current_stack(void) { // TODO: implement puts using framebuffer -void puts(char *str, uint32_t len, uint32_t color) { +void puts(char *str, uint32_t len, uint32_t color, uint32_t row_shells) { for (uint32_t i = 0; i < len; i++) { - framebuffer_write(row_shell, i, str[i], color, 0); + framebuffer_write(row_shells, i, str[i], color, 0); } } @@ -134,12 +134,11 @@ void puts_long_text(char *str, uint32_t len, uint32_t color) { } -void template(void){ - puts("Brother420/", 11, 0x0a); - framebuffer_write(row_shell, 11, ':', 0x01, 0); - framebuffer_write(row_shell, 12, '$', 0x0F, 0); - framebuffer_set_cursor(row_shell, 14); - row_shell++; +void template(uint32_t row_shells){ + puts("Brother420/", 11, 0x0a, row_shells); + framebuffer_write(row_shells, 11, ':', 0x01, 0); + framebuffer_write(row_shells, 12, '$', 0x0F, 0); + framebuffer_set_cursor(row_shells, 14); } /** @@ -713,7 +712,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta } else if (cpu.eax == 4) { - template(); + template((uint32_t) cpu.edx); clear_keyboard_buffer(); keyboard_state_activate(); __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called @@ -722,59 +721,39 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta get_keyboard_buffer(buf); memcpy((char *) cpu.ebx, buf, cpu.ecx); } else if (cpu.eax == 5) { - // ini berarti di-enter dari syscall 4 - - uint8_t command = getCommandInput((char *) cpu.ebx, cpu.ecx); - - switch (command){ - case 0: - // cd - framebuffer_write(0, 79, '0', 0x0f, 0); - command_call_multi_cd(((char *) cpu.ebx) + 3); - break; - case 1: - // ls - framebuffer_write(0, 79, '1', 0x0f, 0); - command_call_ls(); - break; - case 2: - // mkdir - framebuffer_write(0, 79, '2', 0x0f, 0); - command_call_mkdir((char *) cpu.ebx); - break; - case 3: - // cat - framebuffer_write(0, 79, '3', 0x0f, 0); - command_call_cat((char *) cpu.ebx); - break; - case 4: - // cp - framebuffer_write(0, 79, '4', 0x0f, 0); - command_call_cp((char *) cpu.ebx); - break; - case 5: - // rm - framebuffer_write(0, 79, '5', 0x0f, 0); - command_call_rm((char *) cpu.ebx); - break; - case 6: - // mv - framebuffer_write(0, 79, '6', 0x0f, 0); - command_call_mv(((char *) cpu.ebx) + 3); - break; - case 7: - // whereis - framebuffer_write(0, 79, '7', 0x0f, 0); - break; - default: - // command not found - framebuffer_write(0, 79, 'x', 0x0f, 0); - break; - } - - puts2((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side } + + // Syscall cd + else if (cpu.eax == 6) { + puts_line((char*) cpu.ebx, cpu.ecx, cpu.edx, 8, 0x0F); + } + + // Syscall addrow + else if (cpu.eax == 7) { + addRow(cpu.ebx); + } + + // Syscall read cluster + else if (cpu.eax == 8) { + read_clusters((struct FAT32DirectoryTable *) cpu.ebx, cpu.ecx, cpu.edx); + } + + // Syscall init current directory + else if (cpu.eax == 9) { + init_current_dir_stack((struct CURRENT_DIR_STACK *) cpu.ebx); + } + + // Syscall pop current dir + else if (cpu.eax == 10) { + pop_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx); + *((int*) cpu.ecx) = get_top_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx); + } + + // Syscall push current dir + else if (cpu.eax == 11) { + push_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx, cpu.ecx); + } } From 589bd86c6048ff92fecfafa5608e362a76cd1a2d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 28 Apr 2023 23:24:34 +0700 Subject: [PATCH 158/176] feat: move mkdir - mkdir is now runable from user --- src/external/user-shell.c | 19 ++++++++++++++++--- src/interrupt.c | 4 ++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 65b0d61..c62e640 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -167,6 +167,21 @@ void command_call_multi_cd(char *path){ } } +void command_call_mkdir(char *dirCommandName){ + + struct FAT32DriverRequest request = { + .buf = 0, + .ext = "\0\0\0", + .parent_cluster_number = current_directory_cluster, + .buffer_size = 0, + }; + for (int i = 6; i < 14; i++){ + request.name[i-6] = dirCommandName[i]; + } + // write(request); + syscall(2, (uint32_t) &request, 0, 0); +} + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -193,7 +208,6 @@ int main(void) { switch (command){ case 0: // cd - // framebuffer_write(0, 79, '0', 0x0f, 0); command_call_multi_cd(((char *) buf) + 3); break; case 1: @@ -202,8 +216,7 @@ int main(void) { break; case 2: // mkdir - // framebuffer_write(0, 79, '2', 0x0f, 0); - // command_call_mkdir((char *) buf); + command_call_mkdir((char *) buf); break; case 3: // cat diff --git a/src/interrupt.c b/src/interrupt.c index 1969386..49a80df 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -704,8 +704,8 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta } else if (cpu.eax == 2) { - // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; - + struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + *((int8_t*) cpu.ecx) = write(request); } else if (cpu.eax == 3) { // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; From f788f6b01d0d72a18e4532a4604ceac69ff7ca32 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Fri, 28 Apr 2023 23:57:51 +0700 Subject: [PATCH 159/176] feat: move cat to user - cat is now runnable from user --- src/external/user-shell.c | 72 +++++++++++++++++++++++++++++++++++++-- src/interrupt.c | 15 +++++--- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index c62e640..68c12d2 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -182,6 +182,75 @@ void command_call_mkdir(char *dirCommandName){ syscall(2, (uint32_t) &request, 0, 0); } + +void command_call_cat(char *rmCommandName){ + // asumsi file only + + int32_t retCode; + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + struct ClusterBuffer cbuf[4]; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + .buf = cbuf, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((rmCommandName[i+4] != '.') && (rmCommandName[i+4] != ' ') && (i < 8)){ + request.name[i] = rmCommandName[i+4]; + i++; + } + + if (rmCommandName[i+4] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + while ((rmCommandName[j+4] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = rmCommandName[j+4]; + j++; + } + + if (j-i-1 == 4 && rmCommandName[j+4] != '\0' && rmCommandName[j+4] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + // read(request); + syscall(0, (uint32_t) &request, (uint32_t) &retCode, 0); + break; + } + } + } + + // puts_long_text(request.buf, request.buffer_size, 0x0e); + syscall(12, (uint32_t) request.buf, request.buffer_size, (uint32_t) &row_shell); +} + + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -220,8 +289,7 @@ int main(void) { break; case 3: // cat - // framebuffer_write(0, 79, '3', 0x0f, 0); - // command_call_cat((char *) buf); + command_call_cat((char *) buf); break; case 4: // cp diff --git a/src/interrupt.c b/src/interrupt.c index 49a80df..9bd5ac3 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -112,22 +112,22 @@ void puts2(char *str, uint32_t len, uint32_t color) { } } -void puts_long_text(char *str, uint32_t len, uint32_t color) { +void puts_long_text(char *str, uint32_t len, uint32_t color, uint8_t *row_shells) { uint8_t j = 0; uint8_t k = 0; for (uint32_t i = 0; i < len; i++) { if (j == 80) { - row_shell++; + (*row_shells)++; j = 0; k++; } if (str[i] == '\n') { - row_shell++; + (*row_shells)++; j = 0; k++; continue; } - framebuffer_write(row_shell, j, str[i], color, 0); + framebuffer_write(*row_shells, j, str[i], color, 0); j++; } addRow(k); @@ -460,7 +460,7 @@ void command_call_cat(char *rmCommandName){ } } - puts_long_text(request.buf, request.buffer_size, 0x0e); + puts_long_text(request.buf, request.buffer_size, 0x0e, &row_shell); framebuffer_write(23, 79, 'L', 0x0F, 0x00); @@ -754,6 +754,11 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta else if (cpu.eax == 11) { push_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx, cpu.ecx); } + + // Syscall puts long text + else if (cpu.eax == 12) { + puts_long_text((char *) cpu.ebx, cpu.ecx, 0x0E, (uint8_t*) (cpu.edx)); + } } From 63f52e8ef27dad13aec6a8131038cf4f4ca644b1 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 00:01:41 +0700 Subject: [PATCH 160/176] feat: move cp to user - cp is now runnable in user mode --- src/external/user-shell.c | 115 +++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 68c12d2..6addc19 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -250,6 +250,118 @@ void command_call_cat(char *rmCommandName){ syscall(12, (uint32_t) request.buf, request.buffer_size, (uint32_t) &row_shell); } +void command_call_cp(char *cpCommandName){ + uint32_t retCode; + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + struct ClusterBuffer cbuf[4]; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + .buf = cbuf, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((cpCommandName[i+3] != '.') && (cpCommandName[i+3] != ' ') && (i < 8)){ + request.name[i] = cpCommandName[i+3]; + i++; + } + + if (cpCommandName[i+3] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (i == 8 && cpCommandName[i+3] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + while ((cpCommandName[j+3] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = cpCommandName[j+3]; + j++; + } + + if (j-i-1 == 3 && cpCommandName[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + // read(request); + syscall(0, (uint32_t) &request, (uint32_t) &retCode, 0); + + break; + } + } + } + + uint8_t k = 0; + uint8_t l = 0; + while ((cpCommandName[j+4] != '.') && (cpCommandName[j+4] != ' ') && (k < 8)){ + request.name[k] = cpCommandName[j+4]; + k++; + j++; + } + + if (cpCommandName[j+4] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (k == 8 && cpCommandName[j+4] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + if (k < 8){ + for (int z = k; z < 8; z++){ + request.name[z] = '\0'; + } + } + + while ((cpCommandName[l+j+5] != ' ') && cpCommandName[l+j+5] != '\0' && (l < 3)){ + request.ext[l] = cpCommandName[l+j+5]; + l++; + } + + if (l == 3 && ((cpCommandName[l+j+5] != ' ') && (cpCommandName[l+j+5] != '\0'))){ + // Error karena extensi terlalu panjang + return; + } + + if (l < 3){ + for (int z = l; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + // write(request); + syscall(2, (uint32_t) &request, 0, 0); + +} int main(void) { struct ClusterBuffer cl = {0}; @@ -293,8 +405,7 @@ int main(void) { break; case 4: // cp - // framebuffer_write(0, 79, '4', 0x0f, 0); - // command_call_cp((char *) buf); + command_call_cp((char *) buf); break; case 5: // rm From b0957ff6f845b149de9d9cb0227461efc6938223 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 00:08:07 +0700 Subject: [PATCH 161/176] feat: move rm to user - rm is now runnable in user mode --- src/external/user-shell.c | 73 +++++++++++++++++++++++++++++++++++++-- src/interrupt.c | 4 +-- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 6addc19..dfd42a5 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -363,6 +363,76 @@ void command_call_cp(char *cpCommandName){ } +void command_call_rm(char *rmCommandName){ + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + bool isFolder = FALSE; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + uint8_t i = 0; + uint8_t j = 0; + while ((rmCommandName[i+3] != '.') && (rmCommandName[i+3] != ' ') && (i < 8)){ + request.name[i] = rmCommandName[i+3]; + i++; + } + + if (rmCommandName[i+3] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (rmCommandName[i+3] == '\0'){ + // berarti folder + isFolder = TRUE; + for (int z = 0; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + if (!isFolder){ + j = i+1; + while ((rmCommandName[j+3] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = rmCommandName[j+3]; + j++; + } + + if (j-i-1 == 3 && rmCommandName[j+3] != '\0' && rmCommandName[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + } + + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + // delete(request); + syscall(3, (uint32_t) &request, 0, 0); + break; + } + } + } +} + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -409,8 +479,7 @@ int main(void) { break; case 5: // rm - // framebuffer_write(0, 79, '5', 0x0f, 0); - // command_call_rm((char *) buf); + command_call_rm((char *) buf); break; case 6: // mv diff --git a/src/interrupt.c b/src/interrupt.c index 9bd5ac3..94d253b 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -708,8 +708,8 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta *((int8_t*) cpu.ecx) = write(request); } else if (cpu.eax == 3) { - // struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; - + struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; + *((int8_t*) cpu.ecx) = delete(request); } else if (cpu.eax == 4) { template((uint32_t) cpu.edx); From 681cb6fcff998e1fe7771616820f903f98f35bc5 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 00:44:40 +0700 Subject: [PATCH 162/176] feat: move mv to user - WARNING! Carefull with shell size! - kernel changed due to shell overload - mv is now runnable in user mode --- src/external/user-shell.c | 144 +++++++++++++++++++++++++++++++++++++- src/interrupt.c | 5 ++ src/kernel.c | 8 +-- 3 files changed, 151 insertions(+), 6 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index dfd42a5..1b32c81 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -433,6 +433,147 @@ void command_call_rm(char *rmCommandName){ } } +void command_call_mv(char *path){ + struct FAT32DriverState state_driver; + // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + // read_clusters(&state_driver.fat_table, 1, 1); + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(8, (uint32_t) &state_driver.fat_table, 1, 1); + + bool isFolder = FALSE; + + struct FAT32DriverRequest request = { + .parent_cluster_number = current_directory_cluster, + }; + + char new_name[8]; + char new_ext[3]; + bool fileFound = FALSE; + // bool validName = FALSE; + + uint8_t i = 0; + uint8_t j = 0; + while ((path[i] != '.') && (path[i] != ' ') && (i < 8)){ + request.name[i] = path[i]; + i++; + } + + if (i == 8 && path[i] != '.' && path[i] != ' '){ + // berarti kepanjangan + return; + } + + if (path[i] == ' '){ + // berarti folder + isFolder = TRUE; + for (int z = 0; z < 3; z++){ + request.ext[z] = '\0'; + } + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + request.name[z] = '\0'; + } + } + + j = i+1; + + if (!isFolder){ + + while ((path[j] != ' ') && (j-i-1 < 3)){ + request.ext[j-i-1] = path[j]; + j++; + } + + if (j-i-1 == 3 && path[j] != '\0' && path[j] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + request.ext[z] = '\0'; + } + } + } + + // saat ini dah didapat mv file/folder + int m; + for (m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + fileFound = TRUE; + break; + } + } + } + + if (j + 1 == '/'){ + // TODO pindah direktori + } else { + + uint8_t k = isFolder ? j : j+1; + uint8_t l = 0; + + if (path[k] == '\0' || path[k] == ' '){ + // Error karena nama file tidak boleh kosong + return; + } + + while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0') && (path[k] != '.')){ + new_name[l] = path[k]; + k++; + l++; + } + + if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + for (uint8_t z = l; z < 8; z++){ + new_name[z] = '\0'; + } + + if (isFolder){ + for (int z = 0; z < 3; z++){ + new_ext[z] = '\0'; + } + } else { + j = k+1; + while ((path[j] != ' ') && (j-k-1 < 3)){ + new_ext[j-k-1] = path[j]; + j++; + } + + if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-k-1 < 3){ + for (int z = j-k-1; z < 3; z++){ + new_ext[z] = '\0'; + } + } + } + + if (fileFound){ + memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); + memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); + // write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + } + + } + + +} + int main(void) { struct ClusterBuffer cl = {0}; struct FAT32DriverRequest request = { @@ -483,8 +624,7 @@ int main(void) { break; case 6: // mv - // framebuffer_write(0, 79, '6', 0x0f, 0); - // command_call_mv(((char *) buf) + 3); + command_call_mv(((char *) buf) + 3); break; case 7: // whereis diff --git a/src/interrupt.c b/src/interrupt.c index 94d253b..4d96c3a 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -759,6 +759,11 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta else if (cpu.eax == 12) { puts_long_text((char *) cpu.ebx, cpu.ecx, 0x0E, (uint8_t*) (cpu.edx)); } + + // Syscall write cluster + else if (cpu.eax == 13) { + write_clusters((struct FAT32DirectoryTable *) cpu.ebx, cpu.ecx, cpu.edx); + } } diff --git a/src/kernel.c b/src/kernel.c index 4768a90..8965f50 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -44,7 +44,7 @@ void kernel_setup(void) { memcpy(requester.name + 4, "FFAA", 4); requester.name[0] = 'c'; - requester.parent_cluster_number = 5; + requester.parent_cluster_number = 7; write(requester); requester.buffer_size = 0x14; @@ -54,13 +54,13 @@ void kernel_setup(void) { for (uint32_t i = 0; i < 15; i++){ if (i == 4){ memcpy(requester.name + 4, "L\0\0\0", 4); - requester.parent_cluster_number = 5; + requester.parent_cluster_number = 7; } else if (i == 8){ memcpy(requester.name + 4, "Du\0\0", 4); - requester.parent_cluster_number = 6; + requester.parent_cluster_number = 8; } else if (i == 12){ memcpy(requester.name + 4, "HALO", 4); - requester.parent_cluster_number = 7; + requester.parent_cluster_number = 9; } requester.name[0]++; write(requester); From f271fd9e56614d61cebfbba0803c4300c3dfc848 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 02:45:05 +0700 Subject: [PATCH 163/176] feat: add cwd - lots of files changed :') - now cwd after cd is shown --- src/currentdirectorystack.c | 32 +- src/external/user-shell.c | 16 +- src/interrupt.c | 574 +------------------------ src/keyboard.c | 10 +- src/lib-header/currentdirectorystack.h | 14 +- src/lib-header/keyboard.h | 2 + 6 files changed, 79 insertions(+), 569 deletions(-) diff --git a/src/currentdirectorystack.c b/src/currentdirectorystack.c index f4d6beb..79524ce 100644 --- a/src/currentdirectorystack.c +++ b/src/currentdirectorystack.c @@ -3,20 +3,26 @@ void init_current_dir_stack(struct CURRENT_DIR_STACK *cds){ cds->top = 0; cds->cd_stack[0] = 2; + cds->cd_stack_name[0] = "root"; } -void push_current_dir(struct CURRENT_DIR_STACK * cds, int dir){ +void push_current_dir(struct CURRENT_DIR_STACK * cds, uint8_t dir, char* dir_name){ cds->top++; cds->cd_stack[cds->top] = dir; + cds->cd_stack_name[cds->top] = dir_name; } -int pop_current_dir(struct CURRENT_DIR_STACK * cds){ +uint8_t pop_current_dir(struct CURRENT_DIR_STACK * cds){ int dir = cds->cd_stack[cds->top]; cds->top--; return dir; } -int get_top_current_dir(struct CURRENT_DIR_STACK * cds){ +char * get_top_current_dir_name(struct CURRENT_DIR_STACK * cds){ + return cds->cd_stack_name[cds->top]; +} + +uint8_t get_top_current_dir(struct CURRENT_DIR_STACK * cds){ return cds->cd_stack[cds->top]; } @@ -30,4 +36,24 @@ void reverse_current_dir(struct CURRENT_DIR_STACK * cds){ i++; j--; } +} + +char * convert_to_paths(struct CURRENT_DIR_STACK * cds){ + int i = 1; + int j = 0; + char temp[255]; + char * path = temp; + while (i <= cds->top){ + path[j] = '/'; + j++; + int k = 0; + while (cds->cd_stack_name[i][k] != '\0'){ + path[j] = cds->cd_stack_name[i][k]; + j++; + k++; + } + i++; + } + path[j] = '\0'; + return path; } \ No newline at end of file diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 1b32c81..ebc5570 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -102,11 +102,6 @@ void command_call_ls(void){ * @return 0 jika berhasil, 1 jika gagal */ uint8_t command_call_cd(char *path){ - if (!initialized_cd_stack){ - initialized_cd_stack = TRUE; - // init_current_dir_stack(¤t_dir_stack); - syscall(9, (uint32_t) ¤t_dir_stack, 0, 0); - } // for one time only struct FAT32DriverState state_driver; @@ -136,7 +131,7 @@ uint8_t command_call_cd(char *path){ // Folder ditemukan current_directory_cluster = state_driver.dir_table_buf.table[i].cluster_high << 16 | state_driver.dir_table_buf.table[i].cluster_low; // push_current_dir(¤t_dir_stack, current_directory_cluster); - syscall(11, (uint32_t) ¤t_dir_stack, (uint32_t) current_directory_cluster, 0); + syscall(11, (uint32_t) ¤t_dir_stack, (uint32_t) current_directory_cluster, (uint32_t) path_name); return 0; } } @@ -591,8 +586,15 @@ int main(void) { char buf[16]; uint8_t command; + + if (!initialized_cd_stack){ + initialized_cd_stack = TRUE; + // init_current_dir_stack(¤t_dir_stack); + syscall(9, (uint32_t) ¤t_dir_stack, 0, 0); + } + while (TRUE) { - syscall(4, (uint32_t) buf, 0x20, (uint32_t) row_shell); + syscall(4, (uint32_t) buf, (uint32_t) ¤t_dir_stack, (uint32_t) row_shell); row_shell++; command = getCommandInput((char*) buf, 16); diff --git a/src/interrupt.c b/src/interrupt.c index 4d96c3a..6205bde 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -133,43 +133,18 @@ void puts_long_text(char *str, uint32_t len, uint32_t color, uint8_t *row_shells addRow(k); } - -void template(uint32_t row_shells){ - puts("Brother420/", 11, 0x0a, row_shells); - framebuffer_write(row_shells, 11, ':', 0x01, 0); - framebuffer_write(row_shells, 12, '$', 0x0F, 0); - framebuffer_set_cursor(row_shells, 14); -} - -/** - * cd - Mengganti current working directory (termasuk .. untuk naik) - * ls - Menuliskan isi current working directory - * mkdir - Membuat sebuah folder kosong baru - * cat - Menuliskan sebuah file sebagai text file ke layar (Gunakan format LF newline) - * cp - Mengcopy suatu file - * rm - Menghapus suatu file atau folder kosong - * mv - Memindah dan merename lokasi file/folder - * whereis - Mencari file/folder dengan nama yang sama diseluruh file system - - * @return 0 cd (spasi) - * @return 1 ls - * @return 2 mkdir (spasi) - * @return 3 cat (spasi) - * @return 4 cp (spasi) - * @return 5 rm (spasi) - * @return 6 mv (spasi) - * @return 7 whereis (spasi) -*/ -uint8_t getCommandInput(char *input, uint8_t len){ - char *command[] = {"cd ", "ls", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis "}; - uint8_t command_len[] = {3, 2, 6, 4, 3, 3, 3, 8}; - for (uint8_t i = 0; i < 8; i++){ - if (len >= command_len[i] && memcmp(input, command[i], command_len[i]) == 0){ - return i; - } - framebuffer_write(23, i, input[i], 0x0f, 0); +void template(uint32_t row_shells, char * cwd){ + uint8_t tempCol = 10; + puts("brother420", 10, 0x0a, row_shells); + while (cwd[tempCol - 10] != '\0'){ + framebuffer_write(row_shells, tempCol, cwd[tempCol - 10], 0x0a, 0); + tempCol++; } - return 255; + framebuffer_write(row_shells, tempCol, '/', 0x01, 0); + framebuffer_write(row_shells, tempCol+1, ':', 0x01, 0); + framebuffer_write(row_shells, tempCol+2, '$', 0x0F, 0); + framebuffer_set_cursor(row_shells, tempCol+4); + setCol(tempCol+4); } void puts_line(char *input, int row, int col, int length, int color){ @@ -178,520 +153,6 @@ void puts_line(char *input, int row, int col, int length, int color){ } } - -void command_call_ls(void){ - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - - int col = 0; - int row_add_needed = 1; - - for (int i = 1; i < 64; i++){ - - if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ - if (col == 5){ - col = 0; - row_shell++; - row_add_needed++; - } - puts_line(state_driver.dir_table_buf.table[i].name, row_shell, col*16, 8, 0x0f); - col++; - } - } - row_shell++; - - addRow(row_add_needed); - -} - -void command_call_mkdir(char *dirCommandName){ - - struct FAT32DriverRequest request = { - .buf = 0, - .ext = "\0\0\0", - .parent_cluster_number = current_directory_cluster, - .buffer_size = 0, - }; - for (int i = 6; i < 14; i++){ - request.name[i-6] = dirCommandName[i]; - } - write(request); -} - -void command_call_cp(char *cpCommandName){ - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - - struct ClusterBuffer cbuf[4]; - - struct FAT32DriverRequest request = { - .parent_cluster_number = current_directory_cluster, - .buf = cbuf, - }; - - uint8_t i = 0; - uint8_t j = 0; - while ((cpCommandName[i+3] != '.') && (cpCommandName[i+3] != ' ') && (i < 8)){ - request.name[i] = cpCommandName[i+3]; - i++; - } - - if (cpCommandName[i+3] == ' '){ - // Error karena tidak ada extensi - return; - } - - if (i == 8 && cpCommandName[i+3] != '.'){ - // Error karena nama file terlalu panjang - return; - } - - if (i < 8){ - for (int z = i; z < 8; z++){ - request.name[z] = '\0'; - } - } - - j = i+1; - while ((cpCommandName[j+3] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = cpCommandName[j+3]; - j++; - } - - if (j-i-1 == 3 && cpCommandName[j+3] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-i-1 < 3){ - for (int z = j-i-1; z < 3; z++){ - request.ext[z] = '\0'; - } - } - - - for (int m = 1; m < 64; m++){ - if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ - // File ditemukan - request.buffer_size = state_driver.dir_table_buf.table[m].filesize; - read(request); - break; - } - } - } - - uint8_t k = 0; - uint8_t l = 0; - while ((cpCommandName[j+4] != '.') && (cpCommandName[j+4] != ' ') && (k < 8)){ - request.name[k] = cpCommandName[j+4]; - k++; - j++; - } - - if (cpCommandName[j+4] == ' '){ - // Error karena tidak ada extensi - return; - } - - if (k == 8 && cpCommandName[j+4] != '.'){ - // Error karena nama file terlalu panjang - return; - } - - if (k < 8){ - for (int z = k; z < 8; z++){ - request.name[z] = '\0'; - } - } - - while ((cpCommandName[l+j+5] != ' ') && cpCommandName[l+j+5] != '\0' && (l < 3)){ - request.ext[l] = cpCommandName[l+j+5]; - l++; - } - - if (l == 3 && ((cpCommandName[l+j+5] != ' ') && (cpCommandName[l+j+5] != '\0'))){ - // Error karena extensi terlalu panjang - return; - } - - if (l < 3){ - for (int z = l; z < 3; z++){ - request.ext[z] = '\0'; - } - } - - write(request); - - -} - - -void command_call_rm(char *rmCommandName){ - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - bool isFolder = FALSE; - - struct FAT32DriverRequest request = { - .parent_cluster_number = current_directory_cluster, - }; - - uint8_t i = 0; - uint8_t j = 0; - while ((rmCommandName[i+3] != '.') && (rmCommandName[i+3] != ' ') && (i < 8)){ - request.name[i] = rmCommandName[i+3]; - i++; - } - - if (rmCommandName[i+3] == ' '){ - // Error karena tidak ada extensi - return; - } - - if (rmCommandName[i+3] == '\0'){ - // berarti folder - isFolder = TRUE; - for (int z = 0; z < 3; z++){ - request.ext[z] = '\0'; - } - } - - if (i < 8){ - for (int z = i; z < 8; z++){ - request.name[z] = '\0'; - } - } - - if (!isFolder){ - j = i+1; - while ((rmCommandName[j+3] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = rmCommandName[j+3]; - j++; - } - - if (j-i-1 == 3 && rmCommandName[j+3] != '\0' && rmCommandName[j+3] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-i-1 < 3){ - for (int z = j-i-1; z < 3; z++){ - request.ext[z] = '\0'; - } - } - } - - for (int m = 1; m < 64; m++){ - if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ - // File ditemukan - request.buffer_size = state_driver.dir_table_buf.table[m].filesize; - delete(request); - break; - } - } - } -} - - -void command_call_cat(char *rmCommandName){ - // asumsi file only - - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - - struct ClusterBuffer cbuf[4]; - - struct FAT32DriverRequest request = { - .parent_cluster_number = current_directory_cluster, - .buf = cbuf, - }; - - uint8_t i = 0; - uint8_t j = 0; - while ((rmCommandName[i+4] != '.') && (rmCommandName[i+4] != ' ') && (i < 8)){ - request.name[i] = rmCommandName[i+4]; - i++; - } - - if (rmCommandName[i+4] == ' '){ - // Error karena tidak ada extensi - return; - } - - if (i < 8){ - for (int z = i; z < 8; z++){ - request.name[z] = '\0'; - } - } - - j = i+1; - while ((rmCommandName[j+4] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = rmCommandName[j+4]; - j++; - } - - if (j-i-1 == 4 && rmCommandName[j+4] != '\0' && rmCommandName[j+4] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-i-1 < 3){ - for (int z = j-i-1; z < 3; z++){ - request.ext[z] = '\0'; - } - } - - for (int m = 1; m < 64; m++){ - if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ - // File ditemukan - request.buffer_size = state_driver.dir_table_buf.table[m].filesize; - read(request); - break; - } - } - } - - puts_long_text(request.buf, request.buffer_size, 0x0e, &row_shell); - - framebuffer_write(23, 79, 'L', 0x0F, 0x00); - -} - -/** - * Command cd dilakukan untuk pindah ke direktori path - * @param path direktori tujuan yang hanya satu kata - * @return 0 jika berhasil, 1 jika gagal -*/ -uint8_t command_call_cd(char *path){ - if (!initialized_cd_stack){ - initialized_cd_stack = TRUE; - init_current_dir_stack(¤t_dir_stack); - } - - // for one time only - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - - char path_name[8]; - char path_ext[3]; - memcpy(path_name, path, 8); - memcpy(path_ext, "\0\0\0", 3); - - if (memcmp(path, "..", 2) == 0){ - // Pindah ke parent directory - if (current_directory_cluster == 2){ - return 1; - } - pop_current_dir(¤t_dir_stack); - current_directory_cluster = get_top_current_dir(¤t_dir_stack); - return 0; - } - - for (int i = 0; i < 64; i++){ - if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[i].name, path_name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[i].ext, path_ext, 3) == 0){ - // Folder ditemukan - current_directory_cluster = state_driver.dir_table_buf.table[i].cluster_high << 16 | state_driver.dir_table_buf.table[i].cluster_low; - push_current_dir(¤t_dir_stack, current_directory_cluster); - return 0; - } - } - } - return 1; -} - - -// char* get_file_name(char *path){ -// char file_name[8]; -// uint8_t i = 0; -// while ((path[i] != '.') && (path[i+3] != ' ') && (i < 8)){ -// file_name[i] = path[i+3]; -// i++; -// } -// return file_name; -// } - - -/** - * Command mv file/folder dilakukan untuk merename file/folder dan memindahkannya ke path - * @param path nama file/folder dan direktori tujuan yang MASIH satu kata -*/ -void command_call_mv(char *path){ - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - bool isFolder = FALSE; - - struct FAT32DriverRequest request = { - .parent_cluster_number = current_directory_cluster, - }; - - char new_name[8]; - char new_ext[3]; - bool fileFound = FALSE; - // bool validName = FALSE; - - uint8_t i = 0; - uint8_t j = 0; - while ((path[i] != '.') && (path[i] != ' ') && (i < 8)){ - request.name[i] = path[i]; - i++; - } - - if (i == 8 && path[i] != '.' && path[i] != ' '){ - // berarti kepanjangan - return; - } - - if (path[i] == ' '){ - // berarti folder - isFolder = TRUE; - for (int z = 0; z < 3; z++){ - request.ext[z] = '\0'; - } - } - - if (i < 8){ - for (int z = i; z < 8; z++){ - request.name[z] = '\0'; - } - } - - j = i+1; - - if (!isFolder){ - - while ((path[j] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = path[j]; - j++; - } - - if (j-i-1 == 3 && path[j] != '\0' && path[j] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-i-1 < 3){ - for (int z = j-i-1; z < 3; z++){ - request.ext[z] = '\0'; - } - } - } - - // saat ini dah didapat mv file/folder - int m; - for (m = 1; m < 64; m++){ - if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ - // File ditemukan - request.buffer_size = state_driver.dir_table_buf.table[m].filesize; - fileFound = TRUE; - break; - } - } - } - - if (j + 1 == '/'){ - // TODO pindah direktori - } else { - - uint8_t k = isFolder ? j : j+1; - uint8_t l = 0; - - if (path[k] == '\0' || path[k] == ' '){ - // Error karena nama file tidak boleh kosong - return; - } - - while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0') && (path[k] != '.')){ - new_name[l] = path[k]; - k++; - l++; - } - - if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ - // Error karena nama file terlalu panjang - return; - } - - for (uint8_t z = l; z < 8; z++){ - new_name[z] = '\0'; - } - - if (isFolder){ - for (int z = 0; z < 3; z++){ - new_ext[z] = '\0'; - } - } else { - j = k+1; - while ((path[j] != ' ') && (j-k-1 < 3)){ - new_ext[j-k-1] = path[j]; - j++; - } - - if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-k-1 < 3){ - for (int z = j-k-1; z < 3; z++){ - new_ext[z] = '\0'; - } - } - } - - if (fileFound){ - memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); - memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); - write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - - } - - } - - -} - - -void command_call_multi_cd(char *path){ - struct FAT32DriverState state_driver; - read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - read_clusters(&state_driver.fat_table, 1, 1); - - uint8_t i = 0; - uint8_t j = 0; - while (path[i] != '\0'){ - if (path[i] == '/'){ - j = i; - } - i++; - } - - if (j == 0){ - // berarti hanya satu direktori - command_call_cd(path); - } else { - char new_path[64]; - memcpy(new_path+3, path, j); - new_path[j+3] = '\0'; - command_call_cd(new_path); - command_call_multi_cd(path+j+1); - } -} - void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -712,14 +173,16 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta *((int8_t*) cpu.ecx) = delete(request); } else if (cpu.eax == 4) { - template((uint32_t) cpu.edx); + char *cwd = convert_to_paths((struct CURRENT_DIR_STACK *) cpu.ecx); + template((uint32_t) cpu.edx, cwd); clear_keyboard_buffer(); keyboard_state_activate(); __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called while (is_keyboard_blocking()); char buf[KEYBOARD_BUFFER_SIZE]; get_keyboard_buffer(buf); - memcpy((char *) cpu.ebx, buf, cpu.ecx); + memcpy((char *) cpu.ebx, buf, 0x20); + } else if (cpu.eax == 5) { puts2((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side } @@ -752,7 +215,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta // Syscall push current dir else if (cpu.eax == 11) { - push_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx, cpu.ecx); + push_current_dir((struct CURRENT_DIR_STACK *) cpu.ebx, cpu.ecx, (char *) cpu.edx); } // Syscall puts long text @@ -764,6 +227,11 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta else if (cpu.eax == 13) { write_clusters((struct FAT32DirectoryTable *) cpu.ebx, cpu.ecx, cpu.edx); } + + // Syscall get path from current dir + // else if (cpu.eax == 14) { + // convert_to_path((struct CURRENT_DIR_STACK *) cpu.ebx, (char *) cpu.ecx); + // } } diff --git a/src/keyboard.c b/src/keyboard.c index fbfceba..8d3a376 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -515,6 +515,14 @@ void keyboard_isrs(void) { } +void setCol (uint8_t cols){ + if (cols >= 80){ + col = 0; + } else { + col = cols; + } +} + /* -- Keyboard Interrupt Service Routine -- */ @@ -541,7 +549,7 @@ void keyboard_isr(void) { framebuffer_write(21,11,'L',0xa,0); } else { keyboard_state.buffer_index = 0; - col = 14; + // col = 14; while (is_keyboard_blocking()){ uint8_t scancode = in(KEYBOARD_DATA_PORT); char mapped_char = keyboard_scancode_1_to_ascii_map[scancode]; diff --git a/src/lib-header/currentdirectorystack.h b/src/lib-header/currentdirectorystack.h index 0b31423..2dbcead 100644 --- a/src/lib-header/currentdirectorystack.h +++ b/src/lib-header/currentdirectorystack.h @@ -1,21 +1,25 @@ #ifndef _CURRENT_DIRECTORY_STACK_H_ #define _CURRENT_DIRECTORY_STACK_H_ - +#include "stdtype.h" struct CURRENT_DIR_STACK { - int cd_stack[256]; + uint8_t cd_stack[256]; + char* cd_stack_name[256]; int top; }; void init_current_dir_stack(struct CURRENT_DIR_STACK *cds); -void push_current_dir(struct CURRENT_DIR_STACK * cds, int dir); +void push_current_dir(struct CURRENT_DIR_STACK * cds, uint8_t dir, char* dir_name); + +uint8_t pop_current_dir(struct CURRENT_DIR_STACK * cds); -int pop_current_dir(struct CURRENT_DIR_STACK * cds); +char * get_top_current_dir_name(struct CURRENT_DIR_STACK * cds); -int get_top_current_dir(struct CURRENT_DIR_STACK * cds); +uint8_t get_top_current_dir(struct CURRENT_DIR_STACK * cds); void reverse_current_dir(struct CURRENT_DIR_STACK * cds); +char* convert_to_paths(struct CURRENT_DIR_STACK * cds); #endif \ No newline at end of file diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index f1a3dee..316c81b 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -83,4 +83,6 @@ void keyboard_isr(void); */ void addRow(int row); +void setCol(uint8_t cols); + #endif \ No newline at end of file From 66f0a12f9e9a54b4e9f34c37791d32ae00c28545 Mon Sep 17 00:00:00 2001 From: Darmodar Date: Sat, 29 Apr 2023 03:17:07 +0700 Subject: [PATCH 164/176] feat: add whereis template --- src/external/user-shell.c | 123 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 1b32c81..ccec76b 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -433,6 +433,129 @@ void command_call_rm(char *rmCommandName){ } } +// void command_call_Whereis(char *whCommandName){ +// struct CURRENT_DIR_STACK path; +// struct CURRENT_DIR_STACK dir; +// struct CURRENT_DIR_STACK ret_stack; +// syscall(9, (uint32_t) &path, 0, 0); +// syscall(9, (uint32_t) &dir, 0, 0); +// syscall(9, (uint32_t) &ret_stack, 0, 0); + +// // struct FAT32DriverState state_driver; +// // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); +// // read_clusters(&state_driver.fat_table, 1, 1); + +// bool isFolder = FALSE; +// char name[8]; +// char ext[3]; +// uint8_t i = 0; +// uint8_t j = 0; + +// while ((whCommandName[i+8] != '.') && (whCommandName[i+8] != ' ') && (i < 8)){ +// name[i] = whCommandName[i+8]; +// i++; +// } + +// if (whCommandName[i+8] == ' '){ +// // Error karena tidak ada extensi +// return; +// } + +// if (whCommandName[i+8] == '\0'){ +// // berarti folder +// isFolder = TRUE; +// for (int z = 0; z < 3; z++){ +// ext[z] = '\0'; +// } +// } + +// if (i < 8){ +// for (int z = i; z < 8; z++){ +// name[z] = '\0'; +// } +// } + +// if (!isFolder){ +// j = i+1; +// while ((whCommandName[j+3] != ' ') && (j-i-1 < 3)){ +// ext[j-i-1] = whCommandName[j+3]; +// j++; +// } + +// if (j-i-1 == 3 && whCommandName[j+3] != '\0' && whCommandName[j+3] != ' '){ +// // Error karena extensi terlalu panjang +// return; +// } + +// if (j-i-1 < 3){ +// for (int z = j-i-1; z < 3; z++){ +// ext[z] = '\0'; +// } +// } + +// do // proses pencarian ketika dia file +// { +// current_directory_cluster = syscall(10, (uint32_t) &dir, 0, 0); +// syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); +// for (int m = 0; m < 64; m++){ +// if (state_driver.dir_table_buf.table[m].buff == 0){ +// syscall(11, (uint32_t) &dir, (uint32_t) current_directory_cluster, 0); +// } + +// if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && +// memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ +// syscall(11, (uint32_t) &path, (uint32_t) current_directory_cluster, 0); + +// // File ditemukan +// // request.buffer_size = state_driver.dir_table_buf.table[m].filesize; +// // // delete(request); +// // syscall(3, (uint32_t) &request, 0, 0); +// // break; + + +// } +// } + +// } while (dir.top != 0); + +// } else { +// do // proses pencarian ketika dia folder +// { +// current_directory_cluster = syscall(10, (uint32_t) &dir, 0, 0); +// syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); +// for (int m = 0; m < 64; m++){ + +// if (state_driver.dir_table_buf.table[m].buff == 0){ +// syscall(11, (uint32_t) &dir, (uint32_t) current_directory_cluster, 0); +// } + +// if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && +// memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ +// syscall(11, (uint32_t) &path, (uint32_t) current_directory_cluster, 0); + +// // File ditemukan +// // request.buffer_size = state_driver.dir_table_buf.table[m].filesize; +// // // delete(request); +// // syscall(3, (uint32_t) &request, 0, 0); +// // break; + + +// } +// } + +// } while (dir.top != 0); +// } + + + + + + +// } + + + + void command_call_mv(char *path){ struct FAT32DriverState state_driver; // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); From b99c3a7387c0c867eff4e640f0c491e2acfcaaaf Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 04:08:38 +0700 Subject: [PATCH 165/176] feat: add whereis logic --- src/directorystack.c | 25 +++++----- src/external/user-shell.c | 82 ++++++++++++++++++++++++++++++++- src/interrupt.c | 25 ++++++++-- src/lib-header/directorystack.h | 5 +- 4 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/directorystack.c b/src/directorystack.c index 84509fe..60dd2c7 100644 --- a/src/directorystack.c +++ b/src/directorystack.c @@ -6,21 +6,21 @@ void init_dir_stack(struct DIR_STACK *stack) { stack->top = -1; } -void push_dir(struct DIR_STACK * ds, char name[8]){ +void push_dir(struct DIR_STACK * ds, char *path){ ds->top++; - memcpy(ds->stack[ds->top].name, name, 8); + memcpy(ds->stack[ds->top].path, path, 255); } char * pop_dir(struct DIR_STACK * ds){ if (ds->top == -1) return "\0"; - char * name = ds->stack[ds->top].name; + char * path = ds->stack[ds->top].path; ds->top--; - return name; + return path; } char* get_top_dir(struct DIR_STACK * ds){ - return ds->stack[ds->top].name; + return ds->stack[ds->top].path; } void reverse_dir(struct DIR_STACK * ds){ @@ -28,15 +28,14 @@ void reverse_dir(struct DIR_STACK * ds){ int j = ds->top; while (i < j){ char temp[8]; - memcpy(temp, ds->stack[i].name, 8); - memcpy(ds->stack[i].name, ds->stack[j].name, 8); - memcpy(ds->stack[j].name, temp, 8); + memcpy(temp, ds->stack[i].path, 8); + memcpy(ds->stack[i].path, ds->stack[j].path, 8); + memcpy(ds->stack[j].path, temp, 8); i++; j--; } } - struct DIR_STACK get_dir_stack(char * request, int * validate){ struct DIR_STACK ds; init_dir_stack(&ds); @@ -47,10 +46,10 @@ struct DIR_STACK get_dir_stack(char * request, int * validate){ i++; continue; } - char name[8]; + char path[8]; int j = 0; while (request[i] != '/' && request[i] != '\0'){ - name[j] = request[i]; + path[j] = request[i]; i++; j++; } @@ -59,10 +58,10 @@ struct DIR_STACK get_dir_stack(char * request, int * validate){ return ds; } while (j < 8){ - name[j] = '\0'; + path[j] = '\0'; j++; } - push_dir(&ds, name); + push_dir(&ds, path); } return ds; diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 5018c8d..aab57ca 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -1,10 +1,12 @@ #include "../lib-header/stdtype.h" #include "../lib-header/fat32.h" #include "../lib-header/currentdirectorystack.h" +#include "../lib-header/directorystack.h" uint8_t row_shell = 0; int current_directory_cluster = ROOT_CLUSTER_NUMBER; struct CURRENT_DIR_STACK current_dir_stack; +struct DIR_STACK dirRet; bool initialized_cd_stack = FALSE; void* memcpy(void* restrict dest, const void* restrict src, size_t n) { @@ -548,7 +550,85 @@ void command_call_rm(char *rmCommandName){ // } +void dfs(struct CURRENT_DIR_STACK * dir, char * name, char * ext){ + struct FAT32DriverState state_driver; + char * returnVal; + char isFolder[3] = "\0\0\0"; + syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + for (int m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, ext, 3) == 0){ + // File ditemukan + syscall(15, (uint32_t) &dir, (uint32_t) &returnVal, 0); + syscall(14, (uint32_t) &dirRet, (uint32_t) returnVal, 0); + } + } + if (memcmp(state_driver.dir_table_buf.table[m].name, isFolder, 3) == 0){ + syscall(11, (uint32_t) &dir, 0, (uint32_t) state_driver.dir_table_buf.table[m].name); + dfs(dir, name, ext); + } + } +} + +void command_call_whereis(char *whCommandName){ + struct CURRENT_DIR_STACK dir; + + syscall(16, (uint32_t) &dirRet, 0, 0); + + bool isFolder = FALSE; + char name[8]; + char ext[3]; + uint8_t i = 0; + uint8_t j = 0; + + while ((whCommandName[i+8] != '.') && (whCommandName[i+8] != ' ') && (i < 8)){ + name[i] = whCommandName[i+8]; + i++; + } + + if (whCommandName[i+8] == ' '){ + // Error karena tidak ada extensi + return; + } + + if (whCommandName[i+8] == '\0'){ + // berarti folder + isFolder = TRUE; + for (int z = 0; z < 3; z++){ + ext[z] = '\0'; + } + } + + if (i < 8){ + for (int z = i; z < 8; z++){ + name[z] = '\0'; + } + } + + if (!isFolder){ + j = i+1; + while ((whCommandName[j+3] != ' ') && (j-i-1 < 3)){ + ext[j-i-1] = whCommandName[j+3]; + j++; + } + if (j-i-1 == 3 && whCommandName[j+3] != '\0' && whCommandName[j+3] != ' '){ + // Error karena extensi terlalu panjang + return; + } + + if (j-i-1 < 3){ + for (int z = j-i-1; z < 3; z++){ + ext[z] = '\0'; + } + } + + } + + dfs(&dir, name, ext); + +} void command_call_mv(char *path){ @@ -753,7 +833,7 @@ int main(void) { break; case 7: // whereis - // framebuffer_write(0, 79, '7', 0x0f, 0); + command_call_whereis((char *) buf); break; default: // command not found diff --git a/src/interrupt.c b/src/interrupt.c index 6205bde..d3e187b 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -153,6 +153,12 @@ void puts_line(char *input, int row, int col, int length, int color){ } } +void showWhereIs(struct DIR_STACK dir_stack, uint32_t row_shells){ + for (int i = 0; i < dir_stack.top; i++){ + puts((char *) &(dir_stack.stack[i]), 80, 0x0a, row_shells); + } +} + void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptStack info) { if (cpu.eax == 0) { struct FAT32DriverRequest request = *(struct FAT32DriverRequest*) cpu.ebx; @@ -228,10 +234,21 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta write_clusters((struct FAT32DirectoryTable *) cpu.ebx, cpu.ecx, cpu.edx); } - // Syscall get path from current dir - // else if (cpu.eax == 14) { - // convert_to_path((struct CURRENT_DIR_STACK *) cpu.ebx, (char *) cpu.ecx); - // } + // Syscall get where is location + else if (cpu.eax == 14) { + push_dir((struct DIR_STACK * ) cpu.ebx, (char *) cpu.ecx); + } + + // Syscall to convert to path + else if (cpu.eax == 15) { + char *cwd = convert_to_paths((struct CURRENT_DIR_STACK *) cpu.ebx); + memcpy((char *) cpu.ecx, cwd, 0x100); + } + + // Syscall initialize dir stack + else if (cpu.eax == 16) { + init_dir_stack((struct DIR_STACK *) cpu.ebx); + } } diff --git a/src/lib-header/directorystack.h b/src/lib-header/directorystack.h index c78a6f5..544ef69 100644 --- a/src/lib-header/directorystack.h +++ b/src/lib-header/directorystack.h @@ -2,7 +2,7 @@ #define _DIRECTORSTACK_H struct DIR_STACK_NAME { - char name[8]; + char path[255]; }; struct DIR_STACK { @@ -12,7 +12,7 @@ struct DIR_STACK { void init_dir_stack(struct DIR_STACK *stack); -void push_dir(struct DIR_STACK * ds, char name[8]); +void push_dir(struct DIR_STACK * ds, char *path); char* pop_dir(struct DIR_STACK * ds); @@ -22,5 +22,4 @@ void reverse_dir(struct DIR_STACK * ds); struct DIR_STACK get_dir_stack(char * request, int * validate); - #endif \ No newline at end of file From 2a6f057fba3f7f3d9bbe83577bb8462fe221e610 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 04:13:59 +0700 Subject: [PATCH 166/176] update kernel --- src/kernel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/kernel.c b/src/kernel.c index 8965f50..af4e685 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -44,7 +44,7 @@ void kernel_setup(void) { memcpy(requester.name + 4, "FFAA", 4); requester.name[0] = 'c'; - requester.parent_cluster_number = 7; + requester.parent_cluster_number = 9; write(requester); requester.buffer_size = 0x14; @@ -54,13 +54,13 @@ void kernel_setup(void) { for (uint32_t i = 0; i < 15; i++){ if (i == 4){ memcpy(requester.name + 4, "L\0\0\0", 4); - requester.parent_cluster_number = 7; + requester.parent_cluster_number = 9; } else if (i == 8){ memcpy(requester.name + 4, "Du\0\0", 4); - requester.parent_cluster_number = 8; + requester.parent_cluster_number = 10; } else if (i == 12){ memcpy(requester.name + 4, "HALO", 4); - requester.parent_cluster_number = 9; + requester.parent_cluster_number = 11; } requester.name[0]++; write(requester); From 1fef2791ac3fae26395b6246955a75f8de694187 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 10:12:36 +0700 Subject: [PATCH 167/176] fix: bug on cd - stack dir was pushed by unknown and make it unsync - now stack dir will always update based on cluster number --- src/external/user-shell.c | 33 ++++++++++++++++++++++++++++++--- src/interrupt.c | 6 +++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index aab57ca..81201d4 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -40,6 +40,30 @@ void syscall(uint32_t eax, uint32_t ebx, uint32_t ecx, uint32_t edx) { __asm__ volatile("int $0x30"); } +char* dirStackConverter(struct CURRENT_DIR_STACK *dir){ + struct FAT32DriverState state_driver; + char temp[255]; + char * cwd = temp; + int i = 1; + int j = 0; + int k = 0; + while(i <= dir->top){ + cwd[j] = '/'; + j++; + syscall(8, (uint32_t) &state_driver.dir_table_buf, dir->cd_stack[i], 1); + memcpy(dir->cd_stack_name[i], state_driver.dir_table_buf.table[0].name, 8); + while(dir->cd_stack_name[i][k] != '\0'){ + cwd[j] = dir->cd_stack_name[i][k]; + j++; + k++; + } + k = 0; + i++; + } + cwd[j] = '\0'; + return cwd; +} + // TODO: pindahin semua fungsi dari interupt.c /** @@ -126,7 +150,7 @@ uint8_t command_call_cd(char *path){ return 0; } - for (int i = 0; i < 64; i++){ + for (int i = 1; i < 64; i++){ if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ if (memcmp(state_driver.dir_table_buf.table[i].name, path_name, 8) == 0 && memcmp(state_driver.dir_table_buf.table[i].ext, path_ext, 3) == 0){ @@ -148,6 +172,7 @@ void command_call_multi_cd(char *path){ while (path[i] != '\0'){ if (path[i] == '/'){ j = i; + break; } i++; } @@ -159,7 +184,8 @@ void command_call_multi_cd(char *path){ char new_path[64]; memcpy(new_path, path, j); new_path[j] = '\0'; - command_call_cd(new_path); + uint8_t retVal = command_call_cd(new_path); + if (retVal == 0) command_call_multi_cd(path+j+1); } } @@ -797,7 +823,8 @@ int main(void) { } while (TRUE) { - syscall(4, (uint32_t) buf, (uint32_t) ¤t_dir_stack, (uint32_t) row_shell); + char * cwdpath = dirStackConverter(¤t_dir_stack); + syscall(4, (uint32_t) buf, (uint32_t) cwdpath, (uint32_t) row_shell); row_shell++; command = getCommandInput((char*) buf, 16); diff --git a/src/interrupt.c b/src/interrupt.c index d3e187b..7fa5558 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -179,15 +179,15 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta *((int8_t*) cpu.ecx) = delete(request); } else if (cpu.eax == 4) { - char *cwd = convert_to_paths((struct CURRENT_DIR_STACK *) cpu.ecx); - template((uint32_t) cpu.edx, cwd); + // char *cwd = convert_to_paths((struct CURRENT_DIR_STACK *) cpu.ecx); + template((uint32_t) cpu.edx, (char *) cpu.ecx); clear_keyboard_buffer(); keyboard_state_activate(); __asm__("sti"); // Due IRQ is disabled when main_interrupt_handler() called while (is_keyboard_blocking()); char buf[KEYBOARD_BUFFER_SIZE]; get_keyboard_buffer(buf); - memcpy((char *) cpu.ebx, buf, 0x20); + memcpy((char *) cpu.ebx, buf, 0x100); } else if (cpu.eax == 5) { puts2((char *) cpu.ebx, cpu.ecx, cpu.edx); // Modified puts() on kernel side From dcfbbce309a3415be60d0e6339f7727b89b838d6 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 11:04:33 +0700 Subject: [PATCH 168/176] feat: add ls varians - "ls" to show all items in the directory - "ls -a" to show all items in the directory with ext - "ls -f" to show all files in the directory - "ls -ff" to show all files in the directory with ext - "ls -F" to show all folders in the directory --- src/external/user-shell.c | 102 ++++++++++++++++++++++++++++++++++---- src/interrupt.c | 2 +- 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 81201d4..0e4a837 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -77,18 +77,24 @@ char* dirStackConverter(struct CURRENT_DIR_STACK *dir){ * whereis - Mencari file/folder dengan nama yang sama diseluruh file system * @return 0 cd (spasi) - * @return 1 ls + * @return 1 ls -a * @return 2 mkdir (spasi) * @return 3 cat (spasi) * @return 4 cp (spasi) * @return 5 rm (spasi) * @return 6 mv (spasi) * @return 7 whereis (spasi) + * @return 8 ls -ff + * @return 9 ls -F + * @return 10 ls -f + * @return 11 ls + * @return 255 command not found */ uint8_t getCommandInput(char *input, uint8_t len){ - char *command[] = {"cd ", "ls", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis "}; - uint8_t command_len[] = {3, 2, 6, 4, 3, 3, 3, 8}; - for (uint8_t i = 0; i < 8; i++){ + char *command[] = {"cd ", "ls -a", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis ", + "ls -ff", "ls -F", "ls -f", "ls"}; + uint8_t command_len[] = {3, 5, 6, 4, 3, 3, 3, 8, 6, 5, 5, 2}; + for (uint8_t i = 0; i < 12; i++){ if (len >= command_len[i] && memcmp(input, command[i], command_len[i]) == 0){ return i; } @@ -96,24 +102,82 @@ uint8_t getCommandInput(char *input, uint8_t len){ return 255; } -void command_call_ls(void){ +/** + * @param type 0 ls + * @param type 1 ls -F + * @param type 2 ls -f + * @param type 3 ls -ff + * @param type 4 ls -a +*/ +void command_call_ls(uint8_t type){ struct FAT32DriverState state_driver; // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); int col = 0; int row_add_needed = 1; - + bool isFile = FALSE; + for (int i = 1; i < 64; i++){ + char nprinter[12] = {0}; + char aprinter[12] = {0}; + char Fprinter[12] = {0}; + char fprinter[12] = {0}; + char ffprinter[12] = {0}; if (state_driver.dir_table_buf.table[i].user_attribute == UATTR_NOT_EMPTY){ - if (col == 5){ + if (col == 4 && type >= 3){ col = 0; row_shell++; row_add_needed++; + } + else if (col == 5){ + col = 0; + row_shell++; + row_add_needed++; + } + memcpy(aprinter, state_driver.dir_table_buf.table[i].name, 8); + memcpy(nprinter, state_driver.dir_table_buf.table[i].name, 8); + memcpy(aprinter+9, state_driver.dir_table_buf.table[i].ext, 3); + if (memcmp(state_driver.dir_table_buf.table[i].ext, "\0\0\0", 3) != 0){ + // File + isFile = TRUE; + aprinter[8] = '.'; + memcpy(fprinter, aprinter, 8); + memcpy(ffprinter, aprinter, 12); + } else { + // Folder + isFile = FALSE; + memcpy(Fprinter, aprinter, 8); + } + + switch (type){ + case 0: + syscall(6, (uint32_t) nprinter, row_shell, col*16); + break; + case 1: + syscall(6, (uint32_t) Fprinter, row_shell, col*16); + break; + case 2: + syscall(6, (uint32_t) fprinter, row_shell, col*16); + break; + case 3: + syscall(6, (uint32_t) ffprinter, row_shell, col*20); + break; + case 4: + syscall(6, (uint32_t) aprinter, row_shell, col*20); + break; + default: + break; + } + + if (isFile && type != 1){ + col++; + } else if (!isFile && type == 1){ + col++; + } else if (type == 0 || type == 4){ + col++; } - syscall(6, (uint32_t) state_driver.dir_table_buf.table[i].name, row_shell, col*16); - col++; } } row_shell++; @@ -835,8 +899,8 @@ int main(void) { command_call_multi_cd(((char *) buf) + 3); break; case 1: - // ls - command_call_ls(); + // ls -a + command_call_ls(4); break; case 2: // mkdir @@ -862,6 +926,22 @@ int main(void) { // whereis command_call_whereis((char *) buf); break; + case 8: + // ls -ff + command_call_ls(3); + break; + case 9: + // ls -F + command_call_ls(1); + break; + case 10: + // ls -f + command_call_ls(2); + break; + case 11: + // ls + command_call_ls(0); + break; default: // command not found // framebuffer_write(0, 79, 'x', 0x0f, 0); diff --git a/src/interrupt.c b/src/interrupt.c index 7fa5558..17e73fb 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -195,7 +195,7 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta // Syscall cd else if (cpu.eax == 6) { - puts_line((char*) cpu.ebx, cpu.ecx, cpu.edx, 8, 0x0F); + puts_line((char*) cpu.ebx, cpu.ecx, cpu.edx, 12, 0x0F); } // Syscall addrow From c348b498aa7f8db5591bd60f5ba50e4c293f3c9c Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 11:22:46 +0700 Subject: [PATCH 169/176] fix: no enter bug in cat - fix bug when text has no enter --- src/interrupt.c | 3 ++- src/kernel.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/interrupt.c b/src/interrupt.c index 17e73fb..8ca9221 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -130,7 +130,8 @@ void puts_long_text(char *str, uint32_t len, uint32_t color, uint8_t *row_shells framebuffer_write(*row_shells, j, str[i], color, 0); j++; } - addRow(k); + (*row_shells) ++; + addRow(k+1); } void template(uint32_t row_shells, char * cwd){ diff --git a/src/kernel.c b/src/kernel.c index af4e685..e8cc935 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -81,7 +81,7 @@ void kernel_setup(void) { "Naicha dame naicha dame\n" "Demo honto wa iitai yo\n" "Ikanaide\n" - "Chizuru\n" + "Chizuru" }; requester.name[0] = 'i'; From 338cc52c762ea947e2708d73d041b5c1ad750e0d Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 11:44:47 +0700 Subject: [PATCH 170/176] fix: bug on cp - There was a lot of bug unhandles and now handled - not all test case has been tested --- src/external/user-shell.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 0e4a837..2892fd2 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -403,11 +403,15 @@ void command_call_cp(char *cpCommandName){ break; } } + if (m == 63){ + // File tidak ditemukan + return; + } } uint8_t k = 0; uint8_t l = 0; - while ((cpCommandName[j+4] != '.') && (cpCommandName[j+4] != ' ') && (k < 8)){ + while ((cpCommandName[j+4] != '.') && (cpCommandName[j+4] != ' ') && (cpCommandName[j+4] != '\0') && (k < 8)){ request.name[k] = cpCommandName[j+4]; k++; j++; @@ -418,7 +422,7 @@ void command_call_cp(char *cpCommandName){ return; } - if (k == 8 && cpCommandName[j+4] != '.'){ + if (k == 8 && cpCommandName[j+4] != '.' && cpCommandName[j+4] != '\0'){ // Error karena nama file terlalu panjang return; } @@ -439,7 +443,9 @@ void command_call_cp(char *cpCommandName){ return; } - if (l < 3){ + if (l == 0){ + // do nothing karena ext tidak berubah + } else if (l < 3){ for (int z = l; z < 3; z++){ request.ext[z] = '\0'; } From 70b05ef70515b6a70fae0ae4441bec3e4bc49247 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 12:42:02 +0700 Subject: [PATCH 171/176] fix: bug on rename - self cluster wasn't written --- src/external/user-shell.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 2892fd2..90cb583 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -729,15 +729,17 @@ void command_call_whereis(char *whCommandName){ void command_call_mv(char *path){ struct FAT32DriverState state_driver; + struct FAT32DriverState state_driver2; // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); // read_clusters(&state_driver.fat_table, 1, 1); syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); - syscall(8, (uint32_t) &state_driver.fat_table, 1, 1); + uint32_t location; bool isFolder = FALSE; - + struct ClusterBuffer cbuf[4]; struct FAT32DriverRequest request = { .parent_cluster_number = current_directory_cluster, + .buf = cbuf, }; char new_name[8]; @@ -801,13 +803,17 @@ void command_call_mv(char *path){ // File ditemukan request.buffer_size = state_driver.dir_table_buf.table[m].filesize; fileFound = TRUE; - break; + location = state_driver.dir_table_buf.table[m].cluster_high << 16 | state_driver.dir_table_buf.table[m].cluster_low; + syscall(8, (uint32_t) &state_driver2.dir_table_buf, location, 1); + break; } } } - if (j + 1 == '/'){ + if (path[j+1] == '.' && path[j+2] == '/'){ // TODO pindah direktori + + } else { uint8_t k = isFolder ? j : j+1; @@ -849,7 +855,9 @@ void command_call_mv(char *path){ return; } - if (j-k-1 < 3){ + if (j-k-1 == 0){ + // do nothing extensi tidak berubah + } else if (j-k-1 < 3){ for (int z = j-k-1; z < 3; z++){ new_ext[z] = '\0'; } @@ -859,8 +867,11 @@ void command_call_mv(char *path){ if (fileFound){ memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); + memcpy(state_driver2.dir_table_buf.table[0].name, new_name, 8); + memcpy(state_driver2.dir_table_buf.table[0].ext, new_ext, 3); // write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); } } From a563e354e9d8a323aaf6e8d5232ee85b95964146 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 13:19:32 +0700 Subject: [PATCH 172/176] save mv state, some of bug is fixed but not all --- src/external/user-shell.c | 157 ++++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 50 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 90cb583..494ef6e 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -735,6 +735,7 @@ void command_call_mv(char *path){ syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); uint32_t location; + uint32_t target_location; bool isFolder = FALSE; struct ClusterBuffer cbuf[4]; struct FAT32DriverRequest request = { @@ -742,8 +743,8 @@ void command_call_mv(char *path){ .buf = cbuf, }; - char new_name[8]; - char new_ext[3]; + char new_name[8] = {0}; + char new_ext[3] = {0}; bool fileFound = FALSE; // bool validName = FALSE; @@ -809,73 +810,129 @@ void command_call_mv(char *path){ } } } + uint8_t adder = 0; + char target_name[8]; + char target_ext[3]; - if (path[j+1] == '.' && path[j+2] == '/'){ + if (path[j] == '/'){ // TODO pindah direktori + + if (memcmp(path + j + 1, "..", 2) == 0){ + // pindah ke parent + if (current_directory_cluster == 0){ + // Error karena sudah di root + return; + } + target_location = state_driver.dir_table_buf.table[0].cluster_high << 16 | state_driver.dir_table_buf.table[0].cluster_low; + adder = 4; + } else { + // pindah ke child + for (int z = 0; z < 8; z++){ + target_name[z] = '\0'; + } + for (int z = 0; z < 3; z++){ + target_ext[z] = '\0'; + } + uint8_t k = j+1; + uint8_t l = 0; + while ((path[k] != ' ') && (k-j-2 < 8) && (path[k] != '\0') && (path[k] != '.')){ + target_name[l] = path[k]; + k++; + l++; + adder++; + } - } else { + if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ + // Error karena nama file terlalu panjang + return; + } - uint8_t k = isFolder ? j : j+1; - uint8_t l = 0; + for (uint8_t z = l; z < 8; z++){ + target_name[z] = '\0'; + } - if (path[k] == '\0' || path[k] == ' '){ - // Error karena nama file tidak boleh kosong - return; - } + adder++; - while ((path[k] != ' ') && (k-j-1 < 8) && (path[k] != '\0') && (path[k] != '.')){ - new_name[l] = path[k]; - k++; - l++; + for (m = 1; m < 64; m++){ + if (state_driver2.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, target_name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, target_ext, 3) == 0){ + // File ditemukan + target_location = state_driver2.dir_table_buf.table[m].cluster_high << 16 | state_driver2.dir_table_buf.table[m].cluster_low; + + break; + } + } + } } + } - if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ - // Error karena nama file terlalu panjang - return; - } + else { + target_location = current_directory_cluster; + } - for (uint8_t z = l; z < 8; z++){ - new_name[z] = '\0'; - } + uint8_t k = isFolder ? j : j+1; + k += adder; + uint8_t l = 0; - if (isFolder){ - for (int z = 0; z < 3; z++){ - new_ext[z] = '\0'; - } - } else { - j = k+1; - while ((path[j] != ' ') && (j-k-1 < 3)){ - new_ext[j-k-1] = path[j]; - j++; - } + if (path[k] == '\0' || path[k] == ' '){ + // Error karena nama file tidak boleh kosong + return; + } - if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ - // Error karena extensi terlalu panjang - return; - } + while ((path[k] != ' ') && (k-j-1-adder < 8) && (path[k] != '\0') && (path[k] != '.')){ + new_name[l] = path[k]; + k++; + l++; + } - if (j-k-1 == 0){ - // do nothing extensi tidak berubah - } else if (j-k-1 < 3){ - for (int z = j-k-1; z < 3; z++){ - new_ext[z] = '\0'; - } - } + if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ + // Error karena nama file terlalu panjang + return; + } + + for (uint8_t z = l; z < 8; z++){ + new_name[z] = '\0'; + } + + if (isFolder){ + for (int z = 0; z < 3; z++){ + new_ext[z] = '\0'; + } + } else { + j = k+1; + while ((path[j] != ' ') && (j-k-1 < 3)){ + new_ext[j-k-1] = path[j]; + j++; + } + + if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ + // Error karena extensi terlalu panjang + return; } - if (fileFound){ - memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); - memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); - memcpy(state_driver2.dir_table_buf.table[0].name, new_name, 8); - memcpy(state_driver2.dir_table_buf.table[0].ext, new_ext, 3); - // write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); - syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); + if (j-k-1 == 0){ + // do nothing extensi tidak berubah + } else if (j-k-1 < 3){ + for (int z = j-k-1; z < 3; z++){ + new_ext[z] = '\0'; + } } + } + if (fileFound){ + memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); + memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); + memcpy(state_driver2.dir_table_buf.table[0].name, new_name, 8); + memcpy(state_driver2.dir_table_buf.table[0].ext, new_ext, 3); + // write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(13, (uint32_t) &state_driver.dir_table_buf, target_location, 1); + syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); } + + } From 49f63186dc25cc85f361856c06414d6173308933 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 22:06:53 +0700 Subject: [PATCH 173/176] mv can now only renaming --- src/external/user-shell.c | 242 +++++++++++--------------------------- 1 file changed, 68 insertions(+), 174 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 494ef6e..8b9da00 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -269,7 +269,6 @@ void command_call_mkdir(char *dirCommandName){ syscall(2, (uint32_t) &request, 0, 0); } - void command_call_cat(char *rmCommandName){ // asumsi file only @@ -726,214 +725,109 @@ void command_call_whereis(char *whCommandName){ } - void command_call_mv(char *path){ struct FAT32DriverState state_driver; struct FAT32DriverState state_driver2; - // read_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - // read_clusters(&state_driver.fat_table, 1, 1); + bool isFile = FALSE; syscall(8, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); - - uint32_t location; - uint32_t target_location; - bool isFolder = FALSE; struct ClusterBuffer cbuf[4]; struct FAT32DriverRequest request = { .parent_cluster_number = current_directory_cluster, .buf = cbuf, }; - char new_name[8] = {0}; - char new_ext[3] = {0}; - bool fileFound = FALSE; - // bool validName = FALSE; - uint8_t i = 0; - uint8_t j = 0; - while ((path[i] != '.') && (path[i] != ' ') && (i < 8)){ + while (path[i] != ' ' && path[i] != '.') { request.name[i] = path[i]; i++; } - if (i == 8 && path[i] != '.' && path[i] != ' '){ - // berarti kepanjangan - return; - } - - if (path[i] == ' '){ - // berarti folder - isFolder = TRUE; - for (int z = 0; z < 3; z++){ - request.ext[z] = '\0'; - } + uint8_t ii = i; + while (ii < 8){ + request.name[ii] = '\0'; + ii++; } - if (i < 8){ - for (int z = i; z < 8; z++){ - request.name[z] = '\0'; + if (path[i] == '.'){ + isFile = TRUE; + i++; + uint8_t j = 0; + while (path[i] != ' '){ + request.ext[j] = path[i]; + i++; + j++; } + } else { + request.ext[0] = '\0'; + request.ext[1] = '\0'; + request.ext[2] = '\0'; } - j = i+1; + // mv file.txt - if (!isFolder){ + uint8_t k = 0; + char newName[8] = {0}; + char newExt[3] = {0}; + if (path[i] != '/'){ + // rename - while ((path[j] != ' ') && (j-i-1 < 3)){ - request.ext[j-i-1] = path[j]; - j++; - } - - if (j-i-1 == 3 && path[j] != '\0' && path[j] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-i-1 < 3){ - for (int z = j-i-1; z < 3; z++){ - request.ext[z] = '\0'; - } + i++; + uint8_t a = 0; + while (path[i] != '\0' && path[i] != '.' && a < 8){ + newName[a] = path[i]; + i++; + a++; } - } - // saat ini dah didapat mv file/folder - int m; - for (m = 1; m < 64; m++){ - if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ - // File ditemukan - request.buffer_size = state_driver.dir_table_buf.table[m].filesize; - fileFound = TRUE; - location = state_driver.dir_table_buf.table[m].cluster_high << 16 | state_driver.dir_table_buf.table[m].cluster_low; - syscall(8, (uint32_t) &state_driver2.dir_table_buf, location, 1); - break; - } + for (uint8_t z = a; z < 8; z++){ + newName[z] = '\0'; } - } - uint8_t adder = 0; - char target_name[8]; - char target_ext[3]; - - if (path[j] == '/'){ - // TODO pindah direktori - - if (memcmp(path + j + 1, "..", 2) == 0){ - // pindah ke parent - if (current_directory_cluster == 0){ - // Error karena sudah di root - return; - } - target_location = state_driver.dir_table_buf.table[0].cluster_high << 16 | state_driver.dir_table_buf.table[0].cluster_low; - adder = 4; - } else { - // pindah ke child - for (int z = 0; z < 8; z++){ - target_name[z] = '\0'; - } - for (int z = 0; z < 3; z++){ - target_ext[z] = '\0'; - } - uint8_t k = j+1; - uint8_t l = 0; - while ((path[k] != ' ') && (k-j-2 < 8) && (path[k] != '\0') && (path[k] != '.')){ - target_name[l] = path[k]; + if (isFile){ + i++; + k = 0; + while (path[i] != '\0'){ + newExt[k] = path[i]; + i++; k++; - l++; - adder++; - } - - if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ - // Error karena nama file terlalu panjang - return; } - for (uint8_t z = l; z < 8; z++){ - target_name[z] = '\0'; + for (uint8_t z = k; z < 3; z++){ + newExt[k] = '\0'; } - - adder++; - - for (m = 1; m < 64; m++){ - if (state_driver2.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ - if (memcmp(state_driver.dir_table_buf.table[m].name, target_name, 8) == 0 && - memcmp(state_driver.dir_table_buf.table[m].ext, target_ext, 3) == 0){ - // File ditemukan - target_location = state_driver2.dir_table_buf.table[m].cluster_high << 16 | state_driver2.dir_table_buf.table[m].cluster_low; - break; - } + } else { + newExt[0] = '\0'; + newExt[1] = '\0'; + newExt[2] = '\0'; + } + + int m; + uint32_t location; + for (m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, request.ext, 3) == 0){ + // File ditemukan + request.buffer_size = state_driver.dir_table_buf.table[m].filesize; + // syscall(3, (uint32_t) &request, (uint32_t) &deleted, 0); + location = state_driver.dir_table_buf.table[m].cluster_high << 16 | state_driver.dir_table_buf.table[m].cluster_low; + syscall(8, (uint32_t) &state_driver2.dir_table_buf, location, 1); + + memcpy(state_driver.dir_table_buf.table[m].name, newName, 8); + memcpy(state_driver.dir_table_buf.table[m].ext, newExt, 3); + + memcpy(state_driver2.dir_table_buf.table[0].name, newName, 8); + memcpy(state_driver2.dir_table_buf.table[0].ext, newExt, 3); + + syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); + break; } } } + } - - else { - target_location = current_directory_cluster; - } - - uint8_t k = isFolder ? j : j+1; - k += adder; - uint8_t l = 0; - - if (path[k] == '\0' || path[k] == ' '){ - // Error karena nama file tidak boleh kosong - return; - } - - while ((path[k] != ' ') && (k-j-1-adder < 8) && (path[k] != '\0') && (path[k] != '.')){ - new_name[l] = path[k]; - k++; - l++; - } - - if (l == 8 && path[k] != '\0' && path[k] != ' ' && path[k] != '.'){ - // Error karena nama file terlalu panjang - return; - } - - for (uint8_t z = l; z < 8; z++){ - new_name[z] = '\0'; - } - - if (isFolder){ - for (int z = 0; z < 3; z++){ - new_ext[z] = '\0'; - } - } else { - j = k+1; - while ((path[j] != ' ') && (j-k-1 < 3)){ - new_ext[j-k-1] = path[j]; - j++; - } - - if (j-k-1 == 3 && path[j] != '\0' && path[j] != ' '){ - // Error karena extensi terlalu panjang - return; - } - - if (j-k-1 == 0){ - // do nothing extensi tidak berubah - } else if (j-k-1 < 3){ - for (int z = j-k-1; z < 3; z++){ - new_ext[z] = '\0'; - } - } - } - - if (fileFound){ - memcpy(state_driver.dir_table_buf.table[m].name, new_name, 8); - memcpy(state_driver.dir_table_buf.table[m].ext, new_ext, 3); - memcpy(state_driver2.dir_table_buf.table[0].name, new_name, 8); - memcpy(state_driver2.dir_table_buf.table[0].ext, new_ext, 3); - // write_clusters(&state_driver.dir_table_buf, current_directory_cluster, 1); - syscall(13, (uint32_t) &state_driver.dir_table_buf, target_location, 1); - syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); - } - - - - } int main(void) { From abd583d0819e40c8133e403f615d0216006384a2 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 22:53:55 +0700 Subject: [PATCH 174/176] update mv, now can step down --- src/external/user-shell.c | 72 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 8b9da00..9c64a77 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -768,7 +768,7 @@ void command_call_mv(char *path){ uint8_t k = 0; char newName[8] = {0}; char newExt[3] = {0}; - if (path[i] != '/'){ + if (path[i+1] != '/'){ // rename i++; @@ -828,6 +828,76 @@ void command_call_mv(char *path){ } } + + else { + // change dir + int temp = current_directory_cluster; + // char newPath[8] = {0}; + if (path[i+1] == '.' && path[i+2] == '.' && path[i+3] == '/'){ + command_call_cd(".."); + current_directory_cluster = temp; + + } + + else { + uint8_t kk = 0; + char newPath[8] = {0}; + i+=2; + while (path[i] != '\0'){ + newPath[kk] = path[i]; + i++; + kk++; + } + int m; + uint32_t location; + uint32_t selfLocation; + for (m = 1; m < 64; m++){ + if (state_driver.dir_table_buf.table[m].user_attribute == UATTR_NOT_EMPTY){ + if (memcmp(state_driver.dir_table_buf.table[m].name, newPath, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[m].ext, "\0\0\0", 3) == 0){ + for (int n = 1; n < 64; n++){ + if (memcmp(state_driver.dir_table_buf.table[n].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[n].ext, request.ext, 3) == 0){ + // Folder ketemu + request.buffer_size = state_driver.dir_table_buf.table[n].filesize; + // syscall(3, (uint32_t) &request, (uint32_t) &deleted, 0); + location = state_driver.dir_table_buf.table[m].cluster_high << 16 | state_driver.dir_table_buf.table[m].cluster_low; + selfLocation = state_driver.dir_table_buf.table[n].cluster_high << 16 | state_driver.dir_table_buf.table[n].cluster_low; + request.parent_cluster_number = location; + + syscall(8, (uint32_t) &state_driver2.dir_table_buf, location, 1); + + // syscall(2, (uint32_t) &request, 0, 0); + for (int o = 1; o < 64; o++){ + if (state_driver2.dir_table_buf.table[o].user_attribute != UATTR_NOT_EMPTY){ + memcpy(state_driver2.dir_table_buf.table[o].name, request.name, 8); + memcpy(state_driver2.dir_table_buf.table[o].ext, request.ext, 3); + state_driver2.dir_table_buf.table[o].filesize = request.buffer_size; + state_driver2.dir_table_buf.table[o].attribute = 0; + state_driver2.dir_table_buf.table[o].user_attribute = UATTR_NOT_EMPTY; + state_driver2.dir_table_buf.table[o].cluster_high = 0; + state_driver2.dir_table_buf.table[o].cluster_low = selfLocation; + syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); + break; + } + } + + memcpy(state_driver.dir_table_buf.table[n].name, "\0\0\0\0\0\0\0\0", 8); + memcpy(state_driver.dir_table_buf.table[n].ext, "\0\0\0", 3); + state_driver.dir_table_buf.table[n].filesize = 0; + state_driver.dir_table_buf.table[n].attribute = 0; + state_driver.dir_table_buf.table[n].user_attribute = 0; + state_driver.dir_table_buf.table[n].cluster_high = 0; + state_driver.dir_table_buf.table[n].cluster_low = 0; + syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + break; + } + } + } + } + } + } + } } int main(void) { From 971181d69f24741fb1af8f18f3c533e616aeecc5 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 23:22:32 +0700 Subject: [PATCH 175/176] update mv and fixed the bug --- src/external/user-shell.c | 48 ++++++++++++++++++++++++++++++++++++--- src/kernel.c | 8 +++---- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 9c64a77..80211a6 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -831,11 +831,53 @@ void command_call_mv(char *path){ else { // change dir - int temp = current_directory_cluster; + char temporal[8]; + memcpy(temporal, state_driver.dir_table_buf.table[0].name, 8); + // int temp = current_directory_cluster; // char newPath[8] = {0}; - if (path[i+1] == '.' && path[i+2] == '.' && path[i+3] == '/'){ + if (path[i+2] == '.' && path[i+3] == '.'){ + uint32_t location; + uint32_t selfLocation; + for (int n = 1; n < 64; n++){ + if (memcmp(state_driver.dir_table_buf.table[n].name, request.name, 8) == 0 && + memcmp(state_driver.dir_table_buf.table[n].ext, request.ext, 3) == 0){ + // Folder ketemu + request.buffer_size = state_driver.dir_table_buf.table[n].filesize; + // syscall(3, (uint32_t) &request, (uint32_t) &deleted, 0); + selfLocation = state_driver.dir_table_buf.table[n].cluster_high << 16 | state_driver.dir_table_buf.table[n].cluster_low; + memcpy(state_driver.dir_table_buf.table[n].name, "\0\0\0\0\0\0\0\0", 8); + memcpy(state_driver.dir_table_buf.table[n].ext, "\0\0\0", 3); + state_driver.dir_table_buf.table[n].filesize = 0; + state_driver.dir_table_buf.table[n].attribute = 0; + state_driver.dir_table_buf.table[n].user_attribute = 0; + state_driver.dir_table_buf.table[n].cluster_high = 0; + state_driver.dir_table_buf.table[n].cluster_low = 0; + syscall(13, (uint32_t) &state_driver.dir_table_buf, current_directory_cluster, 1); + + break; + + } + } command_call_cd(".."); - current_directory_cluster = temp; + syscall(8, (uint32_t) &state_driver2.dir_table_buf, current_directory_cluster, 1); + location = state_driver2.dir_table_buf.table[0].cluster_high << 16 | state_driver2.dir_table_buf.table[0].cluster_low; + + for (int o = 1; o < 64; o++){ + if (state_driver2.dir_table_buf.table[o].user_attribute != UATTR_NOT_EMPTY){ + memcpy(state_driver2.dir_table_buf.table[o].name, request.name, 8); + memcpy(state_driver2.dir_table_buf.table[o].ext, request.ext, 3); + state_driver2.dir_table_buf.table[o].filesize = request.buffer_size; + state_driver2.dir_table_buf.table[o].attribute = 0; + state_driver2.dir_table_buf.table[o].user_attribute = UATTR_NOT_EMPTY; + state_driver2.dir_table_buf.table[o].cluster_high = 0; + state_driver2.dir_table_buf.table[o].cluster_low = selfLocation; + syscall(13, (uint32_t) &state_driver2.dir_table_buf, location, 1); + break; + } + } + + + command_call_cd(temporal); } diff --git a/src/kernel.c b/src/kernel.c index e8cc935..9144f75 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -44,7 +44,7 @@ void kernel_setup(void) { memcpy(requester.name + 4, "FFAA", 4); requester.name[0] = 'c'; - requester.parent_cluster_number = 9; + requester.parent_cluster_number = 10; write(requester); requester.buffer_size = 0x14; @@ -54,13 +54,13 @@ void kernel_setup(void) { for (uint32_t i = 0; i < 15; i++){ if (i == 4){ memcpy(requester.name + 4, "L\0\0\0", 4); - requester.parent_cluster_number = 9; + requester.parent_cluster_number = 10; } else if (i == 8){ memcpy(requester.name + 4, "Du\0\0", 4); - requester.parent_cluster_number = 10; + requester.parent_cluster_number = 11; } else if (i == 12){ memcpy(requester.name + 4, "HALO", 4); - requester.parent_cluster_number = 11; + requester.parent_cluster_number = 12; } requester.name[0]++; write(requester); From 89cdd883a20e65d5c883438502c208f299d20098 Mon Sep 17 00:00:00 2001 From: Hidayatullah Wildan Ghaly Buchary <13521015@std.stei.itb.ac.id> Date: Sat, 29 Apr 2023 23:51:07 +0700 Subject: [PATCH 176/176] feat: add clls --- src/external/user-shell.c | 10 +++++++--- src/interrupt.c | 11 ++++++++++- src/keyboard.c | 4 ++++ src/lib-header/keyboard.h | 2 ++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/external/user-shell.c b/src/external/user-shell.c index 80211a6..bd444fb 100644 --- a/src/external/user-shell.c +++ b/src/external/user-shell.c @@ -92,9 +92,9 @@ char* dirStackConverter(struct CURRENT_DIR_STACK *dir){ */ uint8_t getCommandInput(char *input, uint8_t len){ char *command[] = {"cd ", "ls -a", "mkdir ", "cat ", "cp ", "rm ", "mv ", "whereis ", - "ls -ff", "ls -F", "ls -f", "ls"}; - uint8_t command_len[] = {3, 5, 6, 4, 3, 3, 3, 8, 6, 5, 5, 2}; - for (uint8_t i = 0; i < 12; i++){ + "ls -ff", "ls -F", "ls -f", "ls", "cls"}; + uint8_t command_len[] = {3, 5, 6, 4, 3, 3, 3, 8, 6, 5, 5, 2, 3}; + for (uint8_t i = 0; i < 13; i++){ if (len >= command_len[i] && memcmp(input, command[i], command_len[i]) == 0){ return i; } @@ -1022,6 +1022,10 @@ int main(void) { // ls command_call_ls(0); break; + case 12: + // cls + row_shell = 0; + syscall(17, (uint32_t) buf, (uint32_t) cwdpath, (uint32_t) row_shell); default: // command not found // framebuffer_write(0, 79, 'x', 0x0f, 0); diff --git a/src/interrupt.c b/src/interrupt.c index 8ca9221..d149b7c 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -64,7 +64,8 @@ void pic_remap(void) { // __attribute__((unused)) struct CPURegister cpu, // uint32_t int_number, // __attribute__((unused)) struct InterruptStack info -// ) { +// ) {e_driver2 merupakan MILIK file/folder yang ingin diubah + // switch (int_number) { // case PAGE_FAULT: @@ -250,6 +251,14 @@ void syscall(struct CPURegister cpu, __attribute__((unused)) struct InterruptSta else if (cpu.eax == 16) { init_dir_stack((struct DIR_STACK *) cpu.ebx); } + + // Syscall clear screen + else if (cpu.eax == 17) { + setRow(0); + framebuffer_clear(); + template((uint32_t) cpu.edx, (char *) cpu.ecx); + clear_keyboard_buffer(); + } } diff --git a/src/keyboard.c b/src/keyboard.c index 8d3a376..f6f1add 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -75,6 +75,10 @@ void addRow(int n){ row += n; } +void setRow(int n){ + row = n; +} + bool altF4(){ return altFour; } diff --git a/src/lib-header/keyboard.h b/src/lib-header/keyboard.h index 316c81b..0d89186 100644 --- a/src/lib-header/keyboard.h +++ b/src/lib-header/keyboard.h @@ -83,6 +83,8 @@ void keyboard_isr(void); */ void addRow(int row); +void setRow(int row); + void setCol(uint8_t cols); #endif \ No newline at end of file