* remove "\r" nonsense
[mascara-docs.git] / amd64 / bareMetalOS-0.5.2 / baremetal0.5.2 / os / drivers / fat16.asm
blobd09bc1c6bcd7554818d33c3b019d3d14eb7a2de7
1 ; =============================================================================
2 ; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3 ; Copyright (C) 2008-2011 Return Infinity -- see LICENSE.TXT
5 ; FAT16 Functions
6 ; =============================================================================
8 align 16
9 db 'DEBUG: FAT16 '
10 align 16
13 ; -----------------------------------------------------------------------------
14 ; os_fat16_read_cluster -- Read a cluster from the FAT16 partition
15 ; IN: AX = Cluster # to read
16 ; RDI = Memory location to store at least 32KB
17 ; OUT: AX = Next cluster in chain (0xFFFF if this was the last)
18 ; RDI = Points one byte after the last byte read
19 os_fat16_read_cluster:
20 push rsi
21 push rdx
22 push rcx
23 push rbx
25 and rax, 0x000000000000FFFF ; Clear the top 48 bits
26 mov rbx, rax ; Save the cluster number to be used later
28 cmp ax, 2 ; If less than 2 then bail out...
29 jl near os_fat16_read_cluster_bailout ; as clusters start at 2
31 ; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start
32 xor rcx, rcx
33 mov cl, byte [fat16_SectorsPerCluster]
34 push rcx ; Save the number of sectors per cluster
35 sub ax, 2
36 imul cx ; EAX now holds starting sector
37 add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts
38 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
40 pop rcx ; Restore the number of sectors per cluster
41 call readsectors ; Read one cluster of sectors
43 ; Calculate the next cluster
44 ; Psuedo-code
45 ; tint1 = Cluster / 256 <- Dump the remainder
46 ; sector_to_read = tint1 + ReservedSectors
47 ; tint2 = (Cluster - (tint1 * 256)) * 2
48 push rdi
49 mov rdi, secbuffer1 ; Read to this temporary buffer
50 mov rsi, rdi ; Copy buffer address to RSI
51 push rbx ; Save the original cluster value
52 shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder
53 movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT
54 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
55 add rax, rbx ; Add the sector offset
56 mov rcx, 1
57 call readsectors
58 pop rax ; Get our original cluster value back
59 shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT)
60 sub rax, rbx ; RAX is now pointed to the offset within the sector
61 shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit)
62 add rsi, rax
63 lodsw ; AX now holds the next cluster
64 pop rdi
66 jmp os_fat16_read_cluster_end
68 os_fat16_read_cluster_bailout:
69 xor ax, ax
71 os_fat16_read_cluster_end:
72 pop rbx
73 pop rcx
74 pop rdx
75 pop rsi
76 ret
77 ; -----------------------------------------------------------------------------
80 ; -----------------------------------------------------------------------------
81 ; os_fat16_write_cluster -- Write a cluster to the FAT16 partition
82 ; IN: AX = Cluster # to write to
83 ; RSI = Memory location of data to write
84 ; OUT: AX = Next cluster in the chain (set to 0xFFFF if this was the last cluster of the chain)
85 ; RSI = Points one byte after the last byte written
86 os_fat16_write_cluster:
87 push rdi
88 push rdx
89 push rcx
90 push rbx
92 and rax, 0x000000000000FFFF ; Clear the top 48 bits
93 mov rbx, rax ; Save the cluster number to be used later
95 cmp ax, 2 ; If less than 2 then bail out...
96 jl near os_fat16_write_cluster_bailout ; as clusters start at 2
98 ; Calculate the LBA address --- startingsector = (cluster-2) * clustersize + data_start
99 xor rcx, rcx
100 mov cl, byte [fat16_SectorsPerCluster]
101 push rcx ; Save the number of sectors per cluster
102 sub ax, 2
103 imul cx ; EAX now holds starting sector
104 add eax, dword [fat16_DataStart] ; EAX now holds the sector where our cluster starts
105 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
107 pop rcx ; Restore the number of sectors per cluster
108 call writesectors
110 ; Calculate the next cluster
111 push rsi
112 mov rdi, secbuffer1 ; Read to this temporary buffer
113 mov rsi, rdi ; Copy buffer address to RSI
114 push rbx ; Save the original cluster value
115 shr rbx, 8 ; Divide the cluster value by 256. Keep no remainder
116 movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT
117 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
118 add rax, rbx ; Add the sector offset
119 mov rcx, 1
120 call readsectors
121 pop rax ; Get our original cluster value back
122 shl rbx, 8 ; Quick multiply by 256 (RBX was the sector offset in the FAT)
123 sub rax, rbx ; RAX is now pointed to the offset within the sector
124 shl rax, 1 ; Quickly multiply by 2 (since entries are 16-bit)
125 add rsi, rax
126 lodsw ; AX now holds the next cluster
127 pop rsi
129 jmp os_fat16_write_cluster_done
131 os_fat16_write_cluster_bailout:
132 xor ax, ax
134 os_fat16_write_cluster_done:
135 pop rbx
136 pop rcx
137 pop rdx
138 pop rdi
140 ; -----------------------------------------------------------------------------
143 ; -----------------------------------------------------------------------------
144 ; os_fat16_find_file -- Search for a file name and return the starting cluster
145 ; IN: RSI = Pointer to file name, must be in 'FILENAMEEXT' format
146 ; OUT: AX = Staring cluster
147 ; ECX = File size
148 ; Carry set if not found. If carry is set then ignore value in AX
149 os_fat16_find_file:
150 push rsi
151 push rdi
152 push rdx
153 push rbx
155 clc ; Clear carry
156 xor rax, rax
157 mov eax, [fat16_RootStart] ; eax points to the first sector of the root
158 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
159 mov rdx, rax ; Save the sector value
161 os_fat16_find_file_read_sector:
162 mov rdi, hdbuffer1
163 push rdi
164 mov rcx, 1
165 call readsectors
166 pop rdi
167 mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16
169 os_fat16_find_file_next_entry:
170 cmp byte [rdi], 0x00 ; end of records
171 je os_fat16_find_file_notfound
173 mov rcx, 11
174 push rsi
175 repe cmpsb
176 pop rsi
177 mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at
178 mov ecx, [rdi+17] ; ECX now holds the size of the file in bytes
179 jz os_fat16_find_file_done ; The file was found. Note that rdi now is at dirent+11
181 add rdi, byte 0x20
182 and rdi, byte -0x20
183 dec rbx
184 cmp rbx, 0
185 jne os_fat16_find_file_next_entry
187 ; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector.
189 add rdx, 1
190 mov rax, rdx
191 jmp os_fat16_find_file_read_sector
193 os_fat16_find_file_notfound:
194 stc ; Set carry
195 xor rax, rax
197 os_fat16_find_file_done:
198 cmp ax, 0x0000 ; BUG HERE
199 jne wut ; Carry is not being set properly in this function
201 wut:
202 pop rbx
203 pop rdx
204 pop rdi
205 pop rsi
207 ; -----------------------------------------------------------------------------
210 ; -----------------------------------------------------------------------------
211 ; os_fat16_get_file_list -- Generate a list of files on disk
212 ; IN: RDI = location to store list
213 ; OUT: RDI = pointer to end of list
214 os_fat16_get_file_list:
215 push rsi
216 push rdi
217 push rcx
218 push rbx
219 push rax
221 push rsi
222 mov rsi, dir_title_string
223 call os_string_length
224 call os_string_copy ; Copy the header
225 add rdi, rcx
226 pop rsi
228 xor rbx, rbx
229 mov ebx, [fat16_RootStart] ; ebx points to the first sector of the root
230 add ebx, [fat16_PartitionOffset] ; Add the offset to the partition
232 jmp os_fat16_get_file_list_read_sector
234 os_fat16_get_file_list_next_sector:
235 add rbx, 1
237 os_fat16_get_file_list_read_sector:
238 push rdi
239 mov rdi, hdbuffer1
240 mov rsi, rdi
241 mov rcx, 1
242 mov rax, rbx
243 call readsectors
244 pop rdi
246 ; RDI = location of string
247 ; RSI = buffer that contains the cluster
249 ; start reading
250 os_fat16_get_file_list_read:
251 cmp rsi, hdbuffer1+512
252 je os_fat16_get_file_list_next_sector
253 cmp byte [rsi], 0x00 ; end of records
254 je os_fat16_get_file_list_done
255 cmp byte [rsi], 0xE5 ; unused record
256 je os_fat16_get_file_list_skip
258 mov al, [rsi + 8] ; Grab the attribute byte
259 bt ax, 5 ; check if bit 3 is set (volume label)
260 jc os_fat16_get_file_list_skip ; if so skip the entry
261 mov al, [rsi + 11] ; Grab the attribute byte
262 cmp al, 0x0F ; Check if it is a LFN entry
263 je os_fat16_get_file_list_skip ; if so skip the entry
265 ; copy the string
266 xor rcx, rcx
267 xor rax, rax
268 os_fat16_get_file_list_copy:
269 mov al, [rsi+rcx]
270 stosb ; Store to RDI
271 inc rcx
272 cmp rcx, 8
273 jne os_fat16_get_file_list_copy
275 mov al, ' ' ; Store a space as the separtator
276 stosb
278 mov al, [rsi+8]
279 stosb
280 mov al, [rsi+9]
281 stosb
282 mov al, [rsi+10]
283 stosb
285 mov al, ' ' ; Store a space as the separtator
286 stosb
288 mov eax, [rsi+0x1C]
289 call os_int_to_string
290 dec rdi
291 mov al, 13
292 stosb
294 os_fat16_get_file_list_skip:
295 add rsi, 32
296 jmp os_fat16_get_file_list_read
298 os_fat16_get_file_list_done:
299 mov al, 0x00
300 stosb
302 pop rax
303 pop rbx
304 pop rcx
305 pop rdi
306 pop rsi
309 dir_title_string: db "Name Ext Size", 13, "====================", 13, 0
310 ; -----------------------------------------------------------------------------
313 ; -----------------------------------------------------------------------------
314 ; os_fat16_file_read -- Read a file from disk into memory
315 ; IN: RSI = Address of filename string
316 ; RDI = Memory location where file will be loaded to
317 ; OUT: Carry clear on success, set if file was not found or error occured
318 os_fat16_file_read:
319 push rsi
320 push rdi
321 push rcx ; Used by os_fat16_find_file
322 push rax
324 ; Convert the file name to FAT format
325 push rdi ; Save the memory address
326 mov rdi, os_fat16_file_read_string
327 call os_fat16_filename_convert ; Convert the filename to the proper FAT format
328 xchg rsi, rdi
329 pop rdi ; Grab the memory address
330 jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted
332 ; Check to see if the file exists
333 call os_fat16_find_file ; Fuction will return the starting cluster value in AX or carry set if not found
334 jc os_fat16_file_read_done ; If Carry is clear then the file exists. AX is set to the starting cluster
336 os_fat16_file_read_read:
337 call os_fat16_read_cluster ; Store cluster in memory. AX is set to the next cluster
338 cmp ax, 0xFFFF ; 0xFFFF is the FAT end of file marker
339 jne os_fat16_file_read_read ; Are there more clusters? If so then read again.. if not fall through
340 clc ; Clear Carry
342 os_fat16_file_read_done:
343 pop rax
344 pop rcx
345 pop rdi
346 pop rsi
349 os_fat16_file_read_string times 13 db 0
350 ; -----------------------------------------------------------------------------
353 ; -----------------------------------------------------------------------------
354 ; os_fat16_file_write -- Write a file to the hard disk
355 ; IN: RSI = Address of data in memory
356 ; RDI = File name to write
357 ; RCX = number of bytes to write
358 ; OUT: Carry clear on success, set on failure
359 os_fat16_file_write:
360 push rsi
361 push rdi
362 push rcx
363 push rax
365 mov [memory_address], rsi ; Save the memory address
367 ; Convert the file name to FAT format
368 mov rsi, rdi ; Move the file name address into RSI
369 mov rdi, os_fat16_file_write_string
370 call os_fat16_filename_convert ; Convert the filename to the proper FAT format
371 jc os_fat16_file_write_done ; Fail (Invalid file name)
373 ; Check to see if a file already exists with the same name
374 mov rsi, os_fat16_file_write_string
375 push rcx
376 call os_fat16_find_file ; Returns the starting cluster in AX or carry set if it doesn't exist
377 pop rcx
378 jc os_fat16_file_write_create ; Jump if the file doesn't exist (No need to delete it)
379 jmp os_fat16_file_write_done ; call os_fat16_file_delete
381 ; At this point the file doesn't exist so create it.
382 os_fat16_file_write_create:
383 xchg bx, bx
384 call os_fat16_file_create
385 jc os_fat16_file_write_done ; Fail (Couldn't create the file)
386 call os_fat16_find_file ; Call this to get the starting cluster
387 jc os_fat16_file_write_done ; Fail (File was supposed to be created but wasn't)
389 ; We are ready to start writing. First cluster is in AX
390 mov rsi, [memory_address]
391 os_fat16_file_write_write:
392 call os_fat16_write_cluster
393 cmp ax, 0xFFFF
394 jne os_fat16_file_write_write
397 os_fat16_file_write_done:
398 pop rax
399 pop rcx
400 pop rdi
401 pop rsi
404 os_fat16_file_write_string times 13 db 0
405 memory_address dq 0x0000000000000000
406 ; -----------------------------------------------------------------------------
409 ; -----------------------------------------------------------------------------
410 ; os_fat16_file_create -- Create a file on the hard disk
411 ; IN: RSI = Pointer to file name, must be in FAT 'FILENAMEEXT' format
412 ; RCX = File size
413 ; OUT: Carry clear on success, set on failure
414 ; Note: This function pre-allocates all clusters required for the size of the file
415 os_fat16_file_create:
416 push rsi
417 push rdi
418 push rdx
419 push rcx
420 push rbx
421 push rax
423 clc ; Clear the carry flag. It will be set if there is an error
425 mov [filesize], ecx ; Save file size for later
426 mov [filename], rsi
428 ; Check to see if a file already exists with the same name
429 ; call os_fat16_find_file
430 ; jc os_fat16_file_create_fail ; Fail (File already exists)
432 ; How many clusters will we need?
433 mov rax, rcx
434 xor rdx, rdx
435 xor rbx, rbx
436 mov bl, byte [fat16_SectorsPerCluster]
437 shl rbx, 9 ; Multiply by 512 to get bytes per cluster
438 div rbx
439 cmp rdx, 0
440 jg add_a_bit ; If there's a remainder, we need another cluster
441 jmp carry_on
442 add_a_bit:
443 add rax, 1
444 carry_on:
445 mov rcx, rax ; RCX holds number of clusters that are needed
447 ; Allocate all of the clusters required for the amount of bytes we are writting.
448 xor rax, rax
449 mov ax, [fat16_ReservedSectors] ; First sector of the first FAT
450 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
451 mov rdi, hdbuffer0
452 mov rsi, rdi
453 push rcx
454 mov rcx, 64
455 call readsectors
456 pop rcx
457 xor rdx, rdx ; cluster we are currently at
458 xor rbx, rbx ; cluster marker
459 findfirstfreeclust:
460 mov rdi, rsi
461 lodsw
462 inc dx ; counter
463 cmp ax, 0x0000
464 jne findfirstfreeclust ; Continue until we find a free cluster
465 dec dx
466 mov [startcluster], dx ; Save the starting cluster ID
467 inc dx
468 mov bx, dx
469 cmp rcx, 0
470 je clusterdone
471 cmp rcx, 1
472 je clusterdone
474 findnextfreecluster:
475 lodsw
476 inc dx
477 cmp ax, 0x0000
478 jne findnextfreecluster
479 mov ax, bx
480 mov bx, dx
481 stosw
482 mov rdi, rsi
483 sub rdi, 2
484 dec rcx
485 cmp rcx, 1
486 jne findnextfreecluster
488 clusterdone:
489 mov ax, 0xFFFF
490 stosw
491 ; push dx ; save the free cluster number
492 ; inc rbx
493 ; cmp rbx, rcx ; Have we found enough free clusters?
494 ; jne nextclust ; If not keep going, if yes fall through
495 ; At this point we have free cluster ID's on the stack
497 ; mov ax, 0xFFFF
501 ; At this point we have a sector of FAT in hdbuffer0. A cluster has been marked in use but the sector is not written back to disk yet!
502 ; Save the sector # as we will write this to disk later
504 ; Load the first sector of the file info table
505 xor rax, rax
506 mov eax, [fat16_RootStart] ; eax points to the first sector of the root
507 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
508 mov rdi, hdbuffer1
509 push rdi
510 mov rcx, 1
511 call readsectors
512 pop rdi
513 mov rcx, 16 ; records / sector
514 mov rsi, rdi
515 nextrecord:
516 sub rcx, 1
517 cmp byte [rsi], 0x00 ; Empty record
518 je foundfree
519 cmp byte [rsi], 0xE5 ; Unused record
520 je foundfree
521 add rsi, 32 ; Each record is 32 bytes
522 cmp rcx, 0
523 je os_fat16_file_create_fail
524 jmp nextrecord
526 foundfree:
527 ; At this point RSI points to the start of the record
528 mov rdi, rsi
529 mov rsi, [filename]
530 mov rcx, 11
531 nextchar:
532 lodsb
533 stosb
534 sub rcx, 1
535 cmp rcx, 0
536 jne nextchar
537 xor rax, rax
538 stosb ; LFN Attrib
539 stosb ; NT Reserved
540 stosw ; Create time
541 stosb ; Create time
542 stosw ; Create date
543 stosw ; Access date
544 stosw ; Access time
545 stosw ; Modified time
546 stosw ; Modified date
547 mov ax, [startcluster]
548 stosw
549 mov eax, [filesize]
550 stosd ; File size
552 ; At this point the updated file record is in memory at hdbuffer1
554 xor rax, rax
556 movzx ax, [fat16_ReservedSectors] ; First sector of the first FAT
557 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
558 mov rsi, hdbuffer0
559 mov rcx, 64
560 call writesectors
562 mov eax, [fat16_RootStart] ; eax points to the first sector of the root
563 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
564 mov rsi, hdbuffer1
565 mov rcx, 1
566 call writesectors
568 jmp os_fat16_file_create_done
570 os_fat16_file_create_fail:
572 call os_speaker_beep
574 os_fat16_file_create_done:
575 pop rax
576 pop rbx
577 pop rcx
578 pop rdx
579 pop rdi
580 pop rsi
583 ; newfile_string times 13 db 0
584 startcluster dw 0x0000
585 filesize dd 0x00000000
586 filename dq 0x0000000000000000
587 ; -----------------------------------------------------------------------------
590 ; -----------------------------------------------------------------------------
591 ; os_fat16_file_delete -- Delete a file from the hard disk
592 ; IN: RSI = File name to delete
593 ; OUT: Carry clear on success, set on failure
594 os_fat16_file_delete:
595 push rsi
596 push rdi
597 push rdx
598 push rcx
599 push rbx
601 clc ; Clear carry
602 xor rax, rax
603 mov eax, [fat16_RootStart] ; eax points to the first sector of the root
604 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
605 mov rdx, rax ; Save the sector value
607 ; Convert the file name to FAT format
608 mov rdi, os_fat16_file_delete_string
609 call os_fat16_filename_convert ; Convert the filename to the proper FAT format
610 jc os_fat16_file_delete_error ; Fail (Invalid file name)
611 mov rsi, rdi
613 ; Read through the root cluster (if file not found bail out)
614 os_fat16_file_delete_read_sector:
615 mov rdi, hdbuffer0
616 push rdi
617 mov rcx, 1
618 call readsectors
619 pop rdi
620 mov rbx, 16 ; Each record is 32 bytes. 512 (bytes per sector) / 32 = 16
622 os_fat16_file_delete_next_entry:
623 cmp byte [rdi], 0x00 ; end of records
624 je os_fat16_file_delete_error
626 mov rcx, 11
627 push rsi
628 repe cmpsb
629 pop rsi
630 mov ax, [rdi+15] ; AX now holds the starting cluster # of the file we just looked at
631 jz os_fat16_file_delete_found ; The file was found. Note that rdi now is at dirent+11
633 add rdi, byte 0x20 ; Great little trick here. Add 32 ...
634 and rdi, byte -0x20 ; ... and then round backwards to a 32-byte barrier. Sets RDI to the start of the next record
635 dec rbx
636 cmp rbx, 0
637 jne os_fat16_file_delete_next_entry
639 ; At this point we have read though one sector of file names. We have not found the file we are looking for and have not reached the end of the table. Load the next sector.
640 add rdx, 1 ; We are about to read the next sector so increment the counter
641 mov rax, rdx
642 jmp os_fat16_file_delete_read_sector
644 ; Mark the file as deleted (set first byte of file name to 0xE5) and write the sector back to the drive
645 os_fat16_file_delete_found:
646 xor rbx, rbx
647 mov bx, ax ; Save the starting cluster value
648 and rdi, byte -0x20 ; Round backward to get to the start of the record
649 mov al, 0xE5 ; Set the first character of the filename to this
650 stosb
651 mov rsi, hdbuffer0
652 mov rax, rdx ; Retrieve the sector number
653 mov rcx, 1
654 call writesectors
656 ; Follow cluster chain and set any cluster in the chain to 0x0000 (mark as free)
657 xor rax, rax
658 mov ax, [fat16_ReservedSectors] ; First sector of the first FAT
659 add eax, [fat16_PartitionOffset] ; Add the offset to the partition
660 mov rdx, rax ; Save the sector value
661 mov rdi, hdbuffer1
662 mov rsi, rdi
663 mov rcx, 1
664 call readsectors
665 xor rax, rax
666 os_fat16_file_delete_next_cluster:
667 shl rbx, 1
668 mov ax, word [rsi+rbx]
669 mov [rsi+rbx], word 0x0000
670 mov bx, ax
671 cmp ax, 0xFFFF
672 jne os_fat16_file_delete_next_cluster
673 mov rax, rdx ; Get the sector back. RSI already points to what we need
674 mov rcx, 1
675 call writesectors
676 jmp os_fat16_file_delete_done
678 os_fat16_file_delete_error:
679 xor rax, rax
680 stc ; Set carry
682 os_fat16_file_delete_done:
683 pop rbx
684 pop rcx
685 pop rdx
686 pop rdi
687 pop rsi
690 os_fat16_file_delete_string times 13 db 0
691 ; -----------------------------------------------------------------------------
694 ; -----------------------------------------------------------------------------
695 ; os_fat16_get_file_size -- Read a file from disk into memory
696 ; IN: RSI = Address of filename string
697 ; OUT: RCX = Size of file in bytes
698 ; Carry clear on success, set if file was not found or error occured
699 os_fat16_get_file_size:
700 push rsi
701 push rdi
702 push rax
703 xor ecx, ecx
705 ; Convert the file name to FAT format
706 mov rdi, os_fat16_get_file_size_string
707 call os_fat16_filename_convert ; Convert the filename to the proper FAT format
708 mov rsi, rdi
709 jc os_fat16_file_read_done ; If Carry is set then the filename could not be converted
711 ; Check to see if the file exists
712 call os_fat16_find_file ; Fuction will return the starting cluster value in AX and size in ECX or carry set if not found
714 os_fat16_get_file_size_done:
715 pop rax
716 pop rdi
717 pop rsi
720 os_fat16_get_file_size_string times 13 db 0
721 ; -----------------------------------------------------------------------------
724 ; -----------------------------------------------------------------------------
725 ; os_fat16_filename_convert -- Change 'test.er' into 'TEST ER ' as per FAT16
726 ; IN: RSI = filename string
727 ; RDI = location to store converted string (carry set if invalid)
728 ; OUT: All registers preserved
729 ; NOTE: Must have room for 12 bytes. 11 for the name and 1 for the NULL
730 ; Need fix for short extensions!
731 os_fat16_filename_convert:
732 push rsi
733 push rdi
734 push rdx
735 push rcx
736 push rbx
737 push rax
739 mov rbx, rdi ; Save the string destination address
740 call os_string_length
741 cmp rcx, 12 ; Bigger than name + dot + extension?
742 jg os_fat16_filename_convert_failure ; Fail if so
743 cmp rcx, 0
744 je os_fat16_filename_convert_failure ; Similarly, fail if zero-char string
746 mov rdx, rcx ; Store string length for now
747 xor rcx, rcx
748 os_fat16_filename_convert_copy_loop:
749 lodsb
750 cmp al, '.'
751 je os_fat16_filename_convert_extension_found
752 stosb
753 inc rcx
754 cmp rcx, rdx
755 jg os_fat16_filename_convert_failure ; No extension found = wrong
756 jmp os_fat16_filename_convert_copy_loop
758 os_fat16_filename_convert_failure:
759 stc ; Set carry for failure
760 jmp os_fat16_filename_convert_done
762 os_fat16_filename_convert_extension_found:
763 cmp rcx, 0
764 je os_fat16_filename_convert_failure ; Fail if extension dot is first char
765 cmp rcx, 8
766 je os_fat16_filename_convert_do_extension ; Skip spaces if first bit is 8 chars
768 mov al, ' '
769 os_fat16_filename_convert_add_spaces:
770 stosb
771 inc rcx
772 cmp rcx, 8
773 jl os_fat16_filename_convert_add_spaces
775 os_fat16_filename_convert_do_extension: ; FIX THIS for cases where ext is less than 3 chars
776 lodsb
777 stosb
778 lodsb
779 stosb
780 lodsb
781 stosb
782 mov byte [rdi], 0 ; Zero-terminate filename
783 clc ; Clear carry for success
784 mov rsi, rbx ; Get the start address of the desitination string
785 call os_string_uppercase ; Set it all to uppercase
787 os_fat16_filename_convert_done:
788 pop rax
789 pop rbx
790 pop rcx
791 pop rdx
792 pop rdi
793 pop rsi
795 ; -----------------------------------------------------------------------------
798 ; =============================================================================
799 ; EOF