IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation d'OS Assembleur Discussion :

Projet mini os embarqué


Sujet :

Programmation d'OS Assembleur

  1. #1
    Invité
    Invité(e)
    Par défaut Projet mini os embarqué
    Salut a tous. Moi c'est Romain, j'approche les 20 ans, je ne fais aucune étude, et actuellement je me suis lancé un petit défi que j'ai vite beaucoup apprécié : un mini OS entièrement fait par moi.
    Alors dans ce sens j'entend système de fichier fat12 ou fat16 et quelques utilitaires, ça serait niquel :p

    Je suis débutant en asm mais j'aime ça
    Actuellement j'ai un secteur de boot qui charge une IDT, initialise les segments, charge les secteurs suivants en 0x1000 et y saute.
    Puis c'est mon noyau précédement chargé qui prend la main, il charge une GDT, rempli juste les descripteurs d'interruptions qui seront utiles au timer et au clavier (IRQ0 et IRQ1), programme les PICS (le pic maitre pointe sur mes descripteurs préalablement remlis, et je masque toutes les interruptions sauf le clavier et le timer), puis je démare les interruptions.
    J'ai également fais quelques fonctions dont j'ai eu besoin. Mon driver clavier gère quelques touches de base.
    Biensur le code n'a pas été revu, tout cela est assez brouillon, mais je le poste pour avoir des critiques sur ma facon de coder.

    boot32.asm:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
     
    %define BASE    0x100  ; 0x0100:0x0 = 0x1000
    %define KSIZE   50     ; nombre de secteurs a charger
     
    [BITS 16]
    [ORG 0x00]
     
    jmp start
    %include "fn_boot.inc"
    start:
     
    ; initialisation des segments en 0x07C0
        mov ax, 0x07C0
        mov ds, ax
        mov es, ax
        mov ax, 0x8000    ; stack en 0xFFFF
        mov ss, ax
        mov sp, 0xf000
     
    ; recuparation de l'unite de boot
        mov [bootdrv], dl    
     
    ; affiche un msg
        mov si, msgDebut
        call print16
     
    ; charger le noyau
        xor ax, ax
        int 0x13
     
        push es
        mov ax, BASE
        mov es, ax
        mov bx, 0
        mov ah, 2
        mov al, KSIZE
        mov ch, 0
        mov cl, 2
        mov dh, 0
        mov dl, [bootdrv]
        int 0x13
        pop es
     
    ; initialisation du pointeur sur la GDT
        mov ax, gdtend    ; calcule la limite de GDT
        mov bx, gdt
        sub ax, bx
        mov word [gdtptr], ax
     
        xor eax, eax      ; calcule l'adresse lineaire de GDT
        xor ebx, ebx
        mov ax, ds
        mov ecx, eax
        shl ecx, 4
        mov bx, gdt
        add ecx, ebx
        mov dword [gdtptr+2], ecx
     
    ; passage en modep
        cli
        lgdt [gdtptr]    ; charge la gdt
        mov eax, cr0
        or  ax, 1
        mov cr0, eax        ; PE mis a 1 (CR0)
     
        jmp next
    next:
        mov ax, 0x10        ; segment de donne
        mov ds, ax
        mov fs, ax
        mov gs, ax
        mov es, ax
        mov ss, ax
        mov esp, 0x9F000    
     
        jmp dword 0x8:0x1000    ; reinitialise le segment de code
     
    ;--------------------------------------------------------------------
    bootdrv:  db 0
    msgDebut: db "Loading GDT and jumping to CS:0x1000...", 13, 10, 0
    ;--------------------------------------------------------------------
    gdt:
        db 0, 0, 0, 0, 0, 0, 0, 0
    gdt_cs:
        db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10011011b, 11011111b, 0x0
    gdt_ds:
        db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10010011b, 11011111b, 0x0
    gdtend:
    ;--------------------------------------------------------------------
    gdtptr:
        dw 0  ; limite
        dd 0  ; base
    ;--------------------------------------------------------------------
     
    ;; NOP jusqu'a 510
    times 510-($-$$) db 144
    dw 0xAA55
    kernel32.asm :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
     
    %define IDTSIZE 50    ; Nombre d'interruptions
    %define BASE 0x1000   
     
    ; -------------------------------------------------------------
     
    [BITS 32]
    [ORG 0x1000]
     
    jmp debut
     
    %include "fn.inc"
     
    debut:
        call clear
        mov esi, msgKernel
        call print
     
        lidt [idtptr]
        mov eax, int_clock             ; Init IRQ0
        mov word [idt+32*8], ax            
        mov word [idt+32*8+2], 0x08
        mov word [idt+32*8+4], 0x8e00
        shr eax, 16
        mov word [idt+32*8+6], ax
     
        mov eax, int_kbd               ; Init IRQ1
        mov word [idt+33*8], ax
        mov word [idt+33*8+2], 0x08
        mov word [idt+33*8+4], 0x8e00
        shr eax, 16
        mov word [idt+33*8+6], ax
     
        call remap_pic
     
        sti
     
        jmp $
     
    ; -------------------------------------------------------------
    ; IRQ0 : Timer
    ; -------------------------------------------------------------
     
    int_clock:
        mov al, 0x20
        out 0x20, al
        iret
     
    ; -------------------------------------------------------------
    ; IRQ1 : Driver Clavier     A chaque fin de ligne la chaine est dans buff_cmd
    ; -------------------------------------------------------------
     
    int_kbd:
        cli
     
    .wait:
        in al, 0x64
        and al, 1
        jz .wait
     
        in al, 0x60
     
        cmp al, 224
        je .wait
     
        cmp al, 0xf0
        jl .release
     
        cmp al, 0x3f
        je .refresh
     
        cmp al, 0x0e
        je .backspace
     
        cmp al, 0x2a
        je .shift_enable
     
        movzx ebx, byte [shift]
        call convert_scan
        call putc
     
    .refresh:
        call clear
        jmp .end
     
    .shift_enable:
        mov byte [shift], 1
        jmp .end
     
    .shift_disable:
        mov byte [shift], 0
        jmp .end
     
    .release:
        sub al, 0x80
        cmp al, 0x2a
        je .shift_disable
        jmp .end
     
    ; Backspace, seulement sur la meme ligne pour l'instant
    .backspace:
        movzx eax, byte [posx]
        cmp eax, 1
        jl .end
        sub byte [posx], 1
        mov esi, buff_space
        call putc
        sub byte [posx], 1
        call move_cursor
     
    .end:
        mov al, 0x20
        out 0x20, al
        sti
        iret
     
    ; -------------------------------------------------------------
     
    msgKernel: db 'Kernel loaded...', 10, 13, 'Welcome to RomOS 0.1', 13, 10, 'Press F5 to refresh sreen.', 10, 0
    buff_space: db ' '
    shift: db 0
     
    buff_cmd: times 256 db 0
    buff_cmd_size: db 0
     
    ;--------------------------------------------------------------------
     
    idt:                             ; idt est la table d'interruptions
        times (IDTSIZE*8) db 0       ; 8 * 50 octets aloués (taille_idt_descriptor * nb_interrupt)
     
    idtptr:
        dw (IDTSIZE << 3) - 1  ; Nombre de vecteurs d'interruption * 8 - 1
        dd (BASE+idt-$$)    ;  Adresse de la table
     
    ; -------------------------------------------------------------
     
    ;; NOP jusqu'a 4096
    times 4096-($-$$) db 90
    fn.inc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    ; -------------------------------------------------------------
    ; Remplit la chaine ESI de ECX fois
    ; -------------------------------------------------------------
    clear_string:
        pusha
        mov eax, 0
            mov edi, esi
     
    .debut:
        stosb
        add edi, 1
        loop .debut
        popa
     
        ret
     
    ; -------------------------------------------------------------
    ; Converti scan-code en ASCII    (puis l'affiche pour l'instant)
     
    ; AL = Scan-code     EBX = Décalage
    ; -------------------------------------------------------------
     
    convert_scan:
        push edi
        push eax
     
        dec eax
        shl eax, 1       ; Scancode x 2 
        mov edi, keyb_fr
        add edi, ebx
        add edi, eax
        mov esi, edi
     
        pop eax
        pop edi    
        ret
     
    ; -------------------------------------------------------------
    ; PUTC : Affiche le char dans ESI
    ; -------------------------------------------------------------
     
    putc:
        pusha
     
    .debut:  
        lodsb
        cmp al, 0
        jz .end
        cmp al, 10
        je .nl
        mov ah, 3           ; Couleur
        push eax            ; Push le char
     
    ; Calcul:
        movzx eax, byte [posy]
        mov ebx, 160
        mul ebx
        mov ebx, eax
     
        movzx eax, byte [posx]
        shl eax, 1
     
        mov edi, 0xb8000
        add edi, eax
        add edi, ebx
     
    ; Ecriture:
        pop eax           ; Pop le char
        mov word [ds:edi], ax
        add byte [posx], 1
        movzx eax, byte [posx]
        cmp eax, 80
        je .nl
    .cont:
        movzx eax, byte [posy]
        cmp eax, 25
        je .np
        jmp .end
     
    .end:
        call move_cursor
        popa
        ret
     
    ; New page:
    .np:
        call clear
        jmp .end
     
    ; New line
    .nl:
        add byte [posy], 1
        mov byte [posx], 0
        jmp .cont
     
    ; -------------------------------------------------------------
    ; PRINT : Fonction d'affichage en mode protégé
     
    ; ESI = Chaine
    ; -------------------------------------------------------------
     
    print:
        pusha
     
    .debut:  
        lodsb
        cmp al, 0
        jz .end
        cmp al, 10
        je .lf
        cmp al, 13
        je .cr
        mov ah, 3
        push eax
     
    ; Calcul:
        movzx eax, byte [posy]
        mov ebx, 160
        mul ebx
        mov ebx, eax
     
        movzx eax, byte [posx]
        shl eax, 1
     
        mov edi, 0xb8000
        add edi, eax
        add edi, ebx
     
    ; Ecriture:
        pop eax
        mov word [ds:edi], ax
        add byte [posx], 1
        movzx eax, byte [posx]
        cmp eax, 80
        je .lf
    .cont:
        movzx eax, byte [posy]
        cmp eax, 25
        je .np
        call move_cursor
        jmp .debut
     
    .end:
        popa
        ret
     
    ; New page:
    .np:
        call clear
        jmp .debut
     
    ; Carriage-return
    .cr: 
        mov byte [posx], 0
        jmp .debut
     
    ; Line-feed:
    .lf:
        add byte [posy], 1
        mov byte [posx], 0
        jmp .cont
     
    ; -------------------------------------------------------------
    ; PRINT_REG : Fonction d'affichage registre 32bits
    ; -------------------------------------------------------------
     
    print_reg:
        pusha
        mov edi, outreg
        mov eax, [reg32]
        mov esi, hexchar
        mov ecx, 8
     
    .debut:
        rol eax, 4
        mov ebx, eax
        and ebx, 0x0f
        mov bl, [esi+ebx]
        mov [edi], bl
     
        inc edi
        dec ecx
        jnz .debut
     
    ; End:
        mov esi, outreg
        call print
        popa
        ret
     
    ; -------------------------------------------------------------
    ; Fonction Clear
    ; -------------------------------------------------------------
     
    clear:
        pusha
        mov byte [posx], 0
        mov byte [posy], 0
        mov ecx, 80*25
        dec ecx
    .loop
        mov esi, space_buff
        call putc
        dec ecx
        cmp ecx, 0
        jne .loop
     
    ; Clear le dernier byte de l'écran
        mov byte [ds:0xb8f9f], 1
        mov byte [ds:0xb8fa0], ' '
     
        mov byte [posx], 0
        mov byte [posy], 0   
     
        call move_cursor
     
        popa
        ret
     
    ; -------------------------------------------------------------
    ; Fonction qui remap les PICs
    ; -------------------------------------------------------------
     
    remap_pic:
        pusha
     
    ; ICW1 : Séquence d'initalisation:
     
        mov al, 0x11
        out 0x20, al
        out 0xA0, al
        jmp .2
     
    ; ICW2 : On remap sur les bon vecteur
     
    .2:
        mov al, 0x20
        out 0x21, al  
        mov al, 0x28
        out 0xA1, al
        jmp .3
     
    ; ICW3 : On relie les pic entre eux
     
    .3:
        mov al, 0x08
        out 0x21, al
        mov al, 0x03
        out 0xA1, al
        jmp .4
     
    ; ICW4 : Mode par défaut
     
    .4:
        mov al, 0x01
        out 0x21, al
        out 0xA1, al
     
    ; Mask : 
     
        mov al, 0xfc
        out 0x21, al
        mov al, 0xff
        out 0xA1, al
     
        popa
        ret
     
    ; -------------------------------------------------------------
    ; Fonction de mise a jour du curseur
    ; -------------------------------------------------------------
     
    move_cursor:
        pusha
        movzx eax, byte [posx]
        shl eax, 8
        add al, byte [posy]
        mov ebx, eax
     
        and eax, 0xff
        mov ecx, 80
        mul ecx
     
        mov ecx, ebx
        shr ecx, 8
        add eax, ecx
     
        mov ecx, eax
     
     
    ; Low byte of pos
        mov al, 0x0f
        mov dx, 0x3d4
        out dx, al
        mov eax, ecx
        mov dx, 0x3d5
        out dx, al
     
    ; High byte of pos
        mov al, 0x0e
        mov dx, 0x3d4
        out dx, al
        mov eax, ecx
        shr eax, 8
        mov dx, 0x3d5
        out dx, al
        popa
        ret
     
     
     
    ; -------------------------------------------------------------
     
        hexchar: db '0123456789abcdef'
        outreg: db '00000000', 0
        reg32: dd 0
        space_buff: db ' '
     
        posx: db 0
        posy: db 0
     
        keyb_fr: db 0, 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0, '9', 0, '0', 0, ')', 0, '=', 0, 0x08, 0x08, 0, 0, 'a', 'A', 'z', 'Z', 'e', 'E', 'r', 'R', 't', 'T', 'y', 'Y', 'u', 'U', 'i', 'I', 'o', 'O', 'p', 'P', '^', '¨', '$', '£' , 10, 10, 0, 0, 'q', 'Q', 's', 'S', 'd', 'D', 'f', 'F', 'g', 'G', 'h', 'H', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'ù', '%', 0, 0, 0, 0, 0, 0, 'w', 'W', 'x', 'X', 'c', 'C', 'v', 'V', 'b', 'B', 'n', 'N', ',', '?', ';', '.', ':', '/', '!', '§', 0, 0, 0, 0, 0, 0, ' ', ' ', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    fn_boot.inc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ; -------------------------------------------------------------
    ; Fonction d'affichage qui utilise le BIOS
    ; -------------------------------------------------------------
    print16:
     
       push ax
       push bx
     
    .debut:
       lodsb
       or al, al ; zero=end of str
       jz .end   ; get out
       mov ah, 0x0E
       mov bl, 0xff
       int 0x10
       jmp .debut
     
    .end:
       pop bx
       pop ax
       ret
    Voila Je pense que je vais faire une fonction strcmp histoire d'implementer un 'help' :p Et qui me servira pour la suite. Et surtout je me penche sur les systèmes de fichiers la...

    Edit : tout est en assembleur pour 2 raison : je voulais le faire pour m'y familiariser et étant sous windows actuelement j'ai des soucis lors du linkage... Je me pencherais la dessus quand mon OS aura une taille conséquente

    Re-edit : Apparement Cygwin serait une bonne idée pour pouvoir compiler sous windows des fichiers linkables avec des binaires asm. Si quelqu'un pouvait m'en parler car je l'ai lu sur un site en anglais et je ne suis pas sur de tout comprendre.
    Dernière modification par Invité ; 26/11/2011 à 00h26.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Petit avancement pour mon OS qui stock désormais la dernière ligne dans un buffer. Du coups j'ai enfin ma 1ère commande qui fonctionne (j'ai implementé strncmp et non strcmp pour le moment. Par contre je ne sais pas pourquoi mais je n'arrive plus a demarer mon os sur mon disque dur externe alors que hier encore cela marchait... Avec une taille de 4,5 ko je devrais pas avoir de soucis nan ? Je précise que je copie directement mon bootloader au début et que je vire le mbr du coups, j'utilise "dd" pour la copie.

    Le soucis viendrait il du fait qu'il n'y a pas de MBR, mais directement un jmp pour une initialisation en 7c00 ? Pourtant cela marchait hier, j'ai juste formaté une nouvelle fois mon disque, chose que javais déjà faite plusieurs fois...
    Dernière modification par Invité ; 27/11/2011 à 00h57.

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2011
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1
    Points : 1
    Points
    1
    Par défaut
    salut romain
    sur quel livre tu t'es basé sur l'architecture de ton OS?

  4. #4
    Invité
    Invité(e)
    Par défaut
    Salut,
    Pour te répondre, je n'ai encore aucun livre sur l'assembleur. J'ai juste utilisé les tutos du site ou nous nous trouvons, et OSDev qui est un super site je trouve.
    Actuellement j'en suis toujours a la gestion de la mémoire, bien que j'ai toujours mon soucis de boot sur un vrai pc (pas une machine virtuelle). En effet meme avec le bootloader du formatage (celui que le formatage écrit sur mon disque) ou mon bootloader, peut importe, ni mon disque dur USB, ni ma clée USB ne bootent. Par contre tout est niquel en machine virtuelle.

  5. #5
    Invité
    Invité(e)
    Par défaut Booter depuis une clé usb
    Bonjour romfox17,

    Alors voila pour faire court moi aussi je suis en train de développer un OS.
    Et pour le tester depuis une clé USB, je modifie son Bootsecteur (1er secteur) avec un éditeur Hexadécimal qui est HxD : http://mh-nexus.de/en/hxd

    Tuto pour modifier le Bootsecteur:

    1. Ouvrez HxD.exe, ensuite cliquer sur l'icone en forme de disk (OpenDisk
    en infobulle).

    2. Next choisissez votre clé en décochant 'Open as Readonly'.

    3. Puis ouvrez votre binaire, donc le bootloader et le kernel

    4. Copy/paste le bootloader à l'offset 0 de la clé USB, et le kernel au début du secteur-1, secteur que vous avez choisi dans les paramètres passer à 'Fonctions 02h de int 0x13 (Écrit dans la RAM)

    5. REBOOT

    That's all
    En espérant que cela t'a aidé

    A++

Discussions similaires

  1. Projet mini ecran LCD pour serveur linux
    Par artiom dans le forum Linux
    Réponses: 1
    Dernier message: 10/09/2012, 16h13
  2. Projet mini serveur de chat pair à pair
    Par marwa_miss dans le forum Plateformes (Java EE, Jakarta EE, Spring) et Serveurs
    Réponses: 2
    Dernier message: 27/12/2009, 14h30
  3. [2D] Mini-projet : question pour une interface graphique
    Par kitsune dans le forum Développement 2D, 3D et Jeux
    Réponses: 15
    Dernier message: 10/03/2006, 14h59
  4. [Socket][mini-projet] Quelques questions
    Par Baptiste Wicht dans le forum Entrée/Sortie
    Réponses: 22
    Dernier message: 22/12/2005, 17h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo