From 0c93eeb5bdb79d9c47ca81cb715fabc2c93bee03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hord=C3=A9?= Date: Mon, 2 Apr 2007 12:52:01 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20premi=C3=A8re=20version=20C/C++=20de=20?= =?UTF-8?q?COS2000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Graphisme/logo.png | Bin 0 -> 65941 bytes LICENSE.md | 167 +++++ README.md | 60 ++ boot/boot12.asm | 274 ++++++++ boot/boot16.asm | 270 ++++++++ boot/bootcp.asm | 88 +++ boot/boottest.asm | 217 ++++++ boot/echs.h | 10 + boot/makefile | 24 + include/asm.h | 23 + include/string.h | 3 + include/types.h | 11 + include/vga.h | 10 + install/iflop/iflop.asm | 375 +++++++++++ install/iflop/makefile | 16 + install/makefile | 19 + install/mbrol/echs.h | 10 + install/mbrol/loader.asm | 897 +++++++++++++++++++++++++ install/mbrol/makefile | 17 + install/mbrol/mbr.asm | 214 ++++++ install/mbrol/mbrol.asm | 1343 +++++++++++++++++++++++++++++++++++++ install/mbrol/partition.h | 10 + lib/8x8fnt.c | 130 ++++ lib/makefile | 17 + lib/modes.c | 118 ++++ lib/string.c | 11 + lib/vgatxt.c | 88 +++ makefile | 29 + system/loader.asm | 227 +++++++ system/makefile | 31 + system/system.asm | 5 + system/system.c | 8 + 32 files changed, 4722 insertions(+) create mode 100644 Graphisme/logo.png create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 boot/boot12.asm create mode 100644 boot/boot16.asm create mode 100644 boot/bootcp.asm create mode 100644 boot/boottest.asm create mode 100644 boot/echs.h create mode 100644 boot/makefile create mode 100644 include/asm.h create mode 100644 include/string.h create mode 100644 include/types.h create mode 100644 include/vga.h create mode 100644 install/iflop/iflop.asm create mode 100644 install/iflop/makefile create mode 100644 install/makefile create mode 100644 install/mbrol/echs.h create mode 100644 install/mbrol/loader.asm create mode 100644 install/mbrol/makefile create mode 100644 install/mbrol/mbr.asm create mode 100644 install/mbrol/mbrol.asm create mode 100644 install/mbrol/partition.h create mode 100644 lib/8x8fnt.c create mode 100644 lib/makefile create mode 100644 lib/modes.c create mode 100644 lib/string.c create mode 100644 lib/vgatxt.c create mode 100644 makefile create mode 100644 system/loader.asm create mode 100644 system/makefile create mode 100644 system/system.asm create mode 100644 system/system.c diff --git a/Graphisme/logo.png b/Graphisme/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..029ae7cd265c7e4976ce54745c85e70137ae026b GIT binary patch literal 65941 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 W5f~jyt_OE>;l84V!dE#n|NjDa1d+i2 literal 0 HcmV?d00001 diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7e5358d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,167 @@ +## GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + +![logo](https://www.gnu.org/graphics/lgplv3-with-text-154x68.png) + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README.md b/README.md new file mode 100644 index 0000000..33b9b4f --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +![logo](https://github.com/dahut87/cos2000v2/raw/master/Graphisme/logo.png) + +## Présentation du projet + +### Qu'est ce que COS2000 ? + +COS2000 est un système d'exploitation minimaliste qui vise essentiellement un objectif pédagogique. +Il s'agit avant tout du travail d'un passionné de programmation système. + +Le système est développé essentiellement en langage C mais il comporte aussi un peu d'assembleur X86. + +#### Qu'est ce qu'un système d'exploitation ? + +Il s'agit du logiciel principal qui anime votre ordinateur. Il a pour fonctions principales : + +* Piloter des périphériques tels que souris, clavier, écran, imprimante...etc; +* Gérer des fichiers qui sont produit et exploités par des applications; +* Coordonner l'accès aux ressources par plusieurs utilisateurs; +* Détection et récupération des dysfonctionnements; +* Surveiller les performances et assurer une gestion optimale des ressources systèmes. + +Sans système d'exploitation votre ordinateur est inopérant: c'est une boite vide ! + +#### Comment utiliser COS2000 ? + +COS2000 n'a pas pour but d'être utilisé en production. Il s'agit d'un système en cours de +développement que vous pouvez néanmoins tester sur un ordinateur physique ou de préférence sur une machine virtuelle. +Il est nécessaire de compiler le système avant de démarrer celui-ci à partir d'un périphérique amovible (clé usb). + +#### Sur quel ordinateur fonctionne t'il ? + +COS2000 est compatible avec tout ordinateur compatible PC comprenant un processeur avec FPU intégré, +gestion de la mémoire paginée et mode protégé : Intel Pentium et supérieur. + +#### Ai-je le droit de le copier, de le modifier, de le réutiliser, de le vendre ? + +COS2000 est sous licence LGPL v3.0, en simplifiant un peu : + +* COPIER - OUI +* MODIFIER - OUI +* REUTILISER - OUI en citant l'auteur +* VENDRE - NON + +Les détails se trouvent dans le fichier `LICENSE.md` + +![logo](https://www.gnu.org/graphics/lgplv3-with-text-154x68.png) + +### En savoir plus... + +#### Historique du projet +* Version 2.2fr - C en mode protégé Reprise du projet +* Version 2.1fr - C en mode protégé Abandon du projet +* Version 2.0 - C en mode protégé VGA text+pmode +* Version 1.x - Assembleur en mode réel + +> “La connaissance s'acquiert par l'expérience, +> tout le reste n'est que de l'information.. +> +> ― Albert Einstein +> ― Mathématicien, Physicien \ No newline at end of file diff --git a/boot/boot12.asm b/boot/boot12.asm new file mode 100644 index 0000000..6a68b40 --- /dev/null +++ b/boot/boot12.asm @@ -0,0 +1,274 @@ +[BITS 16] +[ORG 0x7C00] + +section .text + +start: + jmp near Boot + +Disk_ID db "COS2000A" ;Fabricant + n° de série Formatage +Sectors_Size dw 512 ;Nombre d'octets/secteur +Sectors_Per_Cluster db 1 ;Nombre de secteurs/cluster +Reserved_Sectors dw 1 ;Nombre de secteurs réservé +Fats_Number db 2 ;Nombre de copies de la FAT +Fits_Number dw 224 ;Taille du répertoire racine +Sectors_Per_Disk dw 2880 ;Nombre secteurs du volume si < 32 Mo +Media_Descriptor db 0xF0 ;Descripteur de média +Sectors_Per_Fat dw 9 ;Nombre secteurs/FAT +Sectors_Per_Track dw 18 ;Nombre secteurs/piste +Heads_Number dw 2 ;Nombre de tete de lecture/écriture +Sectors_Hidden dd 0 ;Nombre de secteurs cachés +Sectors_Per_Disk2 dd 0 ;Nombre secteurs du volume si > 32 Mo +Boot_Drive db 0 ;Lecteur de démarrage +Reserved db 0 ;NA (pour NT seulement) +Extended_Boot_ID db 0x29 ;Signature Boot étendu 29h +Serial_Number dd 0x01020304 ;N° de série +Disk_Name db "COS2000 " ;Nom de volume +Fat_Type db "FAT12 " ;Type de système de fichiers + +;Cpu_Message db "CPU test",0 +Boot_Message db "Booting ",0 +Finding_Message db "System ",0 +Loading_Message db "Loading ",0 +System_File db "SYSTEM SYS" +Is_Ok db "[ OK ]",0x0A,0x0D,0 +Is_Failed db "[Failed]",0x0A,0x0D,"Press a key",0x0A,0x0D,0 +The_Dot db '.',0 + +Boot_Error: + mov si,Is_Failed + call ShowString + mov ah,0 + int 0x16 + int 0x19 + +Boot_Ok: + mov al,[Stage] + cmp al,0 + jz No_Ok + mov si,Is_Ok + call ShowString +No_Ok: + xor ah,ah + mov si,ax + add si,Boot_Message ;Cpu_Message + call ShowString + add byte [Stage],0x09 + ret + +Stage db 0 + +Boot: + push cs + push cs + pop es + pop ds + mov [Boot_Drive],dl + cli + mov ax,0x9000 + mov ss,ax + mov sp,0xFFFF + sti +; call Detect_Cpu +; jc Boot_Error + call Boot_Ok + xor ax,ax + int 0x13 + jc Boot_Error + mov cx,[Reserved_Sectors] + add cx,[Sectors_Hidden] + adc cx,[Sectors_Hidden+2] + mov di,Fat_Buffer + call ReadSector + jc Boot_Error + xor ax,ax + mov al,[Fats_Number] + mov bx,[Sectors_Per_Fat] + mul bx + add cx,ax + mov ax,32 + mul word [Fits_Number] + div word [Sectors_Size] + add ax,cx + sub ax,2 + mov word [Serial_Number],ax + xor dx,dx + call Boot_Ok +Find_System: + mov di,Buffer + call ReadSector + jc Near Boot_Error + xor bx,bx +Next_Root_Entrie: + cmp byte [di],0 + je near Boot_Error + push di + push cx + mov si,System_File + mov cx,11 + rep cmpsb + pop cx + pop di + je System_Found + add di,32 + add bx,32 + inc dx + cmp dx,[Fits_Number] + ja near Boot_Error + cmp bx,[Sectors_Size] + jb Next_Root_Entrie + inc cx + jmp Find_System +System_Found: + mov cx,[di+26] + mov ax,0x0071 + mov es,ax + push es + mov di,0x100 + push di + call Boot_Ok + mov si,The_Dot +Resume_Loading: + cmp cx,0x0FF0 + jae Finish_Loading + push cx + add cx,word [Serial_Number] + call ReadSector + pop cx + jc near Boot_Error + call ShowString + add di,[Sectors_Size] + call NextFatGroup + jc near Boot_Error + jmp Resume_Loading +Finish_Loading: + call Boot_Ok + retf + +;====================READSECTOR======================= +;Lit le secteur logique LBA CX et le met en es:di +;-> CX (limité à 65536 secteurs, soit 32 Mo avec secteur 512 octets) +;<- Flag Carry si erreur +;===================================================== +ReadSector: + pusha + mov ax,cx + xor dx,dx + div word [Sectors_Per_Track] + inc dl + mov bl,dl + xor dx,dx + div word [Heads_Number] + mov dh, [Boot_Drive] + xchg dl,dh + mov cx,ax + xchg cl,ch + shl cl,6 + or cl, bl + mov bx,di + mov si, 4 + mov al, 1 +Read_Again: + mov ah, 2 + int 0x13 + jnc Read_Done + dec si + jnz Read_Again +Read_Done: + popa + ret + +;===================NEXTFATGROUP====================== +;Renvoie en CX le groupe qui succède dans la FAT le groupe CX +;-> CX +;<- +;===================================================== +NextFatGroup: + push bx + push dx + push di + mov ax,cx + mov bx,ax + and bx,0000000000000001b + shr ax,1 + mov cx,3 + mul cx + mov di,Fat_Buffer + add di,ax + cmp bx,0 + jnz Even_Group +Odd_Group: + mov dx,[di] + and dx,0x0FFF + mov cx,dx + jmp Next_Group_Found +Even_Group: + mov dx,[di+1] + and dx,0xFFF0 + shr dx,4 + mov cx,dx +Next_Group_Found: + pop di + pop dx + pop bx + ret + +;======================SHOWSTR======================== +;Affiche la chaine de caractère pointé par ds:si à l'écran +;-> DS, SI +;<- Flag Carry si erreur +;===================================================== +ShowString: + pusha +Next_Char: + lodsb + or al,al + jz End_Show + mov ah,0x0E + mov bx,0x07 + int 0x10 + jmp Next_Char +End_Show: + popa + ret + +;======================DETECTCPU====================== +;Detecte si le processeur est un 386 au mini +;-> +;<- Flag Carry si erreur +;===================================================== +;Detect_Cpu: +; push ax ; test if 8088/8086 is present (flag bits 12-15 will be set) +; xor ah,ah ; ah = 0 +; push ax ; copy ax into the flags +; popf ; with bits 12-15 clear +; pushf ; Read flags back into ax +; pop ax +; and ah,0xF0 ; check if bits 12-15 are set +; cmp ah,0xF0 +; je No_386 ; no 386 detected (8088/8086 present) +; ; check for a 286 (bits 12-15 are clear) +; mov ah,0xF0 ; set bits 12-15 +; push ax ; copy ax onto the flags +; popf +; pushf ; copy the flags into ax +; pop ax +; and ah,0xF0 ; check if bits 12-15 are clear +; jz No_386 ; no 386 detected (80286 present) +; clc +; ret +;No_386: +; stc +; ret + +times 510-($-$$) db ' ' + +dw 0xAA55 + +Buffer equ $ +Fat_Buffer equ $+512 + +section .bss + +;Buffer resb 512 +;Fat_Buffer resb 10000 \ No newline at end of file diff --git a/boot/boot16.asm b/boot/boot16.asm new file mode 100644 index 0000000..813f14c --- /dev/null +++ b/boot/boot16.asm @@ -0,0 +1,270 @@ +[BITS 16] +[ORG 0x7C00] + +section .text + +start: + jmp near Boot + +Disk_ID db "COS2000A" ;Fabricant + n° de série Formatage +Sectors_Size dw 512 ;Nombre d'octets/secteur +Sectors_Per_Cluster db 4 ;Nombre de secteurs/cluster +Reserved_Sectors dw 1 ;Nombre de secteurs réservé +Fats_Number db 2 ;Nombre de copies de la FAT +Fits_Number dw 512 ;Taille du répertoire racine +Sectors_Per_Disk dw 2880 ;Nombre secteurs du volume si < 32 Mo +Media_Descriptor db 0xF8 ;Descripteur de média +Sectors_Per_Fat dw 207 ;Nombre secteurs/FAT +Sectors_Per_Track dw 18 ;Nombre secteurs/piste +Heads_Number dw 38 ;Nombre de tete de lecture/écriture +Sectors_Hidden dd 16 ;Nombre de secteurs cachés +Sectors_Per_Disk2 dd 39 ;Nombre secteurs du volume si > 32 Mo +Boot_Drive db 0x80 ;Lecteur de démarrage +Reserved db 0 ;NA (pour NT seulement) +Extended_Boot_ID db 0x29 ;Signature Boot étendu 29h +Serial_Number dd 0x01020304 ;N° de série +Disk_Name db "COS2000 " ;Nom de volume +Fat_Type db "FAT16 " ;Type de système de fichiers + +;Cpu_Message db "CPU test",0 +;Boot_Message db "Booting ",0 +;Finding_Message db "System ",0 +;Loading_Message db "Loading ",0 +System_File db "SYSTEM SYS" +Is_Ok db "[ OK ]",0x0A,0x0D,0 +Is_Failed db "[Failed]",0x0A,0x0D,"Press a key",0x0A,0x0D,0 +The_Dot db '.',0 + +Boot_Error: + mov si,Is_Failed + call ShowString + mov ah,0 + int 0x16 + int 0x19 + +Boot_Ok: +; mov al,[Stage] +; cmp al,0 +; jz No_Ok + mov si,Is_Ok + call ShowString +;No_Ok: +; xor ah,ah +; mov si,ax +; add si,Boot_Message ;Cpu_Message +; call ShowString +; add byte [Stage],0x09 + ret +; +;Stage db 0 + +Boot: + push cs + push cs + pop es + pop ds + mov [Boot_Drive],dl + cli + mov ax,0x9000 + mov ss,ax + mov sp,0xFFFF + sti +; call Detect_Cpu +; jc Boot_Error +; call Boot_Ok + xor ax,ax + int 0x13 +; jc Boot_Error + xor eax,eax + add ax,[Reserved_Sectors] + add ecx,eax + mov di,Fat_Buffer + call ReadSector + jc Boot_Error + xor eax,eax + mov al,[Fats_Number] + mov bx,[Sectors_Per_Fat] + mul bx + add ecx,eax + mov ax,32 + mul word [Fits_Number] + div word [Sectors_Size] + add eax,ecx + mov dword [Serial_Number],eax + xor dx,dx +; call Boot_Ok +Find_System: + mov di,Buffer + call ReadSector + jc near Boot_Error + xor bx,bx +Next_Root_Entrie: + cmp byte [di],0 + je near Boot_Error + push di + push cx + mov si,System_File + mov cx,11 + rep cmpsb + pop cx + pop di + je System_Found + add di,32 + add bx,32 + inc dx + cmp dx,[Fits_Number] + ja near Boot_Error + cmp bx,[Sectors_Size] + jb Next_Root_Entrie + inc ecx + jmp Find_System +System_Found: + xor ecx,ecx + mov cx,[di+26] + mov ax,0x0071 + mov es,ax + push es + mov di,0x100 + push di +; call Boot_Ok + mov si,The_Dot +Resume_Loading: + cmp cx,0x0FFF0 + jae Finish_Loading + call ReadGroup + jc near Boot_Error + call ShowString + mov bx,cx + shl bx,1 + mov cx,[bx+Fat_Buffer] + jmp Resume_Loading +Finish_Loading: + call Boot_Ok + retf + +;====================READSECTOR======================= +;Lit le secteur logique LBA ECX et le met en es:di +;-> ECX (limité à 2^32 secteurs, soit 2 To avec secteur 512 octets) +;<- Flag Carry si erreur +;===================================================== +ReadSector: + pushad + mov ax, cx + ror ecx,16 + mov dx,cx + rol ecx,16 + cmp ecx,4128705 + ja Extended_CHS + div word [Sectors_Per_Track] + inc dl + mov bl, dl + xor dx,dx + div word [Heads_Number] + mov dh, [Boot_Drive] + xchg dl, dh + mov cx, ax + xchg cl, ch + shl cl, 6 + or cl, bl + mov bx, di + mov si, 4 + mov al, 1 +Read_Again: + mov ah, 2 + int 0x13 + jnc Read_Done + dec si + jnz Read_Again +Read_Done: + popad + ret +Extended_CHS: + mov si,ECHS_Block + mov byte [si+Sizes],0x10 + mov byte [si+Reserve],0x01 + mov byte [si+NumSectors],0x01 + mov [si+Adressseg],es + mov [si+Adressoff],di + mov [si+SectorLow],ax + mov [si+SectorHigh],dx + mov di,4 + mov dl,[Boot_Drive] +Read_AgainX: + mov ah, 42h + int 13h + jnc Read_Done + dec di + jnz Read_AgainX + +;======================READGROUP====================== +;lit le groupe cx en es:di et incr‚mente DI +;-> cx, es:di +;<- di, Flag Carry si erreur +;===================================================== +ReadGroup: + push ax + push cx + push dx + mov al,[Sectors_Per_Cluster] + sub cx,2 + xor ah,ah + mul cx + mov cx,dx + shl ecx,16 + mov cx,ax + add ecx,dword [Serial_Number] + mov al,[Sectors_Per_Cluster] +read: + call ReadSector + jc errors + inc ecx + add di,[Sectors_Size] + dec al + jnz read + clc +errors: + pop dx + pop cx + pop ax + ret + +;======================SHOWSTR======================== +;Affiche la chaine de caractère pointé par ds:si à l'écran +;-> DS, SI +;<- Flag Carry si erreur +;===================================================== +ShowString: + ;push ax + ;push bx + ;push si + pusha +Next_Char: + lodsb + or al,al + jz End_Show + mov ah,0x0E + mov bx,0x07 + int 0x10 + jmp Next_Char +End_Show: + ;pop si + ;pop bx + ;pop ax + popa + ret + +times 510-($-$$) db ' ' + +dw 0xAA55 + +ECHS_Block equ $ +Buffer equ $+26 +Fat_Buffer equ $+26+512 + +section .bss + +%include "echs.h" + +;ECHS_Block resb 24 +;Buffer resb 512 +;Fat_Buffer resb 10000 \ No newline at end of file diff --git a/boot/bootcp.asm b/boot/bootcp.asm new file mode 100644 index 0000000..6a32fa9 --- /dev/null +++ b/boot/bootcp.asm @@ -0,0 +1,88 @@ +[BITS 16] +[ORG 0x100] + +section .text + +start: + mov ah,09 + mov dx,msg + int 0x21 + cmp byte [0x80],2 + jne near error + mov ax,0x3D02 + mov dx,name + int 0x21 + jc near error + mov bx,ax + mov ax,0x4202 + xor cx,cx + xor dx,dx + int 0x21 + jc error + cmp dx,0 + jne error + cmp ax,512 + jne error + mov ax,0x4200 + xor cx,cx + xor dx,dx + int 0x21 + jc error + mov ah,0x3F + mov cx,512 + mov dx,buffer2 + int 0x21 + jc error + cmp word [buffer2+510],0xAA55 + jne error + mov al,[0x82] + cmp al,'z' + ja error + cmp al,'a' + jb verif + sub al,'a'-'A' +verif: + cmp al,'Z' + ja error + cmp al,'A' + jb error + sub al,'A' + mov bp,ax + mov [segs],cs + mov cx,0xFFFF + mov bx,packet + int 0x25 + pop ax + mov si,buffer+3 + mov di,buffer2+3 + mov cx,59 + rep movsb + mov ax,bp + mov word [offs],buffer2 + mov cx,0xFFFF + mov bx,packet + int 0x26 + pop ax + jc error + mov ah,09 + mov dx,msgok + int 0x21 + ret + +error: + mov ah,09 + mov dx,msgerror + int 0x21 + ret + + +packet dd 0 + dw 1 +offs dw buffer +segs dw 0 +name db "boot.bin",0 +msg db 0x0D,0x0A,"CopyBoot V1.0 by nico",0x0D,0x0A,"Copyright 2002",0x0D,0x0A,'$' +msgok db "Installation of bootsector realized",0x0D,0x0A,'$' +msgerror db "Installation of bootsector failed",0x0D,0x0A,'$' +buffer equ $ +buffer2 equ $+512 \ No newline at end of file diff --git a/boot/boottest.asm b/boot/boottest.asm new file mode 100644 index 0000000..3e61ceb --- /dev/null +++ b/boot/boottest.asm @@ -0,0 +1,217 @@ +[BITS 16] +[ORG 0x7C00] + +section .text + +start: + jmp near boot + +Disk_ID db "COS2000A" ;Fabricant + n° de série Formatage +Sectors_Size dw 512 ;Nombre d"octets/secteur +Sectors_Per_Cluster db 1 ;Nombre de secteurs/cluster +Reserved_Sectors dw 1 ;Nombre de secteurs réservé +Fats_Number db 2 ;Nombre de copies de la FAT +Fits_Number dw 224 ;Taille du répertoire racine +Sectors_Per_Disk dw 2880 ;Nombre secteurs du volume si < 32 Mo +Media_Descriptor db 0xF0 ;Descripteur de média +Sectors_Per_Fat dw 9 ;Nombre secteurs/FAT +Sectors_Per_Track dw 18 ;Nombre secteurs/piste +Heads_Number dw 2 ;Nombre de tete de lecture/écriture +Sectors_Hidden dd 0 ;Nombre de secteurs cachés +Sectors_Per_Disk2 dd 0 ;Nombre secteurs du volume si > 32 Mo +Boot_Drive db 0 ;Lecteur de démarrage +Reserved db 0 ;NA (pour NT seulement) +Extended_Boot_ID db 0x29 ;Signature Boot étendu 29h +Serial_Number dd 0x01020304 ;N° de série +Disk_Name db "COS2000 " ;Nom de volume +Fat_Type db "FAT12 " ;Type de système de fichiers + +Loading_Ok db "Secteur en execution",0x0A,0x0D,0 +Reg_Names db "cs ",0 + db "ds ",0 + db "es ",0 + db "fs ",0 + db "gs ",0 + db "ss ",0 + db "eax",0 + db "ebx",0 + db "ecx",0 + db "edx",0 + db "esi",0 + db "edi",0 + db "esp",0 + db "ebp",0 + db "eip",0 + db "FLG",0 + db "cr0",0 + db "cr1",0 + db "cr2",0 + db "cr3",0 + +Return db 0x0A,0x0D,0 + +Numbers equ 20 + +boot: + mov [cs:segms],cs + mov [cs:segms+4],ds + mov [cs:segms+8],es + mov [cs:segms+12],fs + mov [cs:segms+16],gs + mov [cs:segms+20],ss + mov [cs:segms+24],eax + mov [cs:segms+28],ebx + mov [cs:segms+32],ecx + mov [cs:segms+36],edx + mov [cs:segms+40],esi + mov [cs:segms+44],edi + mov [cs:segms+48],esp + mov [cs:segms+52],ebp +IP: + mov word [cs:segms+56],IP + mov word [cs:segms+58],0 + pushfd + pop dword [cs:segms+60] + mov eax,cr0 + mov [cs:segms+64],eax + mov eax,cr0 + mov [cs:segms+68],eax + mov eax,cr2 + mov [cs:segms+72],eax + mov eax,cr3 + mov [cs:segms+76],eax + cli + mov ax,0x9000 + mov ss,ax + mov sp,0xFFFF + sti + push cs + push cs + pop es + pop ds + mov si,Loading_Ok + call ShowString + xor bx,bx +Show_All_Regs: + mov si,Reg_Names + shl bx,2 + add si,bx + call ShowString + mov al,":" + call ShowChar + mov si,segms + mov edx,[bx+si] + shr bx,2 + mov cx,32 + cmp bx,6 + jae Reg_Size_32 + mov cx,16 +Reg_Size_32: + call ShowHex + mov si,Return + call ShowString + inc bx + cmp bx,Numbers + jb Show_All_Regs +Halting_Cpu: + jmp Halting_Cpu + +;==================SHOWHEX================== +;Affiche un nombre hexadécimal EDX de taille CX aprés le curseur +;-> EDX un entier, CX la taille +;<- +;=========================================== +ShowHex: + push ax + push bx + push cx + push edx + mov ax,cx + shr ax,2 + sub cx,32 + neg cx + shl edx,cl + xchg ax,cx +Hex_Decompose: + rol edx,4 + mov bx,dx + and bx,0x0F + mov al,[cs:bx+Hex_Table] + call ShowChar + dec cl + jnz Hex_Decompose + pop edx + pop cx + pop bx + pop ax + ret +Hex_Table db "0123456789ABCDEF" + +;===================CLS==================== +;Efface l"écran +;-> +;<- +;========================================== +Cls: + push ax + mov ax,0x0003 + int 0x10 + pop ax + ret + +;================SHOWCHAR================== +;Affiche un caractère pointé dans AL +;-> AL +;<- +;========================================== +ShowChar: + push ax + push bx + mov ah,0x0E + mov bx,0x07 + int 0x10 + pop bx + pop ax + ret + +;===================SHOWSTR================ +;Affiche une chaine de caractère pointé par SI +;-> SI pointe une chaine +;<- +;========================================== +ShowString: + push ax + push bx + push si + cld +Show_Next_Char: + lodsb + or al,al + jz String_Showed + call ShowChar + jmp Show_Next_Char +String_Showed: + pop si + pop bx + pop ax + ret + +;=================WAITKEY================= +;Attend l"appuie d"une touche et +;renvoie en AL la touche appuyée +;-> +;<- AL +;========================================= +WaitKey: + mov ax,0x00 + int 0x16 + ret + +times 510-($-$$) db ' ' + +dw 0xAA55 + +section .bss + +segms resb 10000 + diff --git a/boot/echs.h b/boot/echs.h new file mode 100644 index 0000000..fc1bba9 --- /dev/null +++ b/boot/echs.h @@ -0,0 +1,10 @@ +struc echs +Sizes resb 1 +Reserve resb 1 +NumSectors resw 1 +Adressoff resw 1 +Adressseg resw 1 +SectorLow resw 1 +SectorHigh resw 1 +Dummy resq 1 +endstuc diff --git a/boot/makefile b/boot/makefile new file mode 100644 index 0000000..10cbc4f --- /dev/null +++ b/boot/makefile @@ -0,0 +1,24 @@ +all: makall + +makall: boot12.bin boot16.bin boottest.bin bootcp.com + sync + +boot12.bin: + nasm -f bin -o boot12.bin boot12.asm + +boot16.bin: + nasm -f bin -o boot16.bin boot16.asm + +boottest.bin: + nasm -f bin -o boottest.bin boottest.asm + +bootcp.com: + nasm -f bin -o bootcp.com bootcp.asm + +clean: + rm -f *.o + rm -f *.bin + rm -f *.sys + rm -f *.com + + diff --git a/include/asm.h b/include/asm.h new file mode 100644 index 0000000..cc8ccf7 --- /dev/null +++ b/include/asm.h @@ -0,0 +1,23 @@ +#include "types.h" +#define sti() __asm__ ("sti"::) +#define cli() __asm__ ("cli"::) +#define nop() __asm__ ("nop"::) +#define iret() __asm__ ("iret"::) + +#define outb(port,value) \ + asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value)); + +#define outw(port,value) \ + asm volatile ("outb %%ax,%%dx"::"d" (port), "a" (value)); + +#define inb(port) ({ \ + u8 _v; \ + asm volatile ("inb %%dx,%%al" : "=a" (_v) : "d" (port)); \ + _v; \ +}) + +#define inw(port) ({ \ + u16 _v; \ + asm volatile ("inw %%dx,%%ax" : "=a" (_v) : "d"(port)); \ + _v; \ +}) \ No newline at end of file diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..ec199fb --- /dev/null +++ b/include/string.h @@ -0,0 +1,3 @@ +#include "types.h" + +void memset(void *dst, u8 val, u16 count,u32 size); diff --git a/include/types.h b/include/types.h new file mode 100644 index 0000000..451dbd8 --- /dev/null +++ b/include/types.h @@ -0,0 +1,11 @@ +#ifndef I386_TYPE +#define I386_TYPE +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned char uchar; +typedef int bool; +#define true 1; +#define false 0; +#endif + diff --git a/include/vga.h b/include/vga.h new file mode 100644 index 0000000..38bfae4 --- /dev/null +++ b/include/vga.h @@ -0,0 +1,10 @@ +#include "types.h" + +#define TEXTSCREEN 0xB8000 /* debut de la memoire video texte*/ +#define GRPHSCREEN 0xA0000 /* debut de la memoire video graphique*/ + +typedef u8 mode_def[64]; + +void print (u8* string); +void cls (void); +u16 setvmode(u8); diff --git a/install/iflop/iflop.asm b/install/iflop/iflop.asm new file mode 100644 index 0000000..d01f2e9 --- /dev/null +++ b/install/iflop/iflop.asm @@ -0,0 +1,375 @@ +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ COS 2000 ³ +;³ http://www.multimania.com/cos2000 ³ +;ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ +;³ D I S K I M A G E ³ +;ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ +;³ Fonction : Programme permettant de r‚aliser des images dique dur d'³ +;³ une disquettes. ³ +;³ ³ +;³ Appel : Diskimge [Nom du fichier][/r][/s][/h] ³ +;³ /r restaure l'image /s sauve l'image /h aide ³ +;³ ³ +;³ Compilation : TASM boot /m4 /x ³ +;³ TLINK boot /t /x ³ +;ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ +;³ Programmeur : Nico ³ +;³ Con‡us le : 15/07/2001 ³ +;³ Modifi‚ le : 15/07/2001 ³ +;³ Site Web : http://www.multimania.com/cos2000 ³ +;³ Copyright : libre distribution ³ +;³ E-Mail : COS2000@multimania.com ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +;==========================Directive d'assemblages============================ +[BITS 16] ;Directive qui autorise la g‚n‚ration de code 16 bits +[ORG 0x100] ;Directive pour indiquer le d‚but du code + +section .text + + +;=============================Debut du programmes============================= + +start: ;Label du d‚but. + mov ah,0x09 + mov dx,msg ; + int 0x21 + mov ah,'r' + call Check + jnc restitute + mov ah,'s' + call Check + jnc save +help: + mov ah,0x09 + mov dx,helpmsg + int 0x21 + mov ax,0 + int 0x16 + ret +restitute: + mov ah,'n' + call Check + jnc nospl + mov ah,0x09 + mov dx,msg2 + int 21h + mov ax,0x00 + int 16h +nospl: + mov ah,0x09 + mov dx,res + int 0x21 + call OpenCmdLine + jc error + mov si,buffer + mov di,si + xor cx,cx +restoring: + call Read18432 + jc error + call WriteTrack ;Ecrit la piste CX sur les 2 tˆtes depuis ds:di + jc error + call ShowDot + inc cx + cmp cx,80 + jb restoring + mov ah,0x09 + mov dx,msgok + int 0x21 + ret +save: + mov ah,'n' + call Check + jnc nospl2 + mov ah,0x09 + mov dx,msg2 + int 0x21 + mov ax,0 + int 0x16 +nospl2: + mov ah,0x09 + mov dx,sav + int 0x21 + call CreateCmdLine + jc error + mov si,buffer + mov di,si + xor cx,cx +saving: + call ReadTrack ;Lit la piste CX sur 2 tˆte en es:di + jc error + call Write18432 + jc error + call ShowDot + inc cx + cmp cx,80 + jb saving + mov ah,09 + mov dx,msgok + int 0x21 + ret +error: + push cs + pop ds + call CloseCmdLine + mov ah,09 + mov dx,errormsg + int 0x21 + ret + +;Affiche un point +ShowDot: + push ax + push bx + push cx + mov bx,cx + shr bx,4 + mov al,[bx+dot] + mov ah,0x0E + mov bx,0x07 + int 0x10 + pop cx + pop bx + pop ax + ret + +;Ecrit une piste CX 2 Tˆte, depuis le buffer DS:SI +ReadTrack: + push ax + push bx + push cx + push dx + push si + push es + push ds + pop es + xchg ch,cl + xor dx,dx + xor cl,cl + inc cl + mov bx,si + mov si,3 +retry: + mov ax,0x0212 + int 13h + jnc done + dec si + jnz retry + jmp dead +done: + add bx,9216 + inc dh + cmp dh,1 + je retry +dead: + pop es + pop si + pop dx + pop cx + pop bx + pop ax + ret + +;Lit une piste CX sur deux tˆte dans le buffer ES:DI +WriteTrack: + push ax + push bx + push cx + push dx + push si + xchg ch,cl + xor dx,dx + xor cl,cl + inc cl + mov bx,di + mov si,3 +retry2: + mov ax,0x0312 + int 0x13 + jnc done2 + dec si + jnz retry2 +done2: + add bx,9216 + inc dh + cmp dh,1 + je retry2 +dead2: + pop si + pop dx + pop cx + pop bx + pop ax + ret + +;Ecrit 18432 octets depuis DS:SI dans le fichier ouvert par OpenCmdline +Write18432: + push ax + push bx + push cx + push dx + mov ah,0x40 + mov cx,18432 + mov bx,[handle] + mov dx,si + int 0x21 + pop dx + pop cx + pop bx + pop ax + ret + +;Lit 18432 octets vers ES:DI depuis le fichier ouvert par OpenCmdline +Read18432: + push ax + push bx + push cx + push dx + mov ah,0x3F + mov cx,18432 + mov bx,[handle] + mov dx,si + int 0x21 + pop dx + pop cx + pop bx + pop ax + ret + +;Ouvre la ligne de commande +OpenCmdLine: + push ax + push bx + push dx + mov bl,[0x80] + xor bh,bh + add bx,0x80 + mov byte [bx],0 + mov ax,0x3D00 + mov dx,0x82 + int 0x21 + mov [handle],ax + pop dx + pop bx + pop ax + ret + +;Cr‚e un fichier du nom de la ligne de commande +CreateCmdLine: + push ax + push bx + push cx + push dx + mov bl,[0x80] + xor bh,bh + add bx,0x80 + mov byte [bx],0 + mov ah,0x3C + xor cx,cx + mov dx,0x82 + int 0x21 + mov [handle],ax + pop dx + pop cx + pop bx + pop ax + ret + +;Ferme le fichier pr‚c‚damment ouvert avec OpenCmdline +CloseCmdLine: + push ax + push bx + mov bx,[handle] + mov ah,0x3E + int 0x21 + pop bx + pop ax + ret + +;Recherche le commutateur AH dans la ligne de commande si existant retourne FC=True. +Check: + push ax + push cx + push di + mov di,0x80 + mov cl,[di] + cmp cl,0 + je notfound2 + xor ch,ch + mov al,'/' +search: + cmp cx,0 + je notfound + repne scasb + cmp [di],ah + jnz search + jmp okfound +notfound: + sub ah,'a'-'A' + mov di,0x80 + mov cl,[di] +search2: + cmp cx,0 + je notfound2 + repne scasb + cmp [di],ah + jnz search2 +okfound: + mov word [di-2],0 + clc + pop di + pop cx + pop ax + ret +notfound2: + stc + pop di + pop cx + pop ax + ret + +res db "Restauration en cours",0x0A,0x0D,0x0A,0x0D,'$' +sav db "Sauvegarde en cours",0x0A,0x0D,0x0A,0x0D,'$' +dot db " °±²Û" +handle dw 0 +msg db 0x0A,0x0D,"IFlop V1.0",0x0A,0x0D + db "Ecrit par Nico",0x0A,0x0D + db "http://www.multimania.com/cos2000",0Ah,0Dh + db "Copyright 2000",0Ah,0Dh,'$' +msg2 db "Ins‚rez une disquette de 1.44 Mo dans le lecteur et appuyez sur une touche...",0x0A,0x0D,'$' +errormsg db 0Ah,0Dh,"Une erreur est apparue lors de la copie !",0x0A,0x0D,'$' +msgok db 0Ah,0Dh,"La copie de l'image a ‚t‚ correctement r‚alis‚e",0x0A,0x0D,'$' + +SectorsPerTrack dw 18 ;Nombre de secteur par pistes. +HeadsPerDrive dw 2 ;Nombre de t‚tes par disque. + +helpmsg: +db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿" +db "³ COS 2000 ³" +db "³ http://www.multimania.com/cos2000 ³" +db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´" +db "³ I F L O P ³" +db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´" +db "³ Fonction : Programme permettant de r‚aliser des images disque dur ³" +db "³ d'une disquettes. ³" +db "³ ³" +db "³ Appel : Iflop [Nom du fichier][/r][/s][/h] ³" +db "³ /r restaure l'image /s sauve l'image /h aide ³" +db "³ ³" +db "³ Compilation : TASM boot /m4 /x ³" +db "³ TLINK boot /t /x ³" +db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´" +db "³ Programmeur : Nico ³" +db "³ Con‡us le : 15/07/2001 ³" +db "³ Modifi‚ le : 15/07/2001 ³" +db "³ Site Web : http://www.multimania.com/cos2000 ³" +db "³ Copyright : libre distribution ³" +db "³ E-Mail : COS2000@multimania.com ³" +db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ$" + +section .bss + +[org 0x5000] + +buffer resb 512 ;Allocation de 512 octets pour contenir le secteur lu. \ No newline at end of file diff --git a/install/iflop/makefile b/install/iflop/makefile new file mode 100644 index 0000000..84d3c6c --- /dev/null +++ b/install/iflop/makefile @@ -0,0 +1,16 @@ +all: makall + +makall: iflop.com + + +iflop.com: + nasm -f bin -o iflop.com iflop.asm + +clean: + rm -f *.o + rm -f *.bin + rm -f *.sys + rm -f *.com + + + diff --git a/install/makefile b/install/makefile new file mode 100644 index 0000000..b1fb2d2 --- /dev/null +++ b/install/makefile @@ -0,0 +1,19 @@ +all: makall + +makall: + sync + +clean: + (cd iflop; make clean) + (cd mbrol; make clean) + +iflop/iflop.com: + (cd iflop; make) + +mbrol/mbrol.com: + (cd mbrol; make) + + + + + diff --git a/install/mbrol/echs.h b/install/mbrol/echs.h new file mode 100644 index 0000000..fc1bba9 --- /dev/null +++ b/install/mbrol/echs.h @@ -0,0 +1,10 @@ +struc echs +Sizes resb 1 +Reserve resb 1 +NumSectors resw 1 +Adressoff resw 1 +Adressseg resw 1 +SectorLow resw 1 +SectorHigh resw 1 +Dummy resq 1 +endstuc diff --git a/install/mbrol/loader.asm b/install/mbrol/loader.asm new file mode 100644 index 0000000..de1af90 --- /dev/null +++ b/install/mbrol/loader.asm @@ -0,0 +1,897 @@ +[BITS 16] +[ORG 0x0100] + +section .text + +start: + push eax + push ebx + push edi + push ebp + mov di, disk + call detectdisk + call cls + mov si,di + mov di, thepart + call getdriveinfos + mov [numbers],cx + mov si,di + call showdriveinfos + mov al,3 + call selection + mov word [sel],0 +waitafter: + call waitkey + cmp ah,0x50 + jne tre1 + mov ax,[sel] + inc al + cmp ax,[numbers] + jz waitafter + mov [sel],ax + add al,3 + call selection + jmp waitafter +tre1: + cmp ah,0x48 + jne tre2 + mov ax,[sel] + cmp ax,0 + jz waitafter + dec al + mov [sel],ax + add al,3 + call selection + jmp waitafter +tre2: + cmp al,0x0D + jne waitafter + mov bx,[sel] + shl bx,6 + add bx,thepart + mov si,mmp + call showstr + mov si,bx + add si,28 + call showstr + mov bp,[bx+26] + call initdisk + xor ax,ax + mov es,ax + mov ds,ax + mov di,0x0600 + mov ecx,[cs:bx+16] + call readsector + mov di,0x7C00 + mov ecx,[cs:bx+22] + call readsector + mov dx,bp + mov si,[cs:bx+20] + add si,0x0600 + pop ebp + pop edi + pop ebx + pop eax + jmp 0x0000:0x7C00 + +;============================================================================= + +; DONNEES FIXES + +;============================================================================= +mmp db "Chargement du disque ",0 +msg db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄ¿" + db "³ Letter:Name ³ Type ³ Boot ³ Statut ³ Size MByte ³ StartSector ³" + db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄ´",0 +tab db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÙ",0 +sep db " ³ ",0 + +partkind db 001h,"FAT12 ",0 + db 004h,"FAT16 ",0 + db 005h,"Extended ",0 + db 006h,"FAT16B ",0 + db 007h,"IFS ",0 + db 00Bh,"FAT32 ",0 + db 00Ch,"FAT32X ",0 + db 00Eh,"FAT16X ",0 + db 00Fh,"ExtendedX ",0 + db 081h,"Linux 1.4b",0 + db 082h,"Linux SWAP",0 + db 083h,"Linux EXT2",0 + db 011h,"FAT12 Hid ",0 + db 014h,"FAT16 Hid",0 + db 016h,"FAT16B Hid",0 + db 017h,"IFS Hid ",0 + db 01Bh,"FAT32 Hid ",0 + db 01Ch,"FAT32X Hid",0 + db 01Eh,"FAT16X Hid",0 + db 0FFh,"Unknowed ",0 + +noname db "Unknowed ","Unkowned ",0 +unknowed db "Movable ",0 +primary db "Primary ",0 +secondary db "Secondary",0 +yes db "Yes ",0 +no db "No ",0 +mo db " MB",0 + +;============================================================================= + +; ROUTINES PARTICULIERES + +;============================================================================= +;Affiche des infos sur le volume +showdriveinfos: + push ax + push bx + push cx + push edx + push si + mov si, msg + call showstr + mov bx,thepart + mov cx,[numbers] +showall: + mov al,'³' + call showchar + mov al,' ' + call showchar + mov al,[bx+51] + call showchar + mov al,':' + call showchar + mov si,bx + add si,28 + call showstr + mov si, sep + call showstr + mov al,[bx+4] + cmp al,0xFF + je useboot + mov si, partkind+1 +search: + cmp byte[si-1],0x0FF + je notboot + cmp [si-1],al + je notboot + add si,12 + jmp search +useboot: + mov si,bx + add si,40 +notboot: + call showstr + mov si, sep + call showstr + mov si, yes + cmp byte [bx],0x80 + je okboot + mov si, no +okboot: + call showstr + mov si, sep + call showstr + mov si, primary + cmp dword [bx+16],0 + je okprimary + mov si, secondary +okprimary: + cmp byte [bx+4],0x0FF + jne wasno + mov si, unknowed +wasno: + call showstr + mov si, sep + call showstr + mov edx,[bx+12] + shr edx,11 + call showint + mov si, mo + call showstr + mov si, sep + call showstr + mov edx,[bx+22] + call showint + mov al,' ' + call showchar + mov al,'³' + call showchar + add bx,64 + dec cx + jnz near showall + mov si, tab + call showstr + pop si + pop edx + pop cx + pop bx + pop ax + ret + +;met en surlign‚e la ligne al et seulement al +selection: + push cx + mov ch,0x70 + call selectline + xchg al,[cs:old] + mov ch,0x07 + call selectline + pop cx + ret + +old db 20 + +;selectionne la ligne al de couleur ch +selectline: + push ax + push bx + push cx + push ds + mov bh,160 + mul bh + mov bx,ax + mov ax,0xB800 + mov ds,ax + inc bx + mov cl,80 +select: + mov [bx],ch + add bx,2 + dec cl + jnz select + pop ds + pop cx + pop bx + pop ax + ret + +;============================================================================= + +; ROUTINES UNIVERSELLES INSPIREE DE COS2000 + +;============================================================================= + + +;=========GETDRIVEINFOS============== +;Envoie en es:di les lecteurs logiques sur les volumes point‚ par ds:si +;-> BP, ES:DI +;<- CX leur nombre +;==================================== +getdriveinfos: + push ax + push bx + push dx + push si + push di + push bp + push di + xor bx,bx +show: + xor dh,dh + mov dl,[si] + inc si + cmp dl,0xFF + je endofshow + mov bp,dx + call initdisk + call IsMbr + je okmbr + call getvolume + inc bx + add di,64 + jmp show +okmbr: + call getpartitions + mov ax,cx + shl ax,6 + add di,ax + add bx,cx + jmp show +endofshow: + pop si + mov al,'C' + mov cx,bx + push cx + push si +checkp: + cmp byte [si+4],5 + je notprim + cmp byte [si+4],0x0F + je notprim + cmp byte [si+16],0 + jnz notprim + cmp byte [si+26],0x80 + jb notprim + mov [si+51],al + inc al +notprim: + add si,64 + dec cx + jnz checkp + pop si + pop cx + push cx + push si +checkl: + cmp byte [si+4],5 + je notext + cmp byte [si+4],0x0F + je notext + cmp byte [si+16],0x00 + jz notext + cmp byte [si+26],0x80 + jb notext + mov [si+51],al + inc al +notext: + add si,64 + dec cx + jnz checkl + pop si + pop cx + mov al,'A' + push cx + push si +checkn: + cmp byte [si+26],0x80 + jae notlec + mov [si+51],al + inc al +notlec: + add si,64 + dec cx + jnz checkn + pop si + pop cx + mov al,'*' + push cx + push si +checko: + cmp byte [si+4],5 + je ext2 + cmp byte [si+4],0x0F + jne notext2 +ext2: + mov [si+51],al +notext2: + add si,64 + dec cx + jnz checko + pop si + pop cx + pop bp + pop di + pop si + pop dx + pop bx + pop ax + ret + +;=============GETVOLUME============== +;Envoie en es:di les infos disque EBP +;-> BP, ES:DI +;<- +;==================================== +getvolume: + push ax + push ecx + push edx + push di + push di + mov cx,64 + mov al,0 + cld + rep stosb + pop di + mov byte [es:di+4],0xFF + mov ecx,0 + mov [di+26],bp + push di + add di,28 + call getbootinfos + pop di + mov [di+12],edx + pop di + pop edx + pop ecx + pop ax + ret + +;==========GETBOOTINFOS============== +;Envoie en es:di le nom du volume & le FS d'adresse LBA ECX sur disque EBP +;-> BP, ES:DI, ECX +;<- +;==================================== +getbootinfos: + push ax + push cx + push si + push di + push di + push es + push cs + pop es + mov di,buffer + mov si,di + call readsector + pop es + pop di + cmp byte [si+0x13],0 + je more32 + xor edx,edx + mov dx,[si+0x13] + jmp more16 +more32: + mov edx,[si+0x20] +more16: + cmp byte [si+0x42],0x29 + je fat32 + cmp byte [si+0x26],0x29 + je fat16 +unk: + mov si,noname + jmp rel +fat32: + add si,0x47 + jmp rel +fat16: + add si,0x2B +rel: + mov cx,11 + cld + rep movsb + mov al,0 + stosb + mov cx,8 + rep movsb + mov ax,' ' + stosw + mov al,0 + stosb + pop di + pop si + pop cx + pop ax + ret + +;==========GETPARTITION============== +;Envoie en es:di la liste des partitions du disque BP +;-> BP, ES:DI +;<- renvoie leur nombre en CX +;==================================== +getpartitions: + push eax + push ebx + push edx + push si + push di + mov ecx,0 + mov word [wheres],0 + mov [theprimary],ecx +againpart: + xor eax,eax + mov ebx,ecx + push di + mov di,partition + CALL readsector + mov si, di + pop di + add si,0x01BE + mov cl,4 +showevery: + cmp dword [si+NumSector],0x00000000 + je nothings + mov edx,[si+StartSector] + cmp byte [si+Kind],0x05 + je is + cmp byte [si+Kind],0x0F + jne isnot +is: + mov eax,[theprimary] + add eax,edx + cmp dword [theprimary],0 + jne nothings +isnot: + push ecx + push di + push si + mov cx,[wheres] + shl cx,6 + add di,cx + mov ecx,16/4 + rep movsd + pop si + mov [di],ebx + mov [di+4],si + sub word [di+4],partition + mov [di+6],ebx + add [di+6],edx + mov ecx,[di+6] + mov [di+10],bp + add di,12 + push edx + call getbootinfos + pop edx + pop di + pop ecx + inc word [wheres] +nothings: + add si,16 + dec cl + jnz showevery + mov ecx,eax + cmp dword [theprimary],0x00000000 + jne noth + mov [theprimary],eax +noth: + cmp ecx,0 + jnz near againpart + mov cx,[wheres] + pop di + pop si + pop edx + pop ebx + pop eax + ret + +;==============ISMBR================= +;Zero si Mbr sur le premier secteur du support BP +;-> BP +;<- +;==================================== +IsMbr: + push ax + push ecx + push di + push es + mov ecx,0 + mov di,buffer + push cs + pop es + call readsector + add di,0x01BE + mov cl,4 +isgood: + mov al,[cs:di] + and al,0x7F + cmp al,0 + jne noMbr + add di,16 + dec cl + jne isgood + cmp word [cs:di],0xAA55 +noMbr: + pop es + pop di + pop ecx + pop ax + ret + +;=============DETECTDISK============= +;Renvoie en ES:DI les disques d‚tect‚s fini par 0FFh +;-> ES:DI +;<- +;==================================== +detectdisk: + push ax + push bx + push cx + push dx + push si + push di + mov si,PossibleDisks +DetectAllDisk: + mov dl,[cs:si] + inc si + cmp dl,0xFF + je EndOfDetection + mov cl,4 +retry: + push cx + mov ax,0x0201 + mov cx,0x0101 + mov dh,0x00 + mov bx,buffer + int 0x13 + pop cx + jnc isdetected + dec cl + jnz retry + jmp DetectAllDisk +isdetected: + mov [es:di],dl + inc di + jmp DetectAllDisk +EndOfDetection: + mov byte [di],0xFF + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret + +PossibleDisks db 0x00,0x01,0x02,0x03,0x04,0x05,0x80,0x81,0x82,0x83,0x84,0x85,0xFF + +;=============INITDISK=============== +;Initialise le p‚riph‚rique BP pour une utilisation ult‚rieure +;-> BP +;<- +;==================================== +initdisk: + push ax + push bx + push cx + push dx + push di + push es + mov dx,bp + mov ah,8 + int 0x13 + and cx,0x3F + mov [cs:sectorspertrack],cx + mov cl,dh + inc cl + mov [cs:headsperdrive],cx + pop es + pop di + pop dx + pop cx + pop bx + pop ax + ret + +;=============READSECTOR=============== +;Lit le secteur ECX du disque BP et le met en es:di +;-> +;<- +;====================================== +readsector: + push ax + push bx + push ecx + push dx + push si + mov ax,bp + mov [cs:temp],al + mov ax, cx + ror ecx, 16 + mov dx, cx + rol ecx,16 + cmp ecx,4128705 + ja extended + div word [cs:sectorspertrack] + inc dl + mov bl, dl + xor dx,dx + div word [cs:headsperdrive] + mov dh, [cs:temp] + xchg dl, dh + mov cx, ax + xchg cl, ch + shl cl, 6 + or cl, bl + mov bx, di + mov si, 4 + mov al, 1 +TryAgain: + mov ah, 2 + int 0x13 + jnc Done + dec si + jnz TryAgain +Done: + pop si + pop dx + pop ecx + pop bx + pop ax + ret +extended: + push di + push ds + push cs + pop ds + mov si,block + mov byte [si+Sizes],0x10 + mov byte [si+Reserve],0x01 + mov word [si+NumSectors],0x0001 + mov [si+Adressseg],es + mov [si+Adressoff],di + mov [si+SectorLow],ax + mov [si+SectorHigh],dx + mov di,4 + mov dl,[temp] +TryAgainX: + mov ah, 0x42 + int 0x13 + jnc DoneX + dec di + jnz TryAgainX +DoneX: + pop ds + pop di + pop si + pop dx + pop ecx + pop bx + pop ax + ret + +headsperdrive dw 16 +sectorspertrack dw 38 +block times 24 db 0 +temp db 0 + +;============CLS============== +;Efface l'‚cran +;-> +;<- +;============================= +cls: + push ax + mov ax,0x0003 + int 0x10 + pop ax + ret + +;==========SHOWSTR============ +;Affiche une chaine de caractŠre point‚ par SI +;-> SI pointe une chaine +;<- +;============================= +showstr: + push ax + push bx + push si + cld +again: + lodsb + or al,al + jz fin + call showchar + jmp again +fin: + pop si + pop bx + pop ax + ret + +;==========SHOWPASSTR============ +;Affiche une chaine de caractŠre point‚ par SI +;-> SI pointe une chaine +;<- +;============================= +showpasstr: + push ax + push bx + push cx + push si + mov cl,[si] + inc si + cld +again2: + lodsb + call showchar + dec cl + jnz again2 +fin2: + pop si + pop cx + pop bx + pop ax + ret + +;==========WAITKEY============= +;Attend l'appuie d'une toouche et +;renvoie en AL la touche appuyer +;-> +;<- AL +;============================== +waitkey: + mov ax,0 + int 0x16 + ret + +;==========SHOWCHAR============ +;Affiche un caractŠre point‚ dans AL +;-> AL +;<- +;============================== +showchar: + push ax + push bx + mov ah,0x0E + mov bx,0x07 + int 0x10 + pop bx + pop ax + ret + +;==========SHOWINT============ +;Affiche un entier EDX apr‚s le curseur +;-> EDX un entier +;<- +;============================= +showint: + push eax + push bx + push cx + push edx + push esi + push di + push ds + push es + + push cs + push cs + pop ds + pop es + mov cx,10 + mov di, showbuffer + mov al,' ' + cld + rep stosb + xor cx,cx + mov eax, edx + mov esi, 10 + mov bx,di + mov byte [cs:di+1],0 +decint: + xor edx,edx + div esi + add dl,'0' + inc cx + mov [cs:bx],dl + dec bx + cmp ax, 0 + jne decint +showinteger: + mov si, showbuffer + call showstr + pop es + pop ds + pop di + pop esi + pop edx + pop cx + pop bx + pop eax + ret + +;============================================================================= + +; VARIABLES INITIALISEE + +;============================================================================= + +sel dw 0 +wheres dw 0 +numbers dw 0 + +;============================================================================= + +; VARIABLES NON INITIALISEE + +;============================================================================= + +theprimary equ $ +showbuffer equ $+1 +disk equ $+1+12 +partition equ $+1+12+26 +buffer equ $+1+12+26+512 +thepart equ $+1+12+26+512+512 + +section .bss + +%include "partition.h" +%include "echs.h" + +;theprimary resd 1 +;showbuffer resb 12 +;disk resb 26 +;partition resb 512 +;buffer resb 512 +;thepart resb 10000 + diff --git a/install/mbrol/makefile b/install/mbrol/makefile new file mode 100644 index 0000000..21ce4c0 --- /dev/null +++ b/install/mbrol/makefile @@ -0,0 +1,17 @@ +all: makall + +makall: mbrol.com + +mbrol.com: + nasm -f bin -o mbr.bin mbr.asm + nasm -f bin -o loader.bin loader.asm + sync + nasm -f bin -o mbrol.com mbrol.asm + +clean: + rm -f *.o + rm -f *.bin + rm -f *.sys + rm -f *.com + + diff --git a/install/mbrol/mbr.asm b/install/mbrol/mbr.asm new file mode 100644 index 0000000..ef31b01 --- /dev/null +++ b/install/mbrol/mbr.asm @@ -0,0 +1,214 @@ +[BITS 16] +[ORG 0x7C00] + +start: + jmp short falsereal ;vers debut programme + db "MBROL" ;Signature MBROL +falsereal: + cli ;inhibation interruptions + xor ax,ax + mov ss,ax ;Reloge pile en 0000h:9000h + mov sp,0x9000 + push ax + pop ds ;DS=0000h + add ah,0x10 + push ax + pop es ;ES=1000h + sti ;Reactivation des interruptions + cld + mov [sitemp],si ;sauvegarde si (adresse partition active) + mov di,0x7C00 + mov si,di + mov cx,512/4 + rep movsd ;On reloge le programme en 1000h:7C00h + push es + pop ds ;DS=1000h + jmp 0x1000:RealStart + +RealStart: + xor dh,dh + mov bp,dx ;R‚cupŠre en BP le nølecteur de d‚marrage + call initdisk ;Initialisation du p‚riph‚rique + ;call cls ;Efface l'‚cran + mov si, msg + call showstr ;Affiche le splatch de boot + call getkey ;R‚cupŠre la touche press‚ par l'utilisateur + cmp al,' ' ;touche = espace + jne normal ;si autre touche on démarre normalement + mov si, msgmbrol + call showstr ;Message de chargement de Cos loader + xor ecx,ecx + inc ecx + mov di,0x0100 +readload: + inc ecx + call readsector ;Charge le secteur LBA ecx en es:di + add di,512 + cmp ecx,7 + jb readload ;Charge les secteurs LBA 2 … 6 en 1000h:0100h + + jmp 0x1000:0x0100 ;Execute Cos loader + ;saut FAR vers 1000h:0100h + +normal: + mov si,msgnorm + call showstr ;Affiche le d‚marrage normal + mov ecx,1 + xor ax,ax + mov es,ax + mov ds,ax + mov di,0x7C00 ;Charge le secteur LBA 1 en 0000h:7C00h + call readsector ;qui est le MBR d'origine sauvegard‚ par MBROL + mov dx,bp ;Renvoie dans DL le lecteur de d‚marrage + mov si,[sitemp] ;restaure si (adresse de la partition) + jmp 0x0000:0x7C00 ;Une op‚ration normalement r‚alis‚e par le BIOS + ;Saut vers le MBR en 0000h:7C00h + +temp db 0 +sitemp dw 0 +HeadsPerDrive dw 16 +SectorsPerTrack dw 38 +msg db "Cos2000 MBROL V1.0",0x0A,0x0D,"Press [SPACE] to execute Cos Loader",0x0A,0x0D,0 +point db '.',0 +msgmbrol db "Cos Loader is loading",0 +msgnorm db "Booting...",0 + +;=============INITDISK=============== +;Initialise le p‚riph‚rique BP pour une utilisation ult‚rieure +;-> BP +;<- +;==================================== +initdisk: + push ax + push bx + push cx + push dx + push di + push es + mov dx,bp + mov ah,8 + int 0x13 + and cx,111111b + mov [cs:SectorsPerTrack],cx + mov cl,dh + inc cl + mov [cs:HeadsPerDrive],cx + pop es + pop di + pop dx + pop cx + pop bx + pop ax + ret + +;=============READSECTOR (Fonction 01H)=============== +;Lit le secteur ECX du disque BP et le met en es:di +;-> AH=1 +;<- Flag Carry si erreur +;===================================================== +readsector: + push ax + push bx + push ecx + push dx + push si + mov ax,bp + mov [cs:temp],al + mov ax, cx + ror ecx, 16 + mov dx, cx + rol ecx,16 + div word [cs: SectorsPerTrack] + inc dl + mov bl, dl + xor dx,dx + div word [cs: HeadsPerDrive] + mov dh, [cs:temp] + xchg dl, dh + mov cx, ax + xchg cl, ch + shl cl, 6 + or cl, bl + mov bx, di + mov si, 4 + mov al, 1 +TryAgain: + mov ah, 2 + int 13h + push si + mov si,point + call showstr + pop si + jnc Done + dec si + jnz TryAgain +Done: + pop si + pop dx + pop ecx + pop bx + pop ax + ret + +;============CLS============== +;Efface l'‚cran +;-> +;<- +;============================= +cls: + push ax + mov ax,0x0003 + int 0x10 + pop ax + ret + +;==========SHOWSTR============ +;Affiche une chaine de caractŠre point‚ par SI +;-> SI pointe une chaine +;<- +;============================= +showstr: + push ax + push bx + push si +again: + lodsb + or al,al + jz fin + CALL showchar + jmp again +fin: + pop si + pop bx + pop ax + ret + +;===========GETKEY============= +;N'Attend l'appuie d'une touche et +;renvoie en AL la touche appuyer +;-> +;<- AL +;============================== +getkey: + mov ah,0x01 + int 0x16 + ret + +;==========SHOWCHAR============ +;Affiche un caractŠre point‚ dans AL +;-> AL +;<- +;============================== +showchar: + push ax + push bx + mov ah,0x0E + mov bx,0x07 + int 0x10 + pop bx + pop ax + ret + +times 510-($-$$) db 0 + + dw 0xAA55 \ No newline at end of file diff --git a/install/mbrol/mbrol.asm b/install/mbrol/mbrol.asm new file mode 100644 index 0000000..8cec9bd --- /dev/null +++ b/install/mbrol/mbrol.asm @@ -0,0 +1,1343 @@ +[BITS 16] +[ORG 0x0100] + +section .text + +start: + mov di,disk + call detectdisk + mov si,di + mov di,thedrive + call getalldriveinfos + mov [numbers],cx + mov al,3 + mov word [sel],0 +main: + call cls + mov si,thedrive + call showalldriveinfos + call selection +waitafter: + call waitkey + call lower + cmp ah,0x50 + jne tre1 + mov ax,[sel] + inc al + cmp ax,[numbers] + jz waitafter + mov [sel],ax + add al,3 + call selection + jmp waitafter +tre1: + cmp ah,0x48 + jne tre2 + mov ax,[sel] + cmp ax,0 + jz waitafter + dec al + mov [sel],ax + add al,3 + call selection + jmp waitafter +tre2: + cmp al,0x0D + jne tre3 + mov bx,[sel] + shl bx,4 + add bx,thedrive + mov bp,[bx] + call initdisk + mov di,thepart + call IsMbr + je okmbr2 + call getvolume + mov cx,1 + jmp nombr2 +okmbr2: + call getpartitions +nombr2: + call cls + mov si,di + call showdriveinfos + call waitkey + call lower + mov al,[cs:old] + jmp main +tre3: + cmp al,'i' + jne tre4 + mov bx,[sel] + shl bx,4 + add bx,thedrive + mov bp,[bx] + call initdisk + mov al,[cs:old] + cmp byte [bx+1],1 + je noerase + mov si,erasing + call showstr + call choice + jnz near main +noerase: + cmp byte [bx+2],1 + jne noreinst + mov si,remplacing + call showstr + call choice + jnz near main +noreinst: + cmp byte [bx+3],0 + jne nolbas + cmp dword [bx+4],8300 + jb nolbas + mov si,nowereLBA + call showstr + call choice + jnz near main +nolbas: + mov si,really + call showstr + call choice + jnz near main + call install + mov si,installed + call showstr + mov si,disk + mov di,thedrive + call getalldriveinfos + push ax + call waitkey + pop ax + jmp main +tre4: + cmp al,0x1B + jne tre5 + call cls + ret +tre5: + cmp al,'u' + jne tre6 + mov bx,[sel] + shl bx,4 + add bx,thedrive + mov bp,[bx] + mov al,[cs:old] + cmp byte [bx+2],1 + je letsgo + mov si,noinst + call showstr + push ax + call waitkey + pop ax + jmp main +letsgo: + mov si,uninst + call showstr + call choice + jnz near main + call uninstall + mov si,uninstalled + call showstr + mov si,disk + mov di,thedrive + call getalldriveinfos + push ax + call waitkey + pop ax + jmp main +tre6: + cmp al,'r' + jne near waitafter + call reboot + +;============================================================================= + +; DONNEES FIXES + +;============================================================================= +msg2 db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄ¿" + db "³ Volume ³ Type ³ Installed ³ LBA ³ Size MByte ³ Partitions ³" + db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄ´",0 +tab2 db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÙ" + db "[ENTER] informations [ESC] quit [R] reboot [I] install MBROL [U] uninstall MBROL",0 +noinst db 0x0A,0x0D,"MBROL is not yet installed, press a key...",0 +really db 0x0A,0x0D,"Do you really want to install MBROL ?",0 +erasing db 0x0A,0x0D,"Mbrol need a partionned disk, on this disk data will be erased, do it ?",0 +remplacing db 0x0A,0x0D,"Mbrol is already installed, do you want to replace old installation ?",0 +nowereLBA db 0x0A,0x0D,"BIOS or this drive don''t support LBA and it necessite LBA adressing, install ?",0 +installed db 0x0A,0x0D,"MBROL is installed, press a key to continue...",0 +uninstalled db 0x0A,0x0D,"MBROL is uninstalled, press a key to continue...",0 +uninst db 0x0A,0x0D,"Do you really want to uninstall MBROL ?",0 +processing db 0x0A,0x0D,"Processing",0 + +floppy db "Floppy Disk",0 +hard db "Hard Disk",0 +boot db " Boot ",0 +mbr db " Mbr ",0 +yes1 db " Yes ",0 +no1 db " No ",0 +yes2 db " Yes ",0 +no2 db " No ",0 +choiced db 0x0A,0x0D,"[y/n]:",0 + +msg db "ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄ¿" + db "³ Name ³ Type ³ Boot ³ Statut ³ Size MByte ³ StartSector ³" + db "ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄ´",0 +tab db "ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÙ" + db "Press any key to close...",0 +sep db " ³ ",0 + +partkind db 0x01,"FAT12 ",0 + db 0x04,"FAT16 ",0 + db 0x05,"Extended ",0 + db 0x06,"FAT16B ",0 + db 0x07,"IFS ",0 + db 0x0B,"FAT32 ",0 + db 0x0C,"FAT32X ",0 + db 0x0E,"FAT16X ",0 + db 0x0F,"ExtendedX ",0 + db 0x81,"Linux 1.4b",0 + db 0x82,"Linux SWAP",0 + db 0x83,"Linux EXT2",0 + db 0x11,"FAT12 Hid ",0 + db 0x14,"FAT16 Hid",0 + db 0x16,"FAT16B Hid",0 + db 0x17,"IFS Hid ",0 + db 0x1B,"FAT32 Hid ",0 + db 0x1C,"FAT32X Hid",0 + db 0x1E,"FAT16X Hid",0 + db 0xFF,"Unknowed ",0 + +noname db "Unknowed ","Unkowned ",0 +unknowed db "Movable ",0 +primary db "Primary ",0 +secondary db "Secondary",0 +yes db "Yes ",0 +no db "No ",0 +mo db " MB",0 + +;============================================================================= + +; ROUTINES PARTICULIERES + +;============================================================================= +;converti al en lowercase +lower: + cmp al,'A' + jb noupper + cmp al,'Z' + ja noupper + add al,'a'-'A' +noupper: + ret + +;redemarrage … chaud +reboot: + mov ax,0x40 + mov ds,ax + mov bx,0x1234 + mov [ds:0x0072],bx + jmp 0xFFFF:0x0000 + +;Dialogue qui demande si Yes or No et Renvoie zero si YES et +choice: + push ax + push si + mov si,choiced + call showstr +waiter: + call waitkey + call lower + cmp al,'y' + je iyes + cmp al,'n' + je ino + jmp waiter +iyes: + call showchar + cmp al,al + jmp endof +ino: + call showchar + cmp al,' ' + jmp endof +endof: + pop si + pop ax + ret + +;install MBROL sur le disque BP +install: + push ax + push ecx + push si + push di + mov si,processing + call showstr + call initdisk + mov ecx,0 + mov di,buffer + call readsector + inc ecx + mov si,di + cmp dword [di+2],"MBRO" + je nosave + call writesector +nosave: + add si,0x01BE + mov di,prog+0x01BE + mov cx,16*4/4 + cld + rep movsd + mov ecx,0 + mov si,prog + call writesector + inc ecx +copying: + inc ecx + add si,512 + call writesector + mov al,'.' + call showchar + cmp ecx,7 + jb copying + pop di + pop si + pop ecx + pop ax + ret + +;desinstalle MBROL sur le disque BP +uninstall: + push ecx + push si + push di + call initdisk + mov ecx,1 + mov di,buffer + call readsector + dec ecx + mov si,di + call writesector + pop di + pop si + pop ecx + ret + +;Affiche des infos sur le volume +showalldriveinfos: + push ax + push bx + push cx + push edx + push si + mov si,msg2 + call showstr + mov bx,thedrive + mov cx,[numbers] +showall: + mov al,'³' + call showchar + mov al,' ' + call showchar + mov al,[bx] + mov si,floppy + cmp al,0x80 + jb disks + mov si,hard +disks: + call showstr + and al,0xF + push ax + mov al,' ' + call showchar + mov al,'0' + call showchar + pop ax + add al,'0' + call showchar + mov si,sep + call showstr + mov si,boot + cmp byte [bx+1],1 + jne booter + mov si,mbr +booter: + call showstr + mov si,sep + call showstr + mov si,no1 + cmp byte [bx+2],1 + jne noinsts + mov si,yes1 +noinsts: + call showstr + mov si,sep + call showstr + mov si,no2 + cmp byte [bx+3],1 + jne lbas + mov si,yes2 +lbas: + call showstr + mov si,sep + call showstr + mov edx,[bx+4] + call showint + mov si,mo + call showstr + mov si,sep + call showstr + mov dx,[bx+8] + call showint + mov al,' ' + call showchar + mov al,'³' + call showchar + add bx,16 + dec cx + jnz near showall + mov si,tab2 + call showstr + pop di + pop edx + pop cx + pop bx + pop ax + ret + +;renvoie en ES:DI les infos sur les disques DS:SI et Nb dans CX +getalldriveinfos: + push ax + push bx + push dx + push si + push di + push bp + xor bx,bx + xor cx,cx +show2: + xor dh,dh + mov dl,[si] + inc si + cmp dl,0xFF + je endofshow2 + inc cx + mov bp,dx + call initdisk + mov [es:di],dl + call IsMbr + sete [es:di+1] + call IsInstalled + sete [es:di+2] + call IsLBA + setnc [es:di+3] + push cx + call getcapacity + mov [es:di+4],ecx + mov cx,1 + cmp byte [si-1],0x80 + jb noone + push es + push di + push cs + pop es + mov di,dummys + call getpartitions + pop di + pop es +noone: + mov [es:di+8],cx + add di,16 + pop cx + jmp show2 +endofshow2: + pop bp + pop di + pop si + pop dx + pop bx + pop ax + ret + +;===========ISInstalled============== +;Zero si Mbr sur le premier secteur du support BP +;-> BP +;<- +;==================================== +IsInstalled: + push ax + push ecx + push di + push es + mov ecx,0 + mov di,buffer + push cs + pop es + call readsector + cmp dword [di+2],"MBRO" + pop es + pop di + pop ecx + pop ax + ret + +;Affiche des infos sur le volume +showdriveinfos: + push ax + push bx + push cx + push edx + push si + mov si,msg + call showstr + mov bx,thepart +showall2: + mov al,'³' + call showchar + mov al,' ' + call showchar + mov al,'-' + call showchar + mov al,'>' + call showchar + mov si,bx + add si,28 + call showstr + mov si,sep + call showstr + mov al,[bx+4] + cmp al,0xFF + je useboot + mov si,partkind+1 +search: + cmp byte [si-1],0xFF + je notboot + cmp [si-1],al + je notboot + add si,12 + jmp search +useboot: + mov si,bx + add si,40 +notboot: + call showstr + mov si,sep + call showstr + mov si,yes + cmp byte [bx],0x80 + je okboot + mov si,no +okboot: + call showstr + mov si,sep + call showstr + mov si,primary + cmp dword [bx+16],0 + je okprimary + mov si,secondary +okprimary: + cmp byte [bx+4],0xFF + jne wasno + mov si,unknowed +wasno: + call showstr + mov si,sep + call showstr + mov edx,[bx+12] + shr edx,11 + call showint + mov si,mo + call showstr + mov si,sep + call showstr + mov edx,[bx+22] + call showint + mov al,' ' + call showchar + mov al,'³' + call showchar + add bx,64 + dec cx + jnz near showall2 + mov si,tab + call showstr + pop si + pop edx + pop cx + pop bx + pop ax + ret + +;met en surlign‚e la ligne al et seulement al +selection: + push cx + mov ch,0x70 + call selectline + xchg al,[cs:old] + cmp al,[cs:old] + je nochange + mov ch,0x07 + call selectline +nochange: + pop cx + ret + +old db 20 + +;selectionne la ligne al de couleur ch +selectline: + push ax + push bx + push cx + push ds + mov bh,160 + mul bh + mov bx,ax + mov ax,0xb800 + mov ds,ax + inc bx + mov cl,80 +select: + mov [bx],ch + add bx,2 + dec cl + jnz select + pop ds + pop cx + pop bx + pop ax + ret + +;============================================================================= + +; ROUTINES UNIVERSELLES INSPIREE DE COS2000 + +;============================================================================= + +;============Getcapacity============= +;Renvoie la capacit‚ du disque Bp dans ECX +;-> BP +;<- +;==================================== +getcapacity: + mov ecx,0 + ret + +;===============IsLBA================ +;Renvoie zero = 1 si LBA +;-> BP +;<- +;==================================== +IsLBA: + push ax + push bx + push cx + push dx + mov dx,bp + mov ah,0x41 + mov bx,0x55AA + int 0x13 + pop dx + pop cx + pop bx + pop ax + ret + +;=========GETDRIVEINFOS============== +;Envoie en es:di les lecteurs logiques sur les volumes point‚ par ds:si +;-> BP, ES:DI +;<- CX leur nombre +;==================================== +getdriveinfos: + push ax + push bx + push dx + push si + push di + push bp + push di + xor bx,bx +show: + xor dh,dh + mov dl,[si] + inc si + cmp dl,0xFF + je endofshow + mov bp,dx + call initdisk + call IsMbr + je okmbr + call getvolume + inc bx + add di,64 + jmp show +okmbr: + call getpartitions + mov ax,cx + shl ax,6 + add di,ax + add bx,cx + jmp show +endofshow: + pop si + mov al,'C' + mov cx,bx + push cx + push si +checkp: + cmp byte [si+4],5 + je notprim + cmp byte [si+4],0x0F + je notprim + cmp byte [si+16],0 + jnz notprim + cmp byte [si+26],0x80 + jb notprim + mov [si+51],al + inc al +notprim: + add si,64 + dec cx + jnz checkp + pop si + pop cx + push cx + push si +checkl: + cmp byte [si+4],5 + je notext + cmp byte [si+4],0x0F + je notext + cmp byte [si+16],0x00 + jz notext + cmp byte [si+26],0x80 + jb notext + mov [si+51],al + inc al +notext: + add si,64 + dec cx + jnz checkl + pop si + pop cx + mov al,'A' + push cx + push si +checkn: + cmp byte [si+26],0x80 + jae notlec + mov [si+51],al + inc al +notlec: + add si,64 + dec cx + jnz checkn + pop si + pop cx + mov al,'*' + push cx + push si +checko: + cmp byte [si+4],5 + je ext2 + cmp byte [si+4],0x0F + jne notext2 +ext2: + mov [si+51],al +notext2: + add si,64 + dec cx + jnz checko + pop si + pop cx + pop bp + pop di + pop si + pop dx + pop bx + pop ax + ret + +;=============GETVOLUME============== +;Envoie en es:di les infos disque EBP +;-> BP, ES:DI +;<- +;==================================== +getvolume: + push ax + push ecx + push edx + push di + push di + mov cx,64 + mov al,0 + cld + rep stosb + pop di + mov byte [es:di+4],0xFF + mov ecx,0 + mov [di+26],bp + push di + add di,28 + call getbootinfos + pop di + mov [di+12],edx + pop di + pop edx + pop ecx + pop ax + ret + +;==========GETBOOTINFOS============== +;Envoie en es:di le nom du volume & le FS d'adresse LBA ECX sur disque EBP +;-> BP, ES:DI, ECX +;<- +;==================================== +getbootinfos: + push ax + push cx + push si + push di + push di + push es + push cs + pop es + mov di,buffer + mov si,di + call readsector + pop es + pop di + cmp byte [si+0x13],0 + je more32 + xor edx,edx + mov dx,[si+0x13] + jmp more16 +more32: + mov edx,[si+0x20] +more16: + cmp byte [si+0x42],0x29 + je fat32 + cmp byte [si+0x26],0x29 + je fat16 +unk: + mov si,noname + jmp rel +fat32: + add si,0x47 + jmp rel +fat16: + add si,0x2B +rel: + mov cx,11 + cld + rep movsb + mov al,0 + stosb + mov cx,8 + rep movsb + mov ax,' ' + stosw + mov al,0 + stosb + pop di + pop si + pop cx + pop ax + ret + +;==========GETPARTITION============== +;Envoie en es:di la liste des partitions du disque BP +;-> BP, ES:DI +;<- renvoie leur nombre en CX +;==================================== +getpartitions: + push eax + push ebx + push edx + push si + push di + mov ecx,0 + mov word [wheres],0 + mov [theprimary],ecx +againpart: + xor eax,eax + mov ebx,ecx + push di + mov di,partition + CALL readsector + mov si, di + pop di + add si,0x01BE + mov cl,4 +showevery: + cmp dword [si+NumSector],0x00000000 + je nothings + mov edx,[si+StartSector] + cmp byte [si+Kind],0x05 + je is + cmp byte [si+Kind],0x0F + jne isnot +is: + mov eax,[theprimary] + add eax,edx + cmp dword [theprimary],0 + jne nothings +isnot: + push ecx + push di + push si + mov cx,[wheres] + shl cx,6 + add di,cx + mov ecx,16/4 + rep movsd + pop si + mov [di],ebx + mov [di+4],si + sub word [di+4],partition + mov [di+6],ebx + add [di+6],edx + mov ecx,[di+6] + mov [di+10],bp + add di,12 + push edx + call getbootinfos + pop edx + pop di + pop ecx + inc word [wheres] +nothings: + add si,16 + dec cl + jnz showevery + mov ecx,eax + cmp dword [theprimary],0x00000000 + jne noth + mov [theprimary],eax +noth: + cmp ecx,0 + jnz near againpart + mov cx,[wheres] + pop di + pop si + pop edx + pop ebx + pop eax + ret + +;==============ISMBR================= +;Zero si Mbr sur le premier secteur du support BP +;-> BP +;<- +;==================================== +IsMbr: + push ax + push ecx + push di + push es + mov ecx,0 + mov di,buffer + push cs + pop es + call readsector + add di,0x01BE + mov cl,4 +isgood: + mov al,[cs:di] + and al,0x7F + cmp al,0 + jne noMbr + add di,16 + dec cl + jne isgood + cmp word [cs:di],0xAA55 +noMbr: + pop es + pop di + pop ecx + pop ax + ret + +;=============DETECTDISK============= +;Renvoie en ES:DI les disques d‚tect‚s fini par 0FFh +;-> ES:DI +;<- +;==================================== +detectdisk: + push ax + push bx + push cx + push dx + push si + push di + mov si,PossibleDisks +DetectAllDisk: + mov dl,[cs:si] + inc si + cmp dl,0xFF + je EndOfDetection + mov cl,4 +retry: + push cx + mov ax,0x0201 + mov cx,0x0101 + mov dh,0x00 + mov bx,buffer + int 0x13 + pop cx + jnc isdetected + dec cl + jnz retry + jmp DetectAllDisk +isdetected: + mov [es:di],dl + inc di + jmp DetectAllDisk +EndOfDetection: + mov byte [di],0xFF + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret + +PossibleDisks db 0x00,0x01,0x02,0x03,0x04,0x05,0x80,0x81,0x82,0x83,0x84,0x85,0xFF + +;=============INITDISK=============== +;Initialise le p‚riph‚rique BP pour une utilisation ult‚rieure +;-> BP +;<- +;==================================== +initdisk: + push ax + push bx + push cx + push dx + push di + push es + mov dx,bp + mov ah,8 + int 0x13 + and cx,0x3F + mov [cs:sectorspertrack],cx + mov cl,dh + inc cl + mov [cs:headsperdrive],cx + pop es + pop di + pop dx + pop cx + pop bx + pop ax + ret + +;=============WRITESECTOR (Fonction 01H)=============== +;Ecrit le secteur ECX du disque BP depuis ds:si +;-> AH=1 +;<- Flag Carry si erreur +;===================================================== +writesector: + push ax + push bx + push ecx + push dx + push si + push di + mov ax,bp + mov [cs:temp],al + mov ax, cx + ror ecx, 16 + mov dx, cx + rol ecx,16 + div word [cs:sectorspertrack] + inc dl + mov bl, dl + xor dx,dx + div word [cs:headsperdrive] + mov dh, [cs:temp] + xchg dl, dh + mov cx, ax + xchg cl, ch + shl cl, 6 + or cl, bl + mov bx, si + mov si, 4 + mov al, 1 +TryAgain2: + mov ah, 3 + int 0x13 + jnc Done2 + dec si + jnz TryAgain2 +Done2: + pop di + pop si + pop dx + pop ecx + pop bx + pop ax + ret + +;=============READSECTOR=============== +;Lit le secteur ECX du disque BP et le met en es:di +;-> +;<- +;====================================== +readsector: + push ax + push bx + push ecx + push dx + push si + mov ax,bp + mov [cs:temp],al + mov ax, cx + ror ecx, 16 + mov dx, cx + rol ecx,16 + cmp ecx,4128705 + ja extended + div word [cs:sectorspertrack] + inc dl + mov bl, dl + xor dx,dx + div word [cs:headsperdrive] + mov dh, [cs:temp] + xchg dl, dh + mov cx, ax + xchg cl, ch + shl cl, 6 + or cl, bl + mov bx, di + mov si, 4 + mov al, 1 +TryAgain: + mov ah, 2 + int 0x13 + jnc Done + dec si + jnz TryAgain +Done: + pop si + pop dx + pop ecx + pop bx + pop ax + ret +extended: + push di + push ds + push cs + pop ds + mov si,block + mov byte [si+Sizes],0x10 + mov byte [si+Reserve],0x01 + mov word [si+NumSectors],0x0001 + mov [si+Adressseg],es + mov [si+Adressoff],di + mov [si+SectorLow],ax + mov [si+SectorHigh],dx + mov di,4 + mov dl,[temp] +TryAgainX: + mov ah, 0x42 + int 0x13 + jnc DoneX + dec di + jnz TryAgainX +DoneX: + pop ds + pop di + pop si + pop dx + pop ecx + pop bx + pop ax + ret + +headsperdrive dw 16 +sectorspertrack dw 38 +block times 24 db 0 +temp db 0 + +;============CLS============== +;Efface l'‚cran +;-> +;<- +;============================= +cls: + push ax + mov ax,0x0003 + int 0x10 + pop ax + ret + +;==========SHOWSTR============ +;Affiche une chaine de caractŠre point‚ par SI +;-> SI pointe une chaine +;<- +;============================= +showstr: + push ax + push bx + push si + cld +again: + lodsb + or al,al + jz fin + call showchar + jmp again +fin: + pop si + pop bx + pop ax + ret + +;==========SHOWPASSTR============ +;Affiche une chaine de caractŠre point‚ par SI +;-> SI pointe une chaine +;<- +;============================= +showpasstr: + push ax + push bx + push cx + push si + mov cl,[si] + inc si + cld +again2: + lodsb + call showchar + dec cl + jnz again2 +fin2: + pop si + pop cx + pop bx + pop ax + ret + +;==========WAITKEY============= +;Attend l'appuie d'une toouche et +;renvoie en AL la touche appuyer +;-> +;<- AL +;============================== +waitkey: + mov ax,0 + int 0x16 + ret + +;==========SHOWCHAR============ +;Affiche un caractŠre point‚ dans AL +;-> AL +;<- +;============================== +showchar: + push ax + push bx + mov ah,0x0E + mov bx,0x07 + int 0x10 + pop bx + pop ax + ret + +;==========SHOWINT============ +;Affiche un entier EDX apr‚s le curseur +;-> EDX un entier +;<- +;============================= +showint: + push eax + push bx + push cx + push edx + push esi + push di + push ds + push es + push cs + push cs + pop ds + pop es + mov cx,10 + mov di,showbuffer + mov al,' ' + cld + rep stosb + xor cx,cx + mov eax, edx + mov esi, 10 + mov bx,di + mov byte [cs:di+1],0 +decint: + xor edx,edx + div esi + add dl,'0' + inc cx + mov [cs:bx],dl + dec bx + cmp ax, 0 + jne decint +showinteger: + mov si,showbuffer + call showstr + pop es + pop ds + pop di + pop esi + pop edx + pop cx + pop bx + pop eax + ret + +;============================================================================= + +; VARIABLES INITIALISEE + +;============================================================================= + +sel dw 0 +wheres dw 0 +numbers dw 0 +theprimary dd 0 +prog: + +incbin "mbr.bin" +incbin "loader.bin" +;============================================================================= + +; VARIABLES NON INITIALISEE + +;============================================================================= + +showbuffer equ $ +disk equ $+12 +partition equ $+12+26 +buffer equ $+12+26+512 +thepart equ $+12+26+512+512 +thedrive equ $+12+26+512+512+10000 +dummys equ $+12+26+512+512+10000+10000 + +section .bss + +%include "partition.h" +%include "echs.h" + +;showbuffer resb 12 +;disk resb 26 +;partition resb 512 +;buffer resb 512 +;thepart resb 10000 +;thedrive resb 10000 +;dummys resb 10000 + diff --git a/install/mbrol/partition.h b/install/mbrol/partition.h new file mode 100644 index 0000000..96800f8 --- /dev/null +++ b/install/mbrol/partition.h @@ -0,0 +1,10 @@ +struc part +Active resb 1 +StartH resb 1 +StartCS resw 1 +Kind resb 1 +EndH resb 1 +EndCS resw 1 +StartSector resd 1 +NumSector resd 1 +endstruc diff --git a/lib/8x8fnt.c b/lib/8x8fnt.c new file mode 100644 index 0000000..e786385 --- /dev/null +++ b/lib/8x8fnt.c @@ -0,0 +1,130 @@ +static u8 font8x8 [2048] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E, + 0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E, 0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x38, 0x7C, 0x38, 0xFE, 0xFE, 0xD6, 0x10, 0x38, + 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x7C, 0x10, 0x38, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, + 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, + 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78, + 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, + 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, 0x18, 0xDB, 0x3C, 0xE7, 0xE7, 0x3C, 0xDB, 0x18, + 0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00, 0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, 0x3E, 0x61, 0x3C, 0x66, 0x66, 0x3C, 0x86, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, + 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, + 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, + 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, + 0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00, 0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00, + 0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x18, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, + 0x38, 0x6C, 0xC6, 0xD6, 0xC6, 0x6C, 0x38, 0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x7C, 0xC6, 0x06, 0x1C, 0x30, 0x66, 0xFE, 0x00, 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, + 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00, 0xFE, 0xC0, 0xC0, 0xFC, 0x06, 0xC6, 0x7C, 0x00, + 0x38, 0x60, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00, 0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00, 0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30, + 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0x0C, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00, + 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00, + 0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00, 0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3A, 0x00, + 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00, 0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00, + 0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00, + 0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xCE, 0x7C, 0x0E, + 0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00, 0x3C, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x3C, 0x00, + 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, + 0xC6, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0xC6, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00, + 0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, + 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, + 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00, + 0x1C, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, + 0x3C, 0x66, 0x60, 0xF8, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8, + 0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x06, 0x00, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E, + 0x00, 0x00, 0xDC, 0x76, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x7E, 0xC0, 0x7C, 0x06, 0xFC, 0x00, + 0x30, 0x30, 0xFC, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, + 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0xFC, + 0x00, 0x00, 0x7E, 0x4C, 0x18, 0x32, 0x7E, 0x00, 0x0E, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0E, 0x00, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x70, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x70, 0x00, + 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00, + 0x7C, 0xC6, 0xC0, 0xC0, 0xC6, 0x7C, 0x0C, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x0C, 0x18, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, 0x7C, 0x82, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0xC6, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x30, 0x18, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x7E, 0xC0, 0xC0, 0x7E, 0x0C, 0x38, + 0x7C, 0x82, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, + 0x30, 0x18, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x7C, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00, + 0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0x7C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00, + 0x18, 0x30, 0xFE, 0xC0, 0xF8, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x7E, 0x12, 0xFE, 0x90, 0xFE, 0x00, + 0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00, 0x7C, 0x82, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x30, 0x18, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x78, 0x84, 0x00, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x60, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0xFC, 0xC6, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x00, + 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x02, 0x7C, 0xCE, 0xD6, 0xE6, 0x7C, 0x80, + 0x38, 0x6C, 0x64, 0xF0, 0x60, 0x66, 0xFC, 0x00, 0x3A, 0x6C, 0xCE, 0xD6, 0xE6, 0x6C, 0xB8, 0x00, + 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x0E, 0x1B, 0x18, 0x3C, 0x18, 0xD8, 0x70, 0x00, + 0x18, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00, 0x0C, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3C, 0x00, + 0x0C, 0x18, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x18, 0x30, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, + 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x00, 0x76, 0xDC, 0x00, 0xE6, 0xF6, 0xDE, 0xCE, 0x00, + 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, + 0x18, 0x00, 0x18, 0x18, 0x30, 0x63, 0x3E, 0x00, 0x7E, 0x81, 0xB9, 0xA5, 0xB9, 0xA5, 0x81, 0x7E, + 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x00, 0x00, 0x63, 0xE6, 0x6C, 0x7E, 0x33, 0x66, 0xCC, 0x0F, + 0x63, 0xE6, 0x6C, 0x7A, 0x36, 0x6A, 0xDF, 0x06, 0x18, 0x00, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x00, + 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x30, 0x60, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, + 0x7C, 0x82, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, 0x18, 0x0C, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, + 0x7E, 0x81, 0x9D, 0xA1, 0xA1, 0x9D, 0x81, 0x7E, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18, + 0x66, 0x66, 0x3C, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, + 0x76, 0xDC, 0x7C, 0x06, 0x7E, 0xC6, 0x7E, 0x00, 0x76, 0xDC, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x00, + 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x00, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0x00, + 0x30, 0x7E, 0x0C, 0x7C, 0xCC, 0xCC, 0x78, 0x00, 0xF8, 0x6C, 0x66, 0xF6, 0x66, 0x6C, 0xF8, 0x00, + 0x7C, 0x82, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, 0xC6, 0x00, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, + 0x30, 0x18, 0xFE, 0xC0, 0xFC, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x0C, 0x18, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x3C, 0x42, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, + 0x30, 0x18, 0x3C, 0x18, 0x18, 0x18, 0x3C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x60, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x00, 0x78, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xCC, 0x00, + 0x7C, 0x82, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x00, 0x0C, 0x06, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x00, + 0x76, 0xDC, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x76, 0xDC, 0x38, 0x6C, 0xC6, 0x6C, 0x38, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0xC0, 0xE0, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0xF0, + 0xF0, 0x60, 0x7C, 0x66, 0x7C, 0x60, 0xF0, 0x00, 0x18, 0x30, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x7C, 0x82, 0x00, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x60, 0x30, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, + 0x18, 0x30, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0xFC, 0x0C, 0x18, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x7E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xE1, 0x32, 0xE4, 0x3A, 0xF6, 0x2A, 0x5F, 0x86, + 0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, 0x3E, 0x61, 0x3C, 0x66, 0x66, 0x3C, 0x86, 0x7C, + 0x00, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0x38, + 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, + 0x78, 0x0C, 0x38, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x18, 0x30, 0x7C, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; diff --git a/lib/makefile b/lib/makefile new file mode 100644 index 0000000..6348347 --- /dev/null +++ b/lib/makefile @@ -0,0 +1,17 @@ +FREEC=gcc -O2 -nostdinc -ffreestanding -fno-builtin -fomit-frame-pointer -Wall -I ../Include -c +PARTIAL=-r +OBJS= string.o vgatxt.o + +all: makeall + +makeall: $(OBJS) + (sync;ld $(PARTIAL) -o libs.o $(OBJS)) + +vgatxt.o:vgatxt.c + $(FREEC) $^ + +string.o:string.c + $(FREEC) $^ +clean: + rm -f *.o + diff --git a/lib/modes.c b/lib/modes.c new file mode 100644 index 0000000..de3b38f --- /dev/null +++ b/lib/modes.c @@ -0,0 +1,118 @@ +#define maxgraphmode 5 +#define maxtextmode 5 + +static mode_def textmodes[maxtextmode] = { + + /*MODE 0, 40*25 16 couleurs */ + { + 0x67,0x00,0x03,0x08,0x03,0x00,0x02, + 0x2D,0x27,0x28,0x90,0x2B,0x0A,0xBF,0x1F,0x00,0x4F,0x0D,0x0E,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x14,0x1F,0x96,0xB9,0xA3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x08,0x00, + 40,25 + }, + + /*MODE 1, 80*25 16 couleurs */ + { + 0x67,0x00,0x03,0x00,0x03,0x00,0x02, + 0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F,0x00,0x4F,0x0D,0x0E,0x00,0x00,0x00,0x00, + 0x9C,0x0E,0x8F,0x28,0x1F,0x96,0xB9,0xA3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x08,0x00, + 80,25 + }, + + /*MODE 2, 80*50 16 couleurs */ + { + 0x63,0x00,0x03,0x01,0x03,0x01,0x02, + 0x5F,0x4F,0x50,0x82,0x55,0x81,0xBF,0x1F,0x00,0x47,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x1F,0x96,0xB9,0xA3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x10,0x11,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0xCF,0x00,0x0F,0x00,0x00, + 80,50 + }, + + /*MODE 3, 100*50 16 couleurs */ + { + 0x67,0x00,0x03,0x01,0x03,0x01,0x02, + 0x70,0x63,0x64,0x85,0x68,0x84,0xBF,0x1F,0x00,0x47,0x06,0x07,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x32,0x1F,0x96,0xB9,0xA3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x10,0x11,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x00,0x00, + 100,50 + }, + + /*MODE 4, 100*60 16 couleurs */ + { + 0xA7,0x00,0x03,0x01,0x03,0x01,0x02, + 0x70,0x63,0x64,0x85,0x68,0x84,0xFF,0x1F,0x00,0x47,0x06,0x07,0x00,0x00,0x00,0x00, + 0xE7,0x8E,0xDF,0x32,0x1F,0xDF,0xE5,0xA3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x10,0x0E,0x00,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x10,0x11,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, + 0x0C,0x00,0x0F,0x00,0x00, + 100,60 + } + }; + + +static mode_def graphmodes[maxgraphmode] = { + /*MODE 80, 320*200 256 couleurs */ + { + 0x63,0x00,0x03,0x01,0x0F,0x00,0x06, + 0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x0E,0x8F,0x28,0x00,0x96,0xB9,0xE3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00,0x00, + 40,25 + }, + + /*MODE 81, 320*400 256 couleurs */ + { + 0x63,0x00,0x03,0x01,0x0F,0x00,0x06, + 0x5F,0x4F,0x50,0x82,0x54,0x80,0xBF,0x1F,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0x9C,0x8E,0x8F,0x28,0x00,0x96,0xB9,0xE3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00,0x00, + 40,50 + }, + + /*MODE 82, 320*480 256 couleurs */ + { + 0xE3,0x00,0x03,0x01,0x0F,0x00,0x06, + 0x5F,0x4F,0x50,0x82,0x54,0x80,0x0B,0x3E,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xEA,0xAC,0xDF,0x28,0x00,0xE7,0x06,0xE3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00,0x00, + 40,60 + }, + + /*MODE 83, 360*480 256 couleurs */ + { + 0xE7,0x00,0x03,0x01,0x0F,0x00,0x06, + 0x6B,0x59,0x5A,0x8E,0x5E,0x8A,0x0D,0x3E,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00, + 0xEA,0xAC,0xDF,0x2D,0x00,0xE7,0x06,0xE3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00,0x00, + 45,60 + }, + + /*MODE 84, 400*600 256 couleurs */ + { + 0xE7,0x00,0x03,0x01,0x0F,0x00,0x06, + 0x74,0x63,0x64,0x97,0x68,0x95,0x86,0xF0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5B,0x8D,0x57,0x32,0x00,0x60,0x80,0xE3,0xFF, + 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0F,0xFF, + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, + 0x41,0x00,0x0F,0x00,0x00, + 50,75 + } + }; diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..a4ca0df --- /dev/null +++ b/lib/string.c @@ -0,0 +1,11 @@ +#include "types.h" + +void memset(void *dst, u8 val, u16 count,u32 size) +{ + u8 *temp; + for(temp = (u8 *)dst; count != 0; count--) +{ +temp+=size; +*temp = val; +} +} diff --git a/lib/vgatxt.c b/lib/vgatxt.c new file mode 100644 index 0000000..046542d --- /dev/null +++ b/lib/vgatxt.c @@ -0,0 +1,88 @@ +#include "vga.h" +#include "string.h" +#include "asm.h" + +#include "modes.c" +#include "8x8fnt.c" + +#define sequencer 0x3c4 +#define misc 0x3c2 +#define ccrt 0x3D4 +#define attribs 0x3c0 +#define graphics 0x3ce +#define state 0x3da + + +static u16 resX,resY,cursX,cursY; /* resolution x,y en caractères et position du curseur */ +static u16 pages,pagesize,activepage; /* nombre de pages disponibles et taille d'une page */ +static u8 vmode; /* mode en cours d'utilisation */ +static u16 basemem; /* debut de la mémoire vidéo */ +static bool scrolling,graphic; /* Activation du défilement, Flag du mode graphique */ + + +void print (u8* string) +{ + u8 *source,*screen; + source = string; + screen = (u8 *)TEXTSCREEN; + while(*source!=0x00) + { + *screen = *source; + screen+=2; + source++; + } +} + +void cls (void) +{ + memset((u8 *)TEXTSCREEN,0x20,(80*25*2),2); +} + + +u16 setvmode(u8 choosedmode) +{ + u8 *def,i,mode; + + mode=choosedmode&0x7F; + if (choosedmode>0x7F) + { + if (mode>maxgraphmode) return 1; /* mode inexistant */ + def=(u8 *)&graphmodes[mode]; + graphic=true; + } + else + { + if (mode>maxtextmode) return 1; /* mode inexistant */ + def=(u8 *)&textmodes[mode]; + graphic=false; + } + outb(misc,*def++); + outb(state,*def++); + for(i=0;i<5;i++) + { + outb(sequencer,i); + outb(sequencer+1,*def++); + } + outb(ccrt,0x11); + outb(ccrt+1,0x0E); + for(i=0;i<25;i++) + { + outb(ccrt,i); + outb(ccrt+1,*def++); + } + for(i=0;i<9;i++) + { + outb(graphics,i); + outb(graphics+1,*def++); + } + inb(state); + for(i=0;i<21;i++) + { + inb(attribs); + outb(attribs,i); + outb(attribs,*def++); + } + inb(state); + outb(attribs,0x20); + return 0; +} diff --git a/makefile b/makefile new file mode 100644 index 0000000..bf21808 --- /dev/null +++ b/makefile @@ -0,0 +1,29 @@ +all: makall + +makall: boot/boot12.bin installer/mbrol.com lib/libs.o system/system.sys + sync + +clean: + (cd system; make clean) + (cd boot; make clean) + (cd install; make clean) + (cd lib;make clean) + sync + +backup: clean + (cd .. ; tar cf - cos | gzip -f - > backup.tar.gz) + +allbackup: backup + (echo Inserez une disquette; sleep ; cp ../backup.tar.bz2 /dev/fd0) + +system/system.sys: + (cd system; make) + +boot/boot12.bin: + (cd boot; make) + +installer/mbrol.com: + (cd install; make) + +lib/libs.o: + (cd lib; make) \ No newline at end of file diff --git a/system/loader.asm b/system/loader.asm new file mode 100644 index 0000000..7b9deef --- /dev/null +++ b/system/loader.asm @@ -0,0 +1,227 @@ +[BITS 16] +[ORG 0x100] + + SECTION .text + push cs + push cs + pop ds + pop es + call EnableA20 + mov si,msgpmode + call showstr + mov ax,cs + mov [RealCS],ax + lea ax,[Real] + mov [RealIP],ax + + xor eax,eax + mov ax,cs + shl eax,4 + mov [GDT.Entry1+2],ax + mov [GDT.Entry2+2],ax + mov [GDT.Entry4+2],ax + mov [GDT.Entry5+2],ax + shr eax,16 + mov [GDT.Entry1+4],al + mov [GDT.Entry2+4],al + mov [GDT.Entry4+4],al + mov [GDT.Entry5+4],al + + xor eax,eax + mov ax,cs + shl eax,4 + add eax,gdt0 + mov [GDTR.Address],eax + lgdt [GDTR] + + cli + ;mov al,0xFF + ;out 0x21,al + mov al,0x80 + out 0x70,al + + mov eax,cr0 + or al,1 + mov cr0,eax + + jmp SYS_CODE_SEL:GoPMode32 + +GoPMode32: +[BITS 32] + mov ax,SYS_DATA_SEL + mov ds,ax + mov ecx,50000/4 + cld + mov esi,kernel + mov edi,0x100000 + mov ax,ALL_DATA_SEL + mov es,ax + mov gs,ax + mov fs,ax + mov ss,ax + rep movsd + mov ds,ax + mov esp,0x3fffff + call KERNEL_SEL:0x100000 + jmp REAL_CODE_SEL:GoReal + +GoReal: +[BITS 16] + mov ax,REAL_DATA_SEL + mov ds,ax + mov es,ax + mov ss,ax + mov gs,ax + mov fs,ax + mov esp,0xffff + + mov eax,cr0 + and al,0xFE + mov cr0,eax + + jmp far [RealIP] + +Real: + jmp Real + +msgpmode db 'Pmode loader is loading',0 + +;======================SHOWSTR======================== +;Affiche la chaine de caractère pointé par ds:si à l'écran +;-> DS, SI +;<- Flag Carry si erreur +;===================================================== +showstr: + pusha +Next_Char: + lodsb + or al,al + jz End_Show + mov ah,0x0E + mov bx,0x07 + int 0x10 + jmp Next_Char +End_Show: + popa + ret + + +;***********************EnableA20******************************* +;-> +;<- +;Ouvre l'autoroute A20 +;*************************************************************** +EnableA20: + cli + call ClearKeybBuffer + call WaitKeybCommand + mov al,0xd1 + out 0x64,al + call WaitKeybCommand + mov al,0xdf + out 0x60,al + call WaitKeybCommand + jmp A20Enabled +WaitKeybCommand: + in al,0x64 + test al,0x02 + jnz WaitKeybCommand + ret +ClearKeybBuffer: + in al,0x64 + test al,0x01 + jnz ReadKeyb + ret +ReadKeyb: + in al,0x60 + jmp ClearKeybBuffer +A20Enabled: + sti + ret + +section .data + +RealIP: dw 0 +RealCS: dw 0 + +GDTR: +.Size: dw GDT_END +.Address: dd 0 + + + +gdt0 equ $ ; null entry +GDT: +.Entry0: dw 0 ; limit 15:0 + dw 0 ; base 15:0 + db 0 ; base 23:16 + db 0 ; type + db 0 ; limit 19:16, flags + db 0 ; base 31:24 + + +SYS_CODE_SEL equ $-gdt0 ; code segment descriptor + +.Entry1: dw 0xFFFF + dw 0x0 ; base + db 0x0 ; base + db 0x9A ; present, ring 0, code, non-conforming, readable + db 0x40 ; 32 bit + db 0 + + +SYS_DATA_SEL equ $-gdt0 ; data segment descriptor + +.Entry2: dw 0xFFFF + dw 0x0 ; base + db 0x0 ; base + db 0x92 ; present, ring 0, data, expand-up, writable + db 0x40 ; 32 bit + db 0 + + +ALL_DATA_SEL equ $-gdt0 ; 4meg data segment descriptor + +.Entry3: dw 0x03ff + dw 0x0 ; base + db 0x0 ; base + db 0x92 ; present, ring 0, data, expand-up, writable + db 0xcf ; 4k pages, 32 bit + db 0 + + +REAL_CODE_SEL equ $-gdt0 ; code segment descriptor for 16 bit mode + +.Entry4: dw 0xFFFF + dw 0x0 ; base + db 0x0 ; base + db 0x9A ; present, ring 0, code, non-conforming, readable + db 0x00 ; 16 bit + db 0 + + +REAL_DATA_SEL equ $-gdt0 ; data segment descriptor for 16 bit mode + +.Entry5: dw 0xFFFF + dw 0x0 ; base + db 0x0 ; base + db 0x92 ; present, ring 0, data, expand-up, writable + db 0x00 ; 16 bit + db 0 + + +KERNEL_SEL equ $-gdt0 ; 4meg code segment descriptor + +.Entry6: dw 0x03ff + dw 0x0 ; base + db 0x0 ; base + db 0x9A ; present, ring 0, code, non-conforming, readable + db 0xcf ; 4k pages, 32 bit + db 0 + +GDT_END equ $-gdt0 -1 + + kernel: + + SECTION .bss + diff --git a/system/makefile b/system/makefile new file mode 100644 index 0000000..ca416e6 --- /dev/null +++ b/system/makefile @@ -0,0 +1,31 @@ +FREEC=gcc -O2 -nostdinc -ffreestanding -fno-builtin -fomit-frame-pointer -Wall -I ../Include -c -o + + +LINK=ld -Ttext 0x100000 -e __main -o + +all: system.sys + sync + +copy: + (cp system.sys /cygdrive/a) + +copy2: + (cp system.sys /cygdrive/b) + +system.sys: + nasm -f bin -o loader.bin loader.asm + nasm -f elf -o system.o system.asm + + $(FREEC) systemc.o system.c + $(LINK) system.out systemc.o system.o ../lib/libs.o + objcopy -O binary system.out system.bin + cat loader.bin>system.sys + cat system.bin>>system.sys + +clean: + rm -f *.o + rm -f *.out + rm -f *.bin + rm -f *.sys + + diff --git a/system/system.asm b/system/system.asm new file mode 100644 index 0000000..933909c --- /dev/null +++ b/system/system.asm @@ -0,0 +1,5 @@ +[BITS 32] + + + SECTION .text + diff --git a/system/system.c b/system/system.c new file mode 100644 index 0000000..548cb3e --- /dev/null +++ b/system/system.c @@ -0,0 +1,8 @@ +#include "vga.h" + +int __main(void) { + setvmode(1); + cls(); + print("Hello cos is here !"); + while(1); +}