Programmation d'un OS - erreur pdt le test sous bochs

Programmation d'un OS - erreur pdt le test sous bochs - Divers - Programmation

Marsh Posté le 30-10-2002 à 17:34:39    

Je suis en train de réaliser un système d'exploitation en mode protégé. Quand je le teste à partir de bochs, il me dit :
 

========================================================================
Event type: PANIC
Device: [CPU0 ]
Message: [CPU0 ] exception(): 3rd exception with no resolution
 
A PANIC has occurred.  Do you want to:
  cont       - continue execution
  alwayscont - continue execution, and don't ask again.
               This affects only PANIC events from device [CPU0 ]
  die        - stop execution now
  abort      - dump core
  debug      - continue and return to bochs debugger
Choose one of the actions above: [die]
========================================================================
Bochs is exiting with the following message:
[CPU0 ] exception(): 3rd exception with no resolution
========================================================================
damien@Le-Zigoto:~/boost/BoOSt-0.2.0$

En gros, on dirait un plantage de windows, mais encore pire ;) Dommage :( Voici le code qui fait planter :
 

Code :
  1. #include <sys.h>
  2. /**
  3. * Structure générale d'une GDT
  4. **/
  5. typedef struct s_entree_GDT
  6. {
  7.   unsigned short   limit15_00;
  8.   unsigned short   base15_00;
  9.   unsigned char    base23_16;
  10.   unsigned char    type;
  11.   unsigned char    type_util;
  12.   unsigned char    base31_24;
  13. } t_entree_GDT;
  14. // La GDT peut avoir au plus 8192 segments...
  15. t_entree_GDT GDT[128];
  16. // Fonction permettant de charger la GDT (page 3-8)
  17. void _lgdt(void * base, unsigned long limit)
  18. {
  19.     unsigned long i[2];
  20.     i[0] = limit << 16;
  21.     i[1] = (unsigned long) base;
  22.     __asm__ __volatile__ ("lgdt (%0)": :"p" (((char *) i)+2));
  23. }
  24. /**
  25. * Définit un descripteur de la GDT
  26. **/
  27. void set_gdt_desc(int num, long base, long limite, char G, char DB, char AVL,
  28.  char present, char DPL, char S, char type)
  29. {
  30. // CF page 3-10 du tome 3 du IA-32 Intel Architecture Software Developer's Manual.
  31. GDT[num].limit15_00 = limite & 0xFFFF;
  32. GDT[num].base15_00 = base & 0xFFFF;
  33. GDT[num].base23_16 = (base / 0x10000) & 0xFF;
  34. GDT[num].type = type + (present * 0x8 + DPL * 2 + S)*0x10;
  35. GDT[num].type_util = (limite/0x10000) & 0xFF + AVL + DB*4 + G*8;
  36. GDT[num].base31_24 = (base/0x1000000) & 0xFF;
  37. }
  38. void init_gdt(void)
  39. {
  40. set_gdt_desc(0,0,0,0,0,0,0,0,0,0);  /* Le bouquin Intel est clair : le 1er descripteur
  41.     * doit être entièrement à 0. D'où cette ligne.
  42.     */
  43. set_gdt_desc(1,0,0xFFFFF,1,1,0,1,1,1,0xB); // CS
  44. set_gdt_desc(2,0,0xFFFFF,1,1,0,1,1,1,0x3); // DS
  45. _lgdt(GDT,0x3FF);
  46. asm volatile("jmp reinit_cs\n \
  47.  reinit_cs:\n \
  48.  movl $0x10,%eax\n \
  49.  movw %ax,%ds\n \
  50.  movw %ax,%es\n \
  51.  movw %ax,%fs\n \
  52.  movw %ax,%gs\n \
  53.  movw %ax,%es\n" );
  54. }


Et en fait, ça plante quand je mets la ligne init_gdt() dans le programme principal du kernel. Qqn pourrait-il m'éclairer sur l'affaire ? Merci...


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 30-10-2002 à 17:34:39   

Reply

Marsh Posté le 30-10-2002 à 19:06:11    

T'as testé en vrai sur ton ordi ?
PS : pourquoi il faut mettre volatile devant asm ?


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 30-10-2002 à 21:00:08    

Euh
 
Question à 2 balles.
 
Comment tu fais pour compiler un truc qui doit pouvoir faire booter la machine?
 
J'ai un vague souvenir qu'il faut mettre l'adresse dans le MBR du début du code à exécuter, c'est ca ou je me plante?
 


---------------
Informaticien.be - Lancez des défis à vos amis
Reply

Marsh Posté le 30-10-2002 à 21:15:08    

HelloWorld a écrit a écrit :

T'as testé en vrai sur ton ordi ?
PS : pourquoi il faut mettre volatile devant asm ?



en vrai sur mon ordi, ça reboote :(
Pour le volatile, je c pas, il faut le mettre, c tout ce ke je c... Si on peut m'éclairer sur ce sujet d'ailleurs...


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 30-10-2002 à 21:17:26    

zion a écrit a écrit :

Euh
 
Question à 2 balles.
 
Comment tu fais pour compiler un truc qui doit pouvoir faire booter la machine?
 
J'ai un vague souvenir qu'il faut mettre l'adresse dans le MBR du début du code à exécuter, c'est ca ou je me plante?
 
 



pour ça, tu vas voir mon site, consacré à l'étude et à la réalisation d'un système d'exploitation :
 http://boost.ht.st/indexo.php et tu vas dans la rubrique téléchargement, tu télécharges le fichier boost-0.2.0-20020831-linux.tar.gz, tu mates les sources et le makefile qui compile tout ça... En gros, tu ne dois utiliser aucune fonction de la libc, tu dois donc tout reprogrammer toi-même, et tu dois créer un secteur de boot, à moins que lilo ou grub ne s'en charge...


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 30-10-2002 à 23:40:52    

up ace ke je le vaux bien...
 
Je tiens à préciser que je suis en mode protégé, là... J'ai déjà réinitialisé la GDT en mode réel, et tout s'est bien passé... Je suppose donc ke le problème vient du mode du processeur :(


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 31-10-2002 à 07:56:29    

Ben si ca reboot oui c'est ton code.
 
Au passage, petit conseil pour que ce soit + rapide et + lisible (pour une fois que les 2 sont comptibles) :
change :
(base / 0x10000) & 0xFF;  
en
(base >> 16) & 0xFF;  
 
Ensuite, vite fait comme ca avec les souvenirs qu'il me reste, lgdt doit immédiatement être suivie par un jump.
Toi, le lgdt est dans une fonction et est suivi par un ret.
Donc j'inclurais tout le code assembleur dans ta fonction _lgdt, y compris les init sur les registres, tant qu'à faire.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 31-10-2002 à 11:13:02    

HelloWorld a écrit a écrit :

Ben si ca reboot oui c'est ton code.
 
Au passage, petit conseil pour que ce soit + rapide et + lisible (pour une fois que les 2 sont comptibles) :
change :
(base / 0x10000) & 0xFF;  
en
(base >> 16) & 0xFF;  
 
Ensuite, vite fait comme ca avec les souvenirs qu'il me reste, lgdt doit immédiatement être suivie par un jump.
Toi, le lgdt est dans une fonction et est suivi par un ret.
Donc j'inclurais tout le code assembleur dans ta fonction _lgdt, y compris les init sur les registres, tant qu'à faire.
 




J'ai donc suivi tes indications... Voici mon code à présent :
 

Code :
  1. #include <sys.h>
  2. /**
  3. * Structure générale d'une GDT
  4. **/
  5. typedef struct s_entree_GDT
  6. {
  7.   unsigned short   limit15_00;
  8.   unsigned short   base15_00;
  9.   unsigned char    base23_16;
  10.   unsigned char    type;
  11.   unsigned char    type_util;
  12.   unsigned char    base31_24;
  13. } t_entree_GDT;
  14. // La GDT peut avoir au plus 8192 segments...
  15. t_entree_GDT GDT[128]; // ce qui suffit amplement
  16. // Fonction permettant de charger la GDT (page 3-8)
  17. void _lgdt(void * base, unsigned long limit)
  18. {
  19.     unsigned long i[2];
  20.     i[0] = limit << 16;
  21.     i[1] = (unsigned long) base;
  22.     __asm__ __volatile__ ("lgdt (%0)": :"p" (((char *) i)+2));
  23.     asm volatile("jmp reinit_cs\n \
  24.  reinit_cs:\n \
  25.  movl $0x10,%eax\n \
  26.  movw %ax,%ds\n \
  27.  movw %ax,%es\n \
  28.  movw %ax,%fs\n \
  29.  movw %ax,%gs\n \
  30.  movw %ax,%es\n" );
  31. }
  32. /**
  33. * Définit un descripteur de la GDT
  34. **/
  35. void set_gdt_desc(int num, long base, long limite, char G, char DB, char AVL,
  36.  char present, char DPL, char S, char type)
  37. {
  38. // CF page 3-10 du tome 3 du IA-32 Intel Architecture Software Developer's Manual.
  39. GDT[num].limit15_00 = limite & 0xFFFF;
  40. GDT[num].base15_00 = base & 0xFFFF;
  41. GDT[num].base23_16 = (base >> 16) & 0xFF;
  42. GDT[num].type = type + (present * 0x8 + DPL * 2 + S)*0x10;
  43. GDT[num].type_util = (limite >> 16) & 0xFF + AVL + DB*4 + G*8;
  44. GDT[num].base31_24 = (base >> 24) & 0xFF;
  45. }
  46. void init_gdt(void)
  47. {
  48. set_gdt_desc(0,0,0,0,0,0,0,0,0,0);
  49. /* Le bouquin Intel est clair : le 1er descripteur
  50.  * doit être entièrement à 0. D'où cette ligne.
  51.  */
  52. set_gdt_desc(1,0,0xFFFFF,1,1,0,1,1,1,0xB); // CS
  53. set_gdt_desc(2,0,0xFFFFF,1,1,0,1,1,1,0x3); // DS
  54. _lgdt(GDT,0x3FF);
  55. }


Et là... Toujours la même erreur  :cry:  Je vois pas du tout où est mon pb  :cry:


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 31-10-2002 à 16:43:23    

Bon je me suis gourré ... c'est après avoir commuté en mp qu'il faut faire le jump,pas apres le changement de gdt.
L'erreur peut aussi venir de donnée incorrectes dans ta gdt.
voici un lien qui m'avais bcp servi
note l'attribut packed pour les structures qui dit au compilo de ne pas ajouter des bytes en plus pour aligner en mémoire. Mais dans ton cas ca m'etonnerais que ca change.
http://inferno.cs.univ-paris8.fr/~ [...] ial06.html


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 31-10-2002 à 18:08:02    

HelloWorld a écrit a écrit :

Bon je me suis gourré ... c'est après avoir commuté en mp qu'il faut faire le jump,pas apres le changement de gdt.
L'erreur peut aussi venir de donnée incorrectes dans ta gdt.
voici un lien qui m'avais bcp servi
note l'attribut packed pour les structures qui dit au compilo de ne pas ajouter des bytes en plus pour aligner en mémoire. Mais dans ton cas ca m'etonnerais que ca change.
http://inferno.cs.univ-paris8.fr/~ [...] ial06.html



Mais justement, là je pige pas... J'ai initialisé EXACTEMENT la même GDT avant... Tiens, mate ça, c la même chose, en assembleur, c exécuté avant cette fontion, c'est en nasm.
 

Code :
  1. [BITS 16]
  2. extern main, kernelsize
  3. global _start,gdt
  4. ;[ORG 0x1000]
  5. _start:
  6. pop ax
  7. mov [kernelsize],ax
  8. push si
  9. mov si, testsencours
  10. call afficher
  11. pop si
  12.         push si
  13.         mov si,msgC386
  14.         call afficher
  15.         pop si
  16.         push si
  17.         call C386
  18.         pop si
  19. push si
  20. mov si,msgA20
  21. call afficher
  22. pop si
  23. call EnableA20
  24. push si
  25. mov si,msgA20ok
  26. call afficher
  27. pop si
  28. ModeProtege:
  29.         pop es
  30.         push ax
  31.         xor ax,ax
  32.         mov ds,ax
  33.         mov es,ax
  34.         pop ax
  35.         mov ax, gdtEnd
  36.         mov bx, gdt
  37.         sub ax, bx
  38.         mov word [gdtPtr], ax
  39.         xor eax, eax
  40.         xor ebx, ebx
  41.         mov ax, ds
  42.         mov ecx, eax
  43.         shl ecx, 4
  44.         mov bx, gdt
  45.         add ecx, ebx
  46.         mov dword [gdtPtr+2], ecx
  47. ; Passage en mode protégé
  48.         cli
  49.         lgdt    [gdtPtr]
  50.         mov eax, cr0
  51.         or ax, 1
  52.         mov cr0, eax
  53.         jmp Next
  54. Next:
  55.         mov ax, 0x10
  56.         mov ds, ax
  57.         mov fs, ax
  58.         mov gs, ax
  59.         mov es, ax
  60.         mov ss, ax
  61.         mov esp, 0x9F000
  62. jmp 0x8:main
  63. ;======================
  64. ;       FONCTIONS
  65. ;======================
  66. ;-------------------------------------
  67. ;        Procédures pour l'activation de la porte A20
  68. ;-------------------------------------
  69. EnableA20:
  70. push ax
  71. mov ah,0dfh
  72. call GateA20
  73. or al,al
  74. jz EnableA20_ok
  75. stc
  76. EnableA20_ok:
  77. pop ax
  78. ret
  79. GateA20:
  80. pushf
  81. cli
  82. call Empty8042
  83. jnz GateA20_fail
  84. out 0edh, ax
  85. mov al,0D1h
  86. out 64h,al
  87. call Empty8042
  88. jnz GateA20_fail
  89. mov al,ah
  90. out 60h,al
  91. call Empty8042
  92. push cx
  93. mov cx,14h
  94. GateA20_loop:
  95. out 0edh,ax
  96. loop GateA20_loop
  97. pop cx
  98. GateA20_fail:
  99. popf
  100. ret
  101. Empty8042:
  102. push cx
  103. xor cx,cx
  104. Empty8042_try:
  105. out 0edh,ax
  106. in al,64h
  107. and al,2
  108. loopnz Empty8042_try
  109. pop cx
  110. ret
  111. ;-----------------------------------
  112. ; Recherche d'un processeur 386 ou supérieur
  113. ;-----------------------------------
  114. C386:
  115.         pushf
  116.         xor ah, ah
  117.         push ax
  118.         popf
  119.         pushf
  120.         pop ax
  121.         and ah, 0x0f
  122.         cmp ah, 0x0f
  123.         je No386
  124.         mov ah, 0x0f
  125.         push ax
  126.         popf
  127.         pushf
  128.         pop ax
  129.         and ah, 0x0f
  130.         jz No386
  131.         popf
  132.         mov si, msgT386
  133.         call afficher
  134.         ret             ; tout va bien on se casse
  135. No386:
  136.         mov si, msgN386
  137.         call afficher
  138. Reboot:
  139.         mov si, msgReboot
  140.         call afficher
  141.         xor ah, ah
  142.         int 0x16                        ; Attend la pression d'une touche
  143.         db 0xEA         ; Reboot a l'arrache
  144.         dw 0x0000
  145.         dw 0xFFFF
  146. ;================================
  147. afficher:
  148.                 push ax
  149.                 push bx
  150.         .debut:
  151.                 lodsb           ; ds:si -> al
  152.                cmp al,0        ; fin chaine ?
  153.                 jz .fin
  154.                 mov ah,0x0E     ; appel au service 0x0e, int 0x10 du bios
  155.                 mov bx,0x07     ; bx -> attribut, al -> caractere ascii
  156.                 int 0x10
  157.                 jmp .debut;;
  158.         .fin:
  159.                 pop bx
  160.                 pop ax
  161.                 ret
  162. ;======================
  163. ;       VARIABLES
  164. ;======================
  165. testsencours db 13,10,'J',39,'effectue des tests sur votre ordinateur...',13,10,0
  166. msgC386 db      'Recherche d',39,'un processeur 386+', 10, 13, 0
  167. msgT386 db      'Processeur 386+ trouv?, poursuite du chargement',10,13,0
  168. msgN386 db      'Boost', 39, 'OS a besoin d', 39, 'un processeur 386+ pour fonctionner', 13, 10, 0
  169. msgA20 db 'Activation de la porte A20...  ',0
  170. msgA20ok db 'OK',13,10,0
  171. msgReboot       db      'Appuyez sur une touche pour red?marrer', 10, 13, 0
  172. msgErrFAT       db      'Erreur lors de la lecture de la FAT', 13, 10, 0
  173. gdtPtr:
  174.         dw      0
  175.         dd      0
  176. gdt:
  177.         db      0, 0, 0, 0, 0, 0, 0, 0
  178. gdt_cs:
  179.         db      0xff, 0xff, 0x0, 0x0, 0x0, 10011011b, 11011111b, 0x0
  180. gdt_ds:
  181.         db      0xff, 0xff, 0x0, 0x0, 0x0, 10010011b, 11011111b, 0x0
  182. gdtEnd:

Tu vois une différence entre les 2 GDT ? La 1è marche nickel, c une certitude, et elle vient de la même source que toi. La 2è, elle marche pas... D'ailleurs, j'ai rajouté les attributs packed, et ça fait pareil...


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 31-10-2002 à 18:08:02   

Reply

Marsh Posté le 31-10-2002 à 18:52:07    

Citation :

       cli
          lgdt    [gdtPtr]
          mov eax, cr0
          or ax, 1
          mov cr0, eax
          jmp Next
Next:


 
Ou est l'equivalent dans ton code C ?
 
2 erreurs possibles : tu as mal traduit l'init de ta gdt de asm -> C
Y'a une couille au niveau du code asm dans ton C qui load et switch en pmode
 

Citation :

GDT[num].type = type + (present * 0x8 + DPL * 2 + S)*0x10;  
GDT[num].type_util = (limite >> 16) & 0xFF + AVL + DB*4 + G*8;


 
C'est assez risqué. Test ce que ça donne si je passe autre chose que 1 ou 0 aufx flags ....
 

Code :
  1. GDT[num].type = (type & 0xF) | ((present & 1) << 3  | (DPL & 1) << 1 | (S & 1)) << 4;
  2. GDT[num].type_util = (limite >> 16) & 0xFF | (AVL & 1) | ((DB & 1) << 2 | (G & 1 )<< 3;


 
et défini des constantes pour que ce siot + lisible :

Code :
  1. #define ATTR_READ 1
  2. #define ATTR_WRITE (1 << 2)
  3. #define ATTR_EXECUTE (1 << 3)
  4. #define ATTR_DATA (ATTR_READ | ATTR_WRITE)
  5. #define ATTR_CODE ATTR_EXECUTE


(valeurs données au pif)
Sinon désolé mais c'est trop loin je peux pas grand chose pour toi.
Mais si ton code asm marche, c'est un problème de transcription asm -> C
Lis avec attention le lien que je t'ai filé.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 31-10-2002 à 20:29:14    

Vraiment, merci beaucoup pour tes réponses.
Concernant ceci :
 

Code :
  1. cli
  2.          lgdt    [gdtPtr]
  3.          mov eax, cr0
  4.          or ax, 1
  5.          mov cr0, eax
  6.          jmp Next
  7. Next:

il s'agit du passage en mode protégé. Le bit PE du registre cr0 doit être mis à 1 pour le mode protégé. Sinon, on est en mode réel. La seule différence entre le code asm et le code C, c que l'asm est en mode réel, et celui en C est en mode protégé. Est-ce qu'il y a une subtilité en mode protégé que je ne respecte pas quand on veut charger une nouvelle GDT ? Sinon je tiens à savoir où se situe mon erreur...
 
Merci.
 
Damien


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 31-10-2002 à 20:43:13    

Citation :

La seule différence entre le code asm et le code C, c que l'asm est en mode réel, et celui en C est en mode protégé


 
Ah okay je suis à la masse. Je croyais que t'écrivais un loader en C :crazy:
 
Mais pourquoi tu réserve pas la taille depuis l'assembleur et tu files l'adresse de la gdt à ton main (ou alors tu décides qu'elle est à une adresse fixe donnée) ?
Depuis ton C tu modifie directement les entrées voulues, sans avoir à recharger la gdt.
P'tête que je dis des conneries ... c'est trop loin là.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 31-10-2002 à 21:27:40    

oui mé bon... Admettons que j'aie besoin de 8192 segments (taille maximale admise pour les processeurs intel), en assembleur, j'aurais 8192*8 à mettre à 0 !? soit 65536 octets de plus pour le loader... Ca fé pas un peu bcp tout ça !? ça ressemblerait étrangement aux lignes xxxxxxxxxxxxxxxxxxxxx dans le msdos.sys de chez Microsoft... Si t'as un autre moyen, donne-le moi...


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 31-10-2002 à 23:09:45    

Mais non !
A partir du moment où t'as décidé où était la GDT en adresse physique, tu écris directement dedans (tu choisis un endroit ou y'a pas ton loader, ton kernell, le bios, etc ...)
 
Un petite boucle qui efface tout, tu initialise les premiers descriptor pour lancer le kernell, tu switch en pmode, et voilou.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 31-10-2002 à 23:17:14    

HelloWorld a écrit a écrit :

Mais non !
A partir du moment où t'as décidé où était la GDT en adresse physique, tu écris directement dedans (tu choisis un endroit ou y'a pas ton loader, ton kernell, le bios, etc ...)
 
Un petite boucle qui efface tout, tu initialise les premiers descriptor pour lancer le kernell, tu switch en pmode, et voilou.



arf... il va falloir copier les octets de gdt: à gdtend: en assembleur !? ouh là... euh... moui... Et tu c pas par hasard où je peux la mettre et comment ?


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Marsh Posté le 01-11-2002 à 11:08:25    

Bon, j'ai réussi à charger une nouvelle GDT, une fois en mode protégé, et en C... J'ai remplacé tout le fichier par celui-ci :
 
 

Code :
  1. unsigned long int GDT[6] = { 0, 0, 0x0000FFFF, 0x00CF9A00,  0x0000FFFF, 0x00CF9200};
  2. void init_gdt(void)
  3. {
  4. unsigned short int gdtr[4] = {23,GDT,((unsigned long int) GDT>>16),0};
  5.     __asm__ __volatile__ ("lgdt (%0)": :"p" (gdtr));
  6.     asm volatile(
  7.     "ljmp $0x08, $reinit_cs\n \
  8.       reinit_cs:\n \
  9.       movl $0x10,%eax\n \
  10.       movw %ax,%ds\n \
  11.       movw %ax,%es\n \
  12.       movw %ax,%fs\n \
  13.       movw %ax,%gs\n \
  14.       movw %ax,%ss\n \
  15.    " );
  16.     print("GDT chargée\n" );
  17. }

Voilà, pour ceux que ça intéresse ;)
ciao  :hello:


---------------
si t déçu d'être dessous, tu iras dessus kom ça tu seras plus déçu ni dessous... Si tu piges pas c ke t saoul, c sûr...
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed