-
Notifications
You must be signed in to change notification settings - Fork 90
/
os.lst
655 lines (655 loc) · 45.5 KB
/
os.lst
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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
1 ;
2 ; bootOS, an operating system in 512 bytes
3 ;
4 ; by Oscar Toledo G.
5 ; http://nanochess.org/
6 ;
7 ; Creation date: Jul/21/2019. 6pm 10pm
8 ; Revision date: Jul/22/2019. Optimization, corrections and comments.
9 ; Revision date: Jul/31/2019. Added a service table and allows
10 ; filenames/sources/targets from any segment.
11 ; 'del' command now shows errors.
12 ;
13
14 cpu 8086
15
16 ;
17 ; What is bootOS:
18 ;
19 ; bootOS is a monolithic operating system that fits in
20 ; one boot sector. It's able to load, execute, and save
21 ; programs. Also keeps a filesystem. It can work with
22 ; any floppy disk size starting at 180K.
23 ;
24 ; It relocates itself at 0000:7a00 and requires further
25 ; 768 bytes of memory starting at 0000:7700.
26 ;
27 ; This operating system runs programs as boot sectors
28 ; at 0000:7c00.
29 ;
30 ; It provides the following services:
31 ; int 0x20 Exit to operating system.
32 ; int 0x21 Input key and show in screen.
33 ; Entry: none
34 ; Output: AL = ASCII key pressed.
35 ; Affects: AH/BX/BP.
36 ; int 0x22 Output character to screen.
37 ; Entry: AL = Character.
38 ; Output: none.
39 ; Affects: AH/BX/BP.
40 ; int 0x23 Load file.
41 ; Entry: DS:BX = Filename terminated with zero.
42 ; ES:DI = Point to source data (512 bytes)
43 ; Output: Carry flag = 0 = Found, 1 = Not found.
44 ; Affects: All registers (including ES).
45 ; int 0x24 Save file.
46 ; Entry: DS:BX = Filename terminated with zero.
47 ; ES:DI = Point to data target (512 bytes)
48 ; Output: Carry flag = 0 = Successful. 1 = Error.
49 ; Affects: All registers (including ES).
50 ; int 0x25 Delete file.
51 ; Entry: DS:BX = Filename terminated with zero.
52 ; Affects: All registers (including ES).
53 ;
54 ;
55 ; Filesystem organization:
56 ;
57 ; bootOS uses tracks from 0 to 32, side 0, sector 1.
58 ;
59 ; The directory is contained in track 0, side 0, sector 2.
60 ;
61 ; Each entry in the directory is 16 bytes wide, and
62 ; contains the ASCII name of the file finished with a
63 ; zero byte. A sector has a capacity of 512 bytes, it
64 ; means only 32 files can be kept on a floppy disk.
65 ;
66 ; Deleting a file is a matter of zeroing a whole entry.
67 ;
68 ; Each file is one sector long. Its location in the
69 ; disk is derived from its position in the directory.
70 ;
71 ; The 1st file is located at track 1, side 0, sector 1.
72 ; The 2nd file is located at track 2, side 0, sector 1.
73 ; The 32nd file is located at track 32, side 0, sector 1.
74 ;
75 ;
76 ; Starting bootOS:
77 ;
78 ; Just make sure to write it at the boot sector of a
79 ; floppy disk. It can work with any floppy disk size
80 ; (360K, 720K, 1.2MB and 1.44MB) and it will waste the
81 ; disk space as only uses the first two sectors of the
82 ; disk and then the first sector of each following
83 ; track.
84 ;
85 ; For emulation make sure to deposit it at the start
86 ; of a .img file of 360K, 720K or 1440K. (at least
87 ; VirtualBox detects the type of disk by the length
88 ; of the image file)
89 ;
90 ; For Mac OS X and Linux you can create a 360K image
91 ; in this way:
92 ;
93 ; dd if=/dev/zero of=oszero.img count=719 bs=512
94 ; cat os.img oszero.img >osbase.img
95 ;
96 ; Replace 719 with 1439 for 720K, or 2879 for 1.44M.
97 ;
98 ; Tested with VirtualBox for Mac OS X running Windows XP
99 ; running it, it also works with qemu:
100 ;
101 ; qemu-system-x86_64 -fda os.img
102 ;
103 ; Running bootOS:
104 ;
105 ; The first time you should enter the 'format' command,
106 ; so it initializes the directory. It also copies itself
107 ; again to the boot sector, this is useful to init new
108 ; disks.
109 ;
110 ; bootOS commands:
111 ;
112 ; ver Shows the version (none at the moment)
113 ; dir Shows the directory's content.
114 ; del filename Deletes the "filename" file.
115 ; format As explained before.
116 ; enter Allows to enter up to 512 hexadecimal
117 ; bytes to create another file.
118 ;
119 ; Notice the line size is 128 characters so
120 ; you must break the input into chunks of
121 ; 4, 8 or 16 bytes.
122 ;
123 ; It also allows to copy the last executed
124 ; program just press Enter when the 'h' prompt
125 ; appears and type the new name.
126 ;
127 ; For example: (Character + is Enter key)
128 ;
129 ; $enter+
130 ; hbb 17 7c 8a 07 84 c0 74 0c 53 b4 0e bb 0f 00 cd+
131 ; h10 5b 43 eb ee cd 20 48 65 6c 6c 6f 2c 20 77 6f+
132 ; h72 6c 64 0d 0a 00+
133 ; h+
134 ; *hello+
135 ; $dir+
136 ; hello
137 ; $hello+
138 ; Hello, world
139 ; $
140 ;
141 ; bootOS programs: (Oh yes! we have software support)
142 ;
143 ; fbird https://github.com/nanochess/fbird
144 ; Pillman https://github.com/nanochess/pillman
145 ; invaders https://github.com/nanochess/invaders
146 ; bootBASIC https://github.com/nanochess/bootBASIC
147 ;
148 ; You can copy the machine code directly using the 'enter'
149 ; command, or you can create a file with signature bytes
150 ; with the same command and later copy the binary into the
151 ; .img file using the signature bytes as a clue to locate
152 ; the right position in the image file.
153 ;
154 ; Or you can find a pre-designed disk image along this Git
155 ; with the name osall.img
156 ;
157
158 stack: equ 0x7700 ; Stack pointer (grows to lower addresses)
159 line: equ 0x7780 ; Buffer for line input
160 sector: equ 0x7800 ; Sector data for directory
161 osbase: equ 0x7a00 ; bootOS location
162 boot: equ 0x7c00 ; Boot sector location
163
164 entry_size: equ 16 ; Directory entry size
165 sector_size: equ 512 ; Sector size
166 max_entries: equ sector_size/entry_size
167
168 ;
169 ; Cold start of bootOS
170 ;
171 ; Notice it is loaded at 0x7c00 (boot) and needs to
172 ; relocate itself to 0x7a00 (osbase). The instructions
173 ; between 'start' and 'ver_command' shouldn't depend
174 ; on the assembly location (osbase) because these
175 ; are running at boot location (boot).
176 ;
177 org osbase
178 start:
179 00000000 31C0 xor ax,ax ; Set all segments to zero
180 00000002 8ED8 mov ds,ax
181 00000004 8EC0 mov es,ax
182 00000006 8ED0 mov ss,ax
183 00000008 BC0077 mov sp,stack ; Set stack to guarantee data safety
184
185 0000000B FC cld ; Clear D flag.
186 0000000C BE007C mov si,boot ; Copy bootOS boot sector...
187 0000000F BF007A mov di,osbase ; ...into osbase
188 00000012 B90002 mov cx,sector_size
189 00000015 F3A4 rep movsb
190
191 ; NOTE: we could avoid the need for setting SI here
192 ; by adjusting the length of the copy above, but that
193 ; would break the 'format' command.
194 00000017 BE[E601] mov si,int_0x20 ; SI now points to int_0x20
195 0000001A BF8000 mov di,0x0020*4 ; Address of service for int 0x20
196 0000001D B106 mov cl,6
197 .load_vec:
198 0000001F A5 movsw ; Copy IP address
199 00000020 AB stosw ; Copy CS address
200 00000021 E2FC loop .load_vec
201
202 ;
203 ; 'ver' command
204 ;
205 ver_command:
206 00000023 BE[B401] mov si,intro
207 print_then_restart:
208 00000026 E83E01 call output_string
209 00000029 CD20 int int_restart ; Restart bootOS
210
211 ;
212 ; Warm start of bootOS
213 ;
214 restart:
215 0000002B FC cld ; Clear D flag.
216 0000002C 0E push cs ; Reinit all segment registers
217 0000002D 0E push cs
218 0000002E 0E push cs
219 0000002F 1F pop ds
220 00000030 07 pop es
221 00000031 17 pop ss
222 00000032 BC0077 mov sp,stack ; Restart stack
223
224 00000035 B024 mov al,'$' ; Command prompt
225 00000037 E8FE00 call input_line ; Input line
226
227 0000003A 803C00 cmp byte [si],0x00 ; Empty line?
228 0000003D 74EC je restart ; Yes, get another line
229
230 0000003F BF[C001] mov di,commands ; Point to commands list
231
232 ; Notice that filenames starting with same characters
233 ; won't be recognized as such (so file dirab cannot be
234 ; executed).
235 os11:
236 00000042 8A0D mov cl,[di] ; Read length of command in chars
237 00000044 47 inc di
238 00000045 30ED xor ch, ch ; Also makes sure that ZF = 1
239 00000047 56 push si ; Save current position
240 00000048 F3A6 rep cmpsb ; Compare statement
241 0000004A 7504 jne os14 ; Equal? No, jump
242 0000004C FF15 call word [di] ; Call command process
243 0000004E EBDB jmp restart ; Go to expect another command
244
245 00000050 01CF os14: add di,cx ; Advance the list pointer
246 00000052 AF scasw ; Avoid the address
247 00000053 5E pop si
248 00000054 EBEC jmp os11 ; Compare another statement
249
250 exec_from_disk:
251 00000056 5B pop bx
252 00000057 5B pop bx
253 00000058 BF007C mov di,boot ; Location to read data
254 0000005B CD23 int int_load_file ; Load file
255 0000005D 7202 jc os7 ; Jump if error
256 0000005F FFE3 jmp bx
257
258 ;
259 ; File not found error
260 ;
261 os7:
262 00000061 BE[BB01] mov si,error_message
263 00000064 EBC0 jmp print_then_restart
264
265 ;
266 ; >> COMMAND <<
267 ; del filename
268 ;
269 del_command:
270 os22:
271 00000066 89F3 mov bx,si ; Copy SI (buffer pointer) to BX
272 00000068 AC lodsb
273 00000069 3C20 cmp al,0x20 ; Avoid spaces
274 0000006B 74F9 je os22
275 0000006D CD25 int int_delete_file
276 0000006F 72F0 jc os7
277 00000071 C3 ret
278
279 ;
280 ; 'dir' command
281 ;
282 dir_command:
283 00000072 E8A000 call read_dir ; Read the directory
284 00000075 89DF mov di,bx
285 os18:
286 00000077 803D00 cmp byte [di],0 ; Empty entry?
287 0000007A 7405 je os17 ; Yes, jump
288 0000007C 89FE mov si,di ; Point to data
289 0000007E E8E600 call output_string ; Show name
290 00000081 E86E00 os17: call next_entry
291 00000084 75F1 jne os18 ; No, jump
292 00000086 C3 ret ; Return
293
294 ;
295 ; Get filename length and prepare for directory lookup
296 ; Entry:
297 ; si = pointer to string
298 ; Output:
299 ; si = unaffected
300 ; di = pointer to start of directory
301 ; cx = length of filename including zero terminator
302 ;
303 filename_length:
304 00000087 56 push si
305 00000088 31C9 xor cx,cx ; cx = 0
306 .loop:
307 0000008A AC lodsb ; Read character.
308 0000008B 41 inc cx ; Count character.
309 0000008C 3C00 cmp al,0 ; Is it zero (end character)?
310 0000008E 75FA jne .loop ; No, jump.
311
312 00000090 5E pop si
313 00000091 BF0078 mov di,sector ; Point to start of directory.
314 00000094 C3 ret
315
316 ;
317 ; >> SERVICE <<
318 ; Load file
319 ;
320 ; Entry:
321 ; ds:bx = Pointer to filename ended with zero byte.
322 ; es:di = Destination.
323 ; Output:
324 ; Carry flag = Set = not found, clear = successful.
325 ;
326 load_file:
327 00000095 57 push di ; Save destination
328 00000096 06 push es
329 00000097 E84000 call find_file ; Find the file (sanitizes ES)
330 0000009A B402 mov ah,0x02 ; Read sector
331 shared_file:
332 0000009C 07 pop es
333 0000009D 5B pop bx ; Restore destination on BX
334 0000009E 7203 jc ret_cf ; Jump if error
335 000000A0 E88400 call disk ; Do operation with disk
336 ; Carry guaranteed to be clear.
337 ret_cf:
338 000000A3 89E5 mov bp,sp
339 000000A5 D05604 rcl byte [bp+4],1 ; Insert Carry flag in Flags (automatic usage of SS)
340 000000A8 CF iret
341
342 ;
343 ; >> SERVICE <<
344 ; Save file
345 ;
346 ; Entry:
347 ; ds:bx = Pointer to filename ended with zero byte.
348 ; es:di = Source.
349 ; Output:
350 ; Carry flag = Set = error, clear = good.
351 ;
352 save_file:
353 000000A9 57 push di ; Save origin
354 000000AA 06 push es
355 000000AB 53 push bx ; Save filename pointer
356 000000AC CD25 int int_delete_file ; Delete previous file (sanitizes ES)
357 000000AE 5B pop bx ; Restore filename pointer
358 000000AF E8D5FF call filename_length ; Prepare for lookup
359
360 000000B2 26803D00 .find: es cmp byte [di],0 ; Found empty directory entry?
361 000000B6 7407 je .empty ; Yes, jump and fill it.
362 000000B8 E83700 call next_entry
363 000000BB 75F5 jne .find
364 000000BD EBDD jmp shared_file
365
366 000000BF 57 .empty: push di
367 000000C0 F3A4 rep movsb ; Copy full name into directory
368 000000C2 E85A00 call write_dir ; Save directory
369 000000C5 5F pop di
370 000000C6 E83200 call get_location ; Get location of file
371 000000C9 B403 mov ah,0x03 ; Write sector
372 000000CB EBCF jmp shared_file
373
374 ;
375 ; >> SERVICE <<
376 ; Delete file
377 ;
378 ; Entry:
379 ; ds:bx = Pointer to filename ended with zero byte.
380 ; Output:
381 ; Carry flag = Set = not found, clear = deleted.
382 ;
383 delete_file:
384 000000CD E80A00 call find_file ; Find file (sanitizes ES)
385 000000D0 72D1 jc ret_cf ; If carry set then not found, jump.
386 000000D2 B91000 mov cx,entry_size
387 000000D5 E84300 call write_zero_dir ; Fill whole entry with zero. Write directory.
388 000000D8 EBC9 jmp ret_cf
389
390 ;
391 ; Find file
392 ;
393 ; Entry:
394 ; ds:bx = Pointer to filename ended with zero byte.
395 ; Output:
396 ; es:di = Pointer to directory entry
397 ; Carry flag = Clear if found, set if not found.
398 find_file:
399 000000DA 53 push bx
400 000000DB E83700 call read_dir ; Read directory (sanitizes ES)
401 000000DE 5E pop si
402 000000DF E8A5FF call filename_length ; Get filename length and setup DI
403 os6:
404 000000E2 56 push si
405 000000E3 57 push di
406 000000E4 51 push cx
407 000000E5 F3A6 repe cmpsb ; Compare name with entry
408 000000E7 59 pop cx
409 000000E8 5F pop di
410 000000E9 5E pop si
411 000000EA 740F je get_location ; Jump if equal.
412 000000EC E80300 call next_entry
413 000000EF 75F1 jne os6 ; No, jump
414 000000F1 C3 ret ; Return
415
416 next_entry:
417 000000F2 83C710 add di,byte entry_size ; Go to next entry.
418 000000F5 81FF007A cmp di,sector+sector_size ; Complete directory?
419 000000F9 F9 stc ; Error, not found.
420 000000FA C3 ret
421
422 ;
423 ; Get location of file on disk
424 ;
425 ; Entry:
426 ; DI = Pointer to entry in directory.
427 ;
428 ; Output:
429 ; CH = Track number in disk.
430 ; CL = Sector (always 0x01).
431 ;
432 ; The position of a file inside the disk depends on its
433 ; position in the directory. The first entry goes to
434 ; track 1, the second entry to track 2 and so on.
435 ;
436 get_location:
437 000000FB 8D851088 lea ax,[di-(sector-entry_size)] ; Get entry pointer into directory
438 ; Plus one entry (files start on track 1)
439 000000FF B104 mov cl,4 ; 2^(8-4) = entry_size
440 00000101 D3E0 shl ax,cl ; Shift left and clear Carry flag
441 00000103 40 inc ax ; AL = Sector 1
442 00000104 91 xchg ax,cx ; CH = Track, CL = Sector
443 00000105 C3 ret
444
445 ;
446 ; >> COMMAND <<
447 ; format
448 ;
449 format_command:
450 00000106 BF0078 mov di,sector ; Fill whole sector to zero
451 00000109 B90002 mov cx,sector_size
452 0000010C E80C00 call write_zero_dir
453 0000010F BB007A mov bx,osbase ; Copy bootOS onto first sector
454 00000112 49 dec cx
455 00000113 EB12 jmp short disk
456
457 ;
458 ; Read the directory from disk
459 ;
460 read_dir:
461 00000115 0E push cs ; bootOS code segment...
462 00000116 07 pop es ; ...to sanitize ES register
463 00000117 B402 mov ah,0x02
464 00000119 EB06 jmp short disk_dir
465
466 write_zero_dir:
467 0000011B B000 mov al,0
468 0000011D F3AA rep stosb
469
470 ;
471 ; Write the directory to disk
472 ;
473 write_dir:
474 0000011F B403 mov ah,0x03
475 disk_dir:
476 00000121 BB0078 mov bx,sector
477 00000124 B90200 mov cx,0x0002
478 ;
479 ; Do disk operation.
480 ;
481 ; Input:
482 ; AH = 0x02 read disk, 0x03 write disk
483 ; ES:BX = data source/target
484 ; CH = Track number
485 ; CL = Sector number
486 ;
487 disk:
488 00000127 50 push ax
489 00000128 53 push bx
490 00000129 51 push cx
491 0000012A 06 push es
492 0000012B B001 mov al,0x01 ; AL = 1 sector
493 0000012D 31D2 xor dx,dx ; DH = Drive A. DL = Head 0.
494 0000012F CD13 int 0x13
495 00000131 07 pop es
496 00000132 59 pop cx
497 00000133 5B pop bx
498 00000134 58 pop ax
499 00000135 72F0 jc disk ; Retry
500 00000137 C3 ret
501
502 ;
503 ; Input line from keyboard
504 ; Entry:
505 ; al = prompt character
506 ; Output:
507 ; buffer 'line' contains line, finished with CR
508 ; SI points to 'line'.
509 ;
510 input_line:
511 00000138 CD22 int int_output_char ; Output prompt character
512 0000013A BE8077 mov si,line ; Setup SI and DI to start of line buffer
513 0000013D 89F7 mov di,si ; Target for writing line
514 0000013F 3C08 os1: cmp al,0x08 ; Backspace?
515 00000141 7502 jne os2
516 00000143 4F dec di ; Undo the backspace write
517 00000144 4F dec di ; Erase a character
518 00000145 CD21 os2: int int_input_key ; Read keyboard
519 00000147 3C0D cmp al,0x0d ; CR pressed?
520 00000149 7502 jne os10
521 0000014B B000 mov al,0x00
522 0000014D AA os10: stosb ; Save key in buffer
523 0000014E 75EF jne os1 ; No, wait another key
524 00000150 C3 ret ; Yes, return
525
526 ;
527 ; Read a key into al
528 ; Also outputs it to screen
529 ;
530 input_key:
531 00000151 B400 mov ah,0x00
532 00000153 CD16 int 0x16
533 ;
534 ; Screen output of character contained in al
535 ; Expands 0x0d (CR) into 0x0a 0x0d (LF CR)
536 ;
537 output_char:
538 00000155 3C0D cmp al,0x0d
539 00000157 7506 jne os3
540 00000159 B00A mov al,0x0a
541 0000015B CD22 int int_output_char
542 0000015D B00D mov al,0x0d
543 os3:
544 0000015F B40E mov ah,0x0e ; Output character to TTY
545 00000161 BB0700 mov bx,0x0007 ; Gray. Required for graphic modes
546 00000164 CD10 int 0x10 ; BIOS int 0x10 = Video
547 00000166 CF iret
548
549 ;
550 ; Output string
551 ;
552 ; Entry:
553 ; SI = address
554 ;
555 ; Implementation:
556 ; It assumes that SI never points to a zero length string.
557 ;
558 output_string:
559 00000167 AC lodsb ; Read character
560 00000168 CD22 int int_output_char ; Output to screen
561 0000016A 3C00 cmp al,0x00 ; Is it 0x00 (terminator)?
562 0000016C 75F9 jne output_string ; No, the loop continues
563 0000016E B00D mov al,0x0d
564 00000170 CD22 int int_output_char
565 00000172 C3 ret
566
567 ;
568 ; 'enter' command
569 ;
570 enter_command:
571 00000173 BF007C mov di,boot ; Point to boot sector
572 00000176 57 os23: push di
573 00000177 B068 mov al,'h' ; Prompt character
574 00000179 E8BCFF call input_line ; Input line
575 0000017C 5F pop di
576 0000017D 803C00 cmp byte [si],0 ; Empty line?
577 00000180 7412 je os20 ; Yes, jump
578 00000182 E81C00 os19: call xdigit ; Get a hexadecimal digit
579 00000185 73EF jnc os23
580 00000187 B104 mov cl,4
581 00000189 D2E0 shl al,cl
582 0000018B 91 xchg ax,cx
583 0000018C E81200 call xdigit ; Get a hexadecimal digit
584 0000018F 08C8 or al,cl
585 00000191 AA stosb ; Write one byte
586 00000192 EBEE jmp os19 ; Repeat loop to complete line
587 os20:
588 00000194 B02A mov al,'*' ; Prompt character
589 00000196 E89FFF call input_line ; Input line with filename
590 00000199 56 push si
591 0000019A 5B pop bx
592 0000019B BF007C mov di,boot ; Point to data entered
593 0000019E CD24 int int_save_file ; Save new file
594 000001A0 C3 ret
595
596 ;
597 ; Convert ASCII letter to hexadecimal digit
598 ;
599 xdigit:
600 000001A1 AC lodsb
601 000001A2 3C00 cmp al,0x00 ; Zero character marks end of line
602 000001A4 740D je os15
603 000001A6 2C30 sub al,0x30 ; Avoid spaces (anything below ASCII 0x30)
604 000001A8 72F7 jc xdigit
605 000001AA 3C0A cmp al,0x0a
606 000001AC 7205 jc os15
607 000001AE 2C07 sub al,0x07
608 000001B0 240F and al,0x0f
609 000001B2 F9 stc
610 os15:
611 000001B3 C3 ret
612
613 ;
614 ; Our amazing presentation line
615 ;
616 intro:
617 000001B4 626F6F744F5300 db "bootOS",0
618
619 error_message:
620 000001BB 4F6F707300 db "Oops",0
621
622 ;
623 ; Commands supported by bootOS
624 ;
625 commands:
626 000001C0 03646972 db 3,"dir"
627 000001C4 [7200] dw dir_command
628 000001C6 06666F726D6174 db 6,"format"
629 000001CD [0601] dw format_command
630 000001CF 05656E746572 db 5,"enter"
631 000001D5 [7301] dw enter_command
632 000001D7 0364656C db 3,"del"
633 000001DB [6600] dw del_command
634 000001DD 03766572 db 3,"ver"
635 000001E1 [2300] dw ver_command
636 000001E3 00 db 0
637 000001E4 [5600] dw exec_from_disk
638
639 int_restart: equ 0x20
640 int_input_key: equ 0x21
641 int_output_char: equ 0x22
642 int_load_file: equ 0x23
643 int_save_file: equ 0x24
644 int_delete_file: equ 0x25
645
646 int_0x20:
647 000001E6 [2B00] dw restart ; int 0x20
648 000001E8 [5101] dw input_key ; int 0x21
649 000001EA [5501] dw output_char ; int 0x22
650 000001EC [9500] dw load_file ; int 0x23
651 000001EE [A900] dw save_file ; int 0x24
652 000001F0 [CD00] dw delete_file ; int 0x25
653
654 000001F2 4F<rep Ch> times 510-($-$$) db 0x4f
655 000001FE 55AA db 0x55,0xaa ; Make it a bootable sector