CD bootable et jeu rétro dans un tweet


Il y a quelques années, j'ai créé une disquette de démarrage et un jeu rétro qui tient dans un tweet. Depuis, Twitter a doublé la longueur des tweets, j'ai donc décidé de créer un CD amorçable. Il exécute une version légèrement améliorée de tron.

perl -E 'say"A"x46422,"BDRDAwMQFFTCBUT1JJVE8gU1BFQ0lGSUNBVElPTg","A"x54,"Ew","A"x2634,"/0NEMDAxAQ","A"x2721,"BAAAAYQ","A"x30,"SVVVqogAAAAAAAEAF","A"x2676,"LMBaACgB76gfbgTAM0Qv8D4uYAI86qqgcc+AXP45GA8SHIRPFB3DTeYSEhyBSwCa8CwicMB3rSG/sHNFbRFJjAke9rrwQ","A"x2638'|base64 -D>cd.iso 

Le code dans le tweet crée une image de CD-ROM amorçable: cd.iso . Vous pouvez télécharger le code sur qemu ou votre machine virtuelle préférée - et jouer avec les touches fléchées. Vous pouvez même graver iso sur CD-R et démarrer sur un vrai ordinateur.

Pour créer une image de CD manuellement, vous devez d'abord acquérir une compréhension de base de l' ISO 9660 . Malheureusement, les documents aux normes ISO sont généralement chers. Cependant, ISO 9660 est identique à ECMA 119 , donc les spécifications peuvent être lues gratuitement.

ISO 9660 a de nombreuses extensions, telles que UDF, El Torito, RockRidge, Joliet, etc. Pour les images de démarrage, seul El Torito est important pour nous. La spécification El Torito, à mon avis, est mal écrite. Il y a des erreurs (par exemple, la dernière ligne du tableau 7), il est facile d'oublier que les valeurs sont hexadécimales (les préfixes 0x ne sont pas spécifiés), les nombres ne sont pas triés intuitivement, etc. Heureusement, le document est assez petit.

Pour créer un disque de démarrage, nous commençons par écrire 17 secteurs vides, suivis d'un ensemble de volumes Descriptor Set. Chaque secteur fait 2048 octets.

Remarque La spécification ISO-9660 indique que le jeu de descripteurs de volume commence par le secteur 16. La spécification El Torito nécessite le démarrage d'un enregistrement de démarrage dans le secteur 17. Techniquement, vous devriez mettre un descripteur de volume factice dans le secteur 16, mais tout fonctionne bien sans lui.

Nous écrivons le premier descripteur de volume:

 0x00 // Type (0 = boot record) 'CD001' // Identifier 0x01 // Version 'EL TORITO SPECIFICATION' // Boot System Identifier 9 x 0x00 // Padding 32 x 0x00 // Unused 0x13 0x00 0x00 0x00 // Boot Catalog address (in absolute sectors) 1973 x 0x00 // Unused 

Le secteur suivant contient le terminateur d'ensemble de descripteurs de volume:

 0xff // Type (255 = terminator) 'CD001' // Identifier 0x01 // Version 2041 x 0x00 // Unused 

Les descripteurs de volume sont suivis du catalogue de démarrage. El Torito prend en charge différents modes d'émulation. Le CD-ROM peut émuler une disquette de démarrage, un disque dur de démarrage, etc. Je n'ai pas installé d'émulation, c'est-à-dire que le BIOS chargera un certain nombre de secteurs - et prendra notre chargeur de démarrage.

La somme de contrôle est calculée de sorte que toutes les valeurs de 16 bits dans l'enregistrement soient additionnées à 0 (mod 65536).

Première entrée dans le répertoire de démarrage (entrée de vérification):

 0x01 // Header ID 0x00 // Platform ID (0 = Intel x86) 0x00 0x00 // Reserved 'a' // ID string 23 x 0x00 // Padding cksum cksum // Checksum (2 bytes) 0x55 0xaa // Key bytes 

Deuxième enregistrement (par défaut):

 0x88 // Boot Indicator (0x88 = bootable) 0x00 // Boot Media Type (0 = no emulation) 0x00 0x00 // Load segment 0x00 // System Type 0x00 // Unused 0x01 0x00 // Number of sectors to load 0x14 0x00 0x00 0x00 // Virtual disk address (in absolute sectors) 20 x 0x00 // Unused 

Puis zéros à la fin du secteur:

 1984 x 0x00 // Unused 

Le prochain secteur est notre bootloader et notre jeu rétro:

 ; to compile: ; nasm bootloader.asm -o bootloader.img [bits 16] ; Pragma, tells the assembler that we ; are in 16 bit mode (which is the state ; of x86 when booting from a floppy). [org 0x7C00] ; Pragma, tell the assembler where the ; code will be loaded. mov bl, 1 ; Starting direction for the worm. push 0xa000 ; Load address of VRAM into es. pop es restart_game: mov si, 320*100+160 ; worm's starting position, center of ; screen ; Set video mode. Mode 13h is VGA (1 byte per pixel with the actual ; color stored in a palette), 320x200 total size. mov ax, 0x0013 int 0x10 ; Draw borders. We assume the default palette will work for us. ; We also assume that starting at the bottom and drawing 2176 pixels ; wraps around and ends up drawing the top + bottom borders. mov di, 320*199 mov cx, 2176 rep draw_loop: stosb ; draw right border stosb ; draw left border add di, 318 jnc draw_loop ; notice the jump in the middle of the ; rep stosb instruction. game_loop: ; We read the keyboard input from port 0x60. This also reads bytes from ; the mouse, so we need to only handle [up (0x48), left (0x4b), ; right (0x4d), down (0x50)] in al, 0x60 cmp al, 0x48 jb kb_handle_end cmp al, 0x50 ja kb_handle_end ; At the end bx contains offset displacement (+1, -1, +320, -320) ; based on pressed/released keypad key. I bet there are a few bytes ; to shave around here given the bounds check above. aaa cbw dec ax dec ax jc kb_handle sub al, 2 imul ax, ax, byte -0x50 kb_handle: mov bx, ax kb_handle_end: add si, bx ; The original code used set pallete command (10h/0bh) to wait for ; the vertical retrace. Today's computers are however too fast, so ; we use int 15h 86h instead. This also shaves a few bytes. ; Note: you'll have to tweak cx+dx if you are running this on a virtual ; machine vs real hardware. Casual testing seems to show that virtual machines ; wait ~3-4x longer than physical hardware. mov ah, 0x86 inc cl int 0x15 ; Draw worm and check for collision with parity ; (even parity=collision). xor [es:si], ah ; Go back to the main game loop. jpo game_loop ; We hit a wall or the worm. Restart the game. jmp restart_game TIMES 2048 - ($ - $$) db 0 ; Fill the rest of the sector with 0 

Ensuite, j'ai écrit un script pour compiler le chargeur de démarrage, créer l'image et générer un tweet. Enfin, j'ai gravé le CD et vérifié que tout fonctionne sur du vrai matériel .

Source: https://habr.com/ru/post/fr419115/


All Articles