Bona Fide OS Developer
View unanswered posts | View active topics It is currently Thu Mar 28, 2024 5:16 am



Post new topic Reply to topic  [ 3 posts ] 
 2020 Project: FAT disks 
Author Message

Joined: Sun Sep 19, 2010 9:45 am
Posts: 29
Post 2020 Project: FAT disks
Download: https://archive.org/download/api_v2020/api_v2020.tar
Decompress to the root of a FAT32 LBA hard disk with DOS or memory stick. Run \start.bat
To compile run \api\bin\OS\v2020.bat with NASM 2 and maybe CWSDPMI, DOSLFN, xmsmmgr, SMARTDRV.
The last thing I implemented was dir, type/viewcode commands, stricmp,
the console speed with dos_speed N_microsecs (minimum 1000 by now),
sort of a skeleton showing how to call with console parameters compatible
with DOS a bit and my system, suport for type command with 8.3 or LFN name.

It still won't write the disk, I need to make sure first that I won't damage
the file system.
------------------------------------------------------------------------

Basic FAT disk access needs to be achieved.

We will concentrate in ATA hard disks with FAT filesystems.

- Recursive directory search.
- File open (fopen/fclose).
- File read (fread)
- File write (fwrite)
- Integrity checking principles
- Formatting
- Resizing

We will read from the Primary Master to simplify development.

Here we are interested in the file system, not in detecting hardware.
----------------------------------------------------------------

Results
-------

After a year, I've found out that handling file systems,
and even more, in read/write mode, with a low level file explorer
capable of providing a regular path/drive letters/browser style/etc.,
is twice as hard as implementing basic paging.

So what I achieved was:

- FAT32 LBA very basic read support
- IRQ ATA access for returning unaligned sector block reads
- LFN support
- dir command for the root directory or another if you set it manually
- viewcode command followed by LFN or 8.3 name to display a TAR or source file
- Fail proof ATA-ATAPI detection for primary master, I will need to extend it to other disks

How it Works
------------
All the new code from 2020 is in the kconsole, Storage, FS,
and ATA-ATAPI directories. I would need another whole year
to perfect it to the level where it can formally recognize
drive letters, UNIX and web paths, and efficiently/correctly
write and do other things like starting to recognize other
file systems and similar media like ATAPI.

A function like fopen causes a chain of the structs, from the highest
level (file system dirents) to the lowest level (Device ID) to resolve the access
to the hardware transparently. IDs are always aligned to 1024 or so,
so the ID relates to the offset in the list. The dirent struct
gives us the Partition ID, and the partition struct contains the ID
of the Device, so we know, whith a list of IFs for supported devices
and partitions, how to access for the requested fopen through
wrapper functions that call down to the lowest level.

The ATA-ATAPI detection miniprogram scans all standard ATA-ATAPI
buses as defined by old PCs.

If the primary master is found, it is added to a list of Storage Device IDs.
For the primary master, it tries to see if it contains a FAT32 LBA partition.
If so, it is added to a list of Storage Partition IDs.

fopen, readdir, etc., all use a single dirent struct, which I will design later
to be added as a list of system-wide FILE, DIR, or dirent handles.

We can read sectors either with pure PIO with interrupts off,
or with IRQs, which are significantly faster.

Each dirent struct contains the file names (LFN, 8.3) of the opened
file or directory, its start cluster, its current cluster, its container cluster
(or other equivalent data depending on the file system as it's designed
as a generic link to any file system). It also contains the Partition ID
to which it belongs to.

Each of these Mass Storage subsystem structures is 1024 bytes,
are allocated dynamically in a single list with malloc. The dirent struct
is not fully defined, it could be larger than 1024 bytes, because we need
a low level file system browser to regularize the C library file system functions,
otherwise we will need to use functions and structs that aren't like those
from other C libraries.

_________________
Live Development (click image links for full size):
PC 1: ImagePC 2: Image


Last edited by ~ on Tue Jan 05, 2021 2:01 am, edited 11 times in total.



Wed Oct 30, 2019 7:38 am
Profile

Joined: Sun Sep 19, 2010 9:45 am
Posts: 29
Post Re: 2020 Project: FAT disks
Code:
//Compile with Turbo C 1.01

//set path=%path%;c:\tc101\bin
//tcc atav2020.c

//Turn off Bus Master in Windows 9x:
//
//control sysdm.cpl
//Device Manager
//Hard Disk Controllers
//Intel 82371AB/EB PCI Bus Master IDE Controller
//Properties button
//Settings
//Dual IDE Channel Settings
//No IDE Channels enabled
//
//It will allow you to issue any ATA-ATAPI commands
//under Windows 9x successfully.
//
//


/*

Lista de Trucos:

Calcular de clúster a LBA de hardware (para el directorio raíz)
CHS de BIOS a LBA (1023 255 63 mamimum chs)
Seguir la cadena de clústeres de un archivo
Obtener el tamaño del clúster en sectores y bytes, y leer acorde a eso




*/


#include <stdio.h>
#include <dos.h>
#include <conio.h>



int bitscero;





#define _byte     unsigned char
#define _word     unsigned short
#define _dword    unsigned long int
#define _wideword unsigned long int


_byte LFN_name[1024*4];
_byte _83_name[11];


_byte filescrollc=0;
_byte filescrollc2=0;



//Siempre hay que calcular sin interfaz
//y despues mostrarlo separadamente, puramente
//en variables internas bien formateadas,
//no en printfs o similares.


void byte_bin80x25_2(_byte val0);


//Test to see if we can get raw bytes/words/dwords/widewords
//with our C functions:
///
 _byte *cccc="kerbb";



//INIT: IDE/ATA/ATAPI register offsets

 #define ATA_ATAPI_statusReg_R 7


//END:  IDE/ATA/ATAPI register offsets



//INIT: IDE/ATA/ATAPI Status Register bit definitions

#define ATA_ATAPI_statusReg_bitDRQ  8
#define ATA_ATAPI_statusReg_bitDRDY 0x040 //01000000b
//;00001000b


//END:  IDE/ATA/ATAPI Status Register bit definitions


//INIT: IDE/TATA/ATAPI H/DEV Register bit definitions

#define ATA_LBA_DEV_Slave  0xF0000000
#define ATA_LBA_DEV_Master 0xE0000000

#define ATA_DEV_1bits 0xA0  //definition of bits set to 1 that are obsolete for newer ATA-ATAPI standards

//END:  IDE/TATA/ATAPI H/DEV Register bit definitions




//INIT: FAT32 partition sector definitions
//INIT: FAT32 partition sector definitions
//INIT: FAT32 partition sector definitions

#define FAT32_partsect_BytesPerSect   11  //WORD
#define FAT32_partsect_SectorsPerClus 13  //BYTE
#define FAT32_partsect_ReservedSects  14  //WORD
#define FAT32_partsect_NumFATs        16  //BYTE
#define FAT32_partsect_HiddenSectors  28  //DWORD
#define FAT32_partsect_SectorsPerFAT  36  //DWORD
#define FAT32_partsect_RootClust      44  //DWORD



//END:  FAT32 partition sector definitions
//END:  FAT32 partition sector definitions
//END:  FAT32 partition sector definitions


//MBR definitions
#define MBR_partition_0 446       //Each partition entry is 16 bytes
#define MBR_partition_1 446+16
#define MBR_partition_2 446+32
#define MBR_partition_3 446+48
#define MBR_partition_entry_startLBA 8      //DWORD




//FAT directory entries
//#define FAT_dirent_LFN_record   1|2|4|8
  #define FAT_dirent_LFN_record   1+2+4+8  //Si no hay bits superpuestos, OR y sumar es lo mismo
  #define FAT_dirent_LFN_endchain 64
 
 #define FAT_dirent_LFN_Checksum 13






void OPCODE__ATA__READ_SECTORS(_word ATA_base, _dword LBA_DEV, _word SectCount, _word bytespersect, _byte *ATA_destbuff);
void OPCODE__ATA__READ_SECTORS_CHS(_word ATA_base, _dword CHS_DEV, _word SectCount, _word bytespersect, _byte *ATA_destbuff);
void _OPCODE__ATA__READ_SECTORS_CHS(_word ATA_base, _dword CHS_DEV, _word SectCount, _byte *ATA_destbuff);
void _OPCODE__ATA__IDENTIFY_DEVICE(unsigned char *buff512);
void wait_DRQ(_word ATA_base, _byte DEV_bit);
void OPCODE__ATA__IDENTIFY_DEVICE(_word ATA_base, _byte ATA_DEV, _byte *buff512);




void byte_bin80x25(_byte val0);
int bit0_bin80x25(_byte val0);


//Implementar pantalla/controles binarios para
//editar los valores crudos de nombres
//mientras no podamos mostrar los caracteres
//en cuestión, siempre todo con la opción de
//mostrarse crudo, y diálogos con la información
//completa de todo tipo para alcanzar los recursos mostrados.



//The FAT32__ functions print a sinle entry.
//The FAT32LBA__ functions work purely in LBA mode
//to get all the data through sectors.
///
 void OPCODE__FS__FAT32__print_8_3_entry__80x25(_byte *entry, int offset);
 void OPCODE__FS__FAT32__print_LFN_entry__80x25(_byte *entry, int offset);
 void _OPCODE__FS__FAT32LBA__get_last_LFN_Entry(_byte *entry, int offset);

 void OPCODE__FS__FAT32LBA__get_last_LFN_Entry(_byte *entry, int offset, _byte checksum);


 void OPCODE__FS__BIOS_CHS_to_native_LBA(_byte *entry, int offset);



//Returns boolean true if the entry is valid (not al zeros),
//or boolean false if it just contains 0, which also marks
//the end of the directory.
//
 _wideword OPCODE__FS__FAT__check_valid_entry(_byte *entry, int offset)
 {
  _wideword sum0,x;
 
  x=0;
  while(x<32)
  {
   sum0+=*(entry+offset);
   offset++;x++;
  }

  return sum0;
 }




//Checksum for an 8.3 name:
///
 //_byte OPCODE__FS__FAT__checksum(_byte *entry, int offset);
 _byte OPCODE__FS__FAT__checksum(_byte *entry);





_byte LowEST_rb(void *buff, _wideword offset);
_word LowEST_rw(void *buff, _wideword offset);
_dword LowEST_rdw(void *buff, _wideword offset);
_wideword LowEST_rww(void *buff, _wideword offset);

_byte LowEST_wb(void *buff, _wideword offset);
_word LowEST_ww(void *buff, _wideword offset);
_dword LowEST_wdw(void *buff, _wideword offset);
_wideword LowEST_www(void *buff, _wideword offset);

_dword LowEST_rdwb(void *buff, _wideword offset);






void prn_buff(_byte *buff, _dword size)
{
 int x;
      x=0;
      while(x<size)
      {
       printf("%c",buff[x]);
       x++;
      }


}






void skels()
{
 asm {
  .386

  // Turbo PROC NEAR
     or eax,eax


  // Turbo ENDP


 };



}




/*
 //REMOVED main() code


// x=0;
// while(x<512)
// {
//  sect[x]=0;
//  x++;
// }
// x=0;
// while(x<512)
// {
  //printf("%c",sect[x]);
//    printf("%c",sect[x]);
//  x++;
// }
//getch();
//clrscr();




*/





_word LowEST__iorw(_word ioaddr)
{
 _word myword;
 asm {
  mov dx,ioaddr
  in ax,dx
  mov myword,ax
 };

 return myword;
}



_byte LowEST__iorb(_word ioaddr)
{
 _byte mybyte;
 asm {
  mov dx,ioaddr
  in al,dx
  mov mybyte,al
 };

 return mybyte;
}


_byte ata_identify_pri_ma[512];

//_byte *ptr_arr;
 //_byte *ata_identify_pri_ma=NULL; //This collides and gets overwritten
                //no matter the memory model and
                //if it's declared inside or outside main
 //_byte *sect;
 _byte sect[512*32];
 _byte mbr[512];
 _byte mbr_part0sect[512];
 _wideword fat32__data_base=0;
 _dword fat32tbl_base=0;
 _dword fat32vol_base=0;
 _dword fat32vol_sects_per_clus=0;
 _dword fat32vol_bytes_per_sect=0;
 _dword fat32vol_clust_SZ=0;
 int x=0,c=0,sectoff=0;
 _dword LBAFAT32=0;   //0xA800;
 _dword FAT32_LBA_Rootdir=0;

 _byte mbr_part0_type;
 _word mbr_part0_c;
 _byte mbr_part0_h;
 _byte mbr_part0_s;
 _dword mbr_part0startlba;

 _dword testfile_startclus;
 _dword testfileSZ;



 _word ata_identify_cylinders;
 _word ata_identify_heads;
 _word ata_identify_sectors_per_track;


 _dword mbr_part0calcstartlba;  //calculated start LBA

 int sfnoff;





int ui(void)
{
 resetall:
  sectoff=0;

 //check that the last LFN entry actually is anded with 64
 //clrscr();printf("%d",'B');getch();exit();

 //sect=(unsigned char *)malloc(512*16);   //sects per clust
 //mbr_part0sect=(unsigned char *)malloc(512);
 //if(mbr_part0sect==NULL)return 1;
 //mbr=(unsigned char *)malloc(512);
 //ata_identify_pri_ma=(_byte *)malloc(512);
 //if(ata_identify_pri_ma==NULL)return 1;

 clrscr();

 




//Windows escribe todo un nuevo sector
//si por ejemplo renombramos My Documents a
//My Documentz solo para asegurarse de que haya
//espacio para todas las entradas, en vez de solo
//cambiar un caracter, la s a z, si los tamanos tienen
//la misma longitud,
//O aparentemente se tarda un ratito en escribir el sector,
//tal vez lo trata de reescribir, comprueba que cambio a
//los nuevos cambios si corremos un programa como este.
///


 //OPCODE__ATA__READ_SECTORS(0x1F0, 0xA800, 1, 512, sect);
  OPCODE__ATA__READ_SECTORS_CHS(0x1F0, 1, 1, 512, mbr);
  mbr_part0_type=mbr[446+4]&0xFF;
  mbr_part0_c=(( (mbr[446+2]&0xC0) << 8  ) | mbr[446+3])&0xFFFF;  //MBR entries only have 8-bit Cyls, not 16-bit
  mbr_part0_s=mbr[446+2]&0x3F;
  mbr_part0_h=mbr[446+1]&0xFF;

  mbr_part0startlba=mbr[446+8]|(mbr[446+9]<<8)|(mbr[446+10]<<16)|(mbr[446+11]<<24);

  //If for example, the H value exceeds 15,
  //we can only rely on the LBA. The more we can do
  //is calculate the LBA from the CHS to see
  //if they match with the given geometric formula:
  ///
//void OPCODE__ATA__READ_SECTORS_CHS(_word ATA_base, _dword CHS_DEV, _word SectCount, _word bytespersect, _byte *ATA_destbuff);
//  printf("CHSpart: %X",mbr_part0_s|(mbr_part0_h<<8)|(mbr_part0_c<<16));getch();


//Hacer tablas de formulas de CHS BIOS a LBA y LBA a CHS BIOS
//  OPCODE__ATA__READ_SECTORS_CHS(0x1F0, mbr_part0_s|(mbr_part0_h<<8)|(mbr_part0_c<<16), 1, 512, mbr_part0sect);






//Hacer un dialogo que nos muestre los datos
//obtenidos del disco, y que nos pregunte si lo
//contamos como drive valido o no.
 OPCODE__ATA__IDENTIFY_DEVICE(0x1F0, 0, ata_identify_pri_ma);

 ata_identify_cylinders=ata_identify_pri_ma[1*2]|(ata_identify_pri_ma[(1*2)+1]<<8);
 ata_identify_heads=ata_identify_pri_ma[3*2]|(ata_identify_pri_ma[(3*2)+1]<<8);
 ata_identify_sectors_per_track=ata_identify_pri_ma[6*2]|(ata_identify_pri_ma[(6*2)+1]<<8);




//Este formato, de poner todo calculado inicialmente sin interfaz
//y después hacer un menú basado en apretar y reconocer caracteres
//de cada tecla del teclado, recalculando otra vez pero para
//la GUI, poner todas las definiciones de funciones y variables
//al principio, es bueno si llega a fallar el disco por trabarse el sistema,
//especialmente si los clústeres tienen unos 8KB y todo lo importante
//cabe en ese espacio.
//
//



/*
 mbr_part0calcstartlba=
    (mbr_part0_c*ata_identify_heads*ata_identify_sectors_per_track)+
    (mbr_part0_h*ata_identify_sectors_per_track)+
    (mbr_part0_s-1);
*/


 mbr_part0calcstartlba=
    (mbr_part0_c*255*63)+
    (mbr_part0_h*63)+
    (mbr_part0_s-1);



//uncomm
 OPCODE__ATA__READ_SECTORS(0x1F0, mbr_part0calcstartlba, 1, 512, mbr_part0sect);


//Tambien es mejor hacer etiquetas y reservar con
//malloc/free para todo lo que vamos a hacer.
//Terminamos accesando todo exactamente igual que
//en Ensamblador sin darnos cuenta.

//printf("%X ee",LowEST_rw(mbr, 446+8));getch();
//printf("%X ee",mbr[446+8]|(mbr[446+9]<<8)|(mbr[446+10]<<16)|(mbr[446+11]<<24));getch();



//;Get the base address of the root directory,
//;partition, data area, FATs...:
//;;
fat32__data_base=//LowEST_rdw(mbr, 446+8)+
         (_dword)LowEST_rdw(mbr_part0sect, FAT32_partsect_HiddenSectors)+ //Skip all before partition
         (_dword)LowEST_rdw(mbr_part0sect, FAT32_partsect_SectorsPerFAT)*
         (_dword)LowEST_rb(mbr_part0sect, FAT32_partsect_NumFATs)+        //Skip FATs
         (_dword)LowEST_rw(mbr_part0sect, FAT32_partsect_ReservedSects); //Skip special partition sectors
         
LBAFAT32=fat32__data_base;



//printf("MBR: ");
//prn_buff(mbr, 512);getch();


fat32vol_sects_per_clus=(_wideword)LowEST_rb(mbr_part0sect, FAT32_partsect_SectorsPerClus);
fat32vol_bytes_per_sect=(_wideword)LowEST_rw(mbr_part0sect, FAT32_partsect_BytesPerSect);
fat32vol_clust_SZ=(_wideword)fat32vol_sects_per_clus*(_wideword)fat32vol_bytes_per_sect;


//Calculate the Cluster to LBA for the root directory:
///
FAT32_LBA_Rootdir=
       fat32__data_base+
       ((_wideword)LowEST_rdw(mbr_part0sect, FAT32_partsect_RootClust)-2)*((_wideword)LowEST_rb(mbr_part0sect, fat32vol_sects_per_clus));

LBAFAT32=FAT32_LBA_Rootdir;




printf("Root cluster: %u\n",(_dword)LowEST_rdw(mbr_part0sect, FAT32_partsect_RootClust));
printf("Root hardware LBA sector: 0x%X\n",FAT32_LBA_Rootdir);



fat32tbl_base=(_dword)LowEST_rdw(mbr_part0sect, FAT32_partsect_HiddenSectors)+ //Skip all before partition
              (_dword)LowEST_rw(mbr_part0sect, FAT32_partsect_ReservedSects);  //Skip special partition sectors



printf("FAT32 base table: 0x%X\n",fat32tbl_base);

printf("Sectors per cluster: %i\n",fat32vol_sects_per_clus);



getch();


FAT32_LBA_Rootdir=LBAFAT32;

while(c!=27)
{

///INIT: Control through keys

  //if c is 0, nothing will happen to the LBA number (initial)

  if(c==77)    //right arrow
  {
   LBAFAT32++;
   sectoff=0;
  }
  if(c==75)  //left arrow
  {
   LBAFAT32--;
   sectoff=0;
  }
  if(c==72 && sectoff>0)  //up arrow
  sectoff-=32;
  if(c==80 && sectoff<(512-32))  //down arrow
  sectoff+=32;




 //Here starts keys that need
 //a clean screen:
 ///



 clrscr();


 //Este ejemcplo con F1 y el resto del
 //bucle de sectores/entradas de directorio
 //produce un excelente efecto de doble
 //menu/dialogo anidado al darle varias veces
 //ESC para regresar eficientemente a lo
 //anterior:
 ///
  if(c==59)  //F1
  {
   c=0;  //Clear the menu char to keep interpreting options dynamically
   do
   {
    clrscr();
    OPCODE__ATA__READ_SECTORS_CHS(0x1F0, 1, 1, 512, mbr);
    printf("MBR Data\n\n");


    printf("Partition 0\n-----------\n");
    mbr_part0_type=mbr[446+4]&0xFF;printf("Type: 0x%X byte at offset 446+4",mbr_part0_type);
    if((mbr[446+4]&0xFF)==0x0C)  //byte[mbr+446+4]
    {
     printf(" (FAT32 MBR)\n");
    }

    mbr_part0_c=(( (mbr[446+2]&0xC0) << 8  ) | mbr[446+3])&0xFFFF;  //MBR entries only have 8-bit Cyls, not 16-bit
    mbr_part0_s=mbr[446+2]&0x3F;
    mbr_part0_h=mbr[446+1]&0xFF;
//    mbr_part0startlba=mbr[446+8];
    mbr_part0startlba=(mbr[446+8])|(mbr[446+9]<<8);

//    printf("Initial CHS: %d,%d,%d (mbr C 10bits[446+2.6-3] H byte[446+1] S 6bits[446+2])\n",mbr_part0_c,mbr_part0_h,mbr_part0_s);
    printf("Initial CHS: %d,%d,%d (mbr: C 10bits[446+2.6-3] H byte[446+1] S 6bits[446+2])\n",mbr_part0_c,mbr_part0_h,mbr_part0_s);


// mbr_part0calcstartlba=
//    (mbr_part0_c*ata_identify_heads*ata_identify_sectors_per_track)+
//    (mbr_part0_h*ata_identify_sectors_per_track)+
//    (mbr_part0_s-1);





 mbr_part0calcstartlba=
    (mbr_part0_c*255*63)+
    (mbr_part0_h*63)+
    (mbr_part0_s-1);

    //printf("milbaA 0x%X",mbr_part0calcstartlba);getch();

    //printf("milba 0x%X",mbr_part0calcstartlba);getch();



    printf("Initial LBA word[mbr+446+8]: 0x%X\n",mbr_part0calcstartlba);




//uncomm
 OPCODE__ATA__READ_SECTORS(0x1F0, mbr_part0calcstartlba, 1, 512, mbr_part0sect);


    //Comandos de teclado para decirle al sistema que el
    //directorio o archivo actual se ve danado para ver que
    //puede hacer o comprobar solo ese directorio.
    ///
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
      x=0;
      while(x<512)
      {
       //printf("%c",mbr_part0sect[x]);
       printf("%c",mbr[x]);
       x++;
      }
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)

//printf("milbaA 0x%X",mbr_part0calcstartlba);getch();return 0;
//printf("Part0 LBA: 0x%X",mbr_part0startlba);//getch();return 0;

   }
   while(getch()!=27);
  }









  if(c==134)  //F12 -- in case there's an initial read error due to IDENTIFY DEVICE
  {           //       See if it also fails under the kernel and wait a bit or reset
              //       the device for trying to avoid it.
 
   c=0;  //Clear the menu char to keep interpreting options dynamically
   goto resetall;
  }


  if(c==60)  //F2
  {
   c=0;  //Clear the menu char to keep interpreting options dynamically
   do
   {
    clrscr();
    //OPCODE__ATA__READ_SECTORS_CHS(0x1F0, 1, 1, 512, mbr);
    printf("Partition Sector\n-----------\n\n");


    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
      x=0;
      while(x<512)
      {
       printf("%c",mbr_part0sect[x]);
       x++;
      }
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)

//printf("milbaA 0x%X",mbr_part0calcstartlba);getch();return 0;
//printf("Part0 LBA: 0x%X",mbr_part0startlba);//getch();return 0;

   }
   while(getch()!=27);
  }












  if(c==61)  //F3 -- IDENTIFY data
  {
   c=0;  //Clear the menu char to keep interpreting options dynamically
   do
   {
    clrscr();
    OPCODE__ATA__IDENTIFY_DEVICE(0x1F0, 0, ata_identify_pri_ma);
    printf("IDENTIFY Data\n\n");


    printf("Device 0\n-----------\n");



    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
      x=0;
      while(x<512)
      {
       printf("%c",ata_identify_pri_ma[x]);
       x++;
      }
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)
   }
   while(getch()!=27);
  }

 //Clear previous menu screen
 //to display normal data
 clrscr();

//getch();printf("Root directory/data absolute LBA sector: 0x%X",LBAFAT32);


 //Display the now current disk sector
 //for the specified device:
 ///
  OPCODE__ATA__READ_SECTORS(0x1F0, LBAFAT32, 1, 512, sect); //sectors per clus
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
    ///INIT: Print the raw sector data (to see if it was correctly read)
      x=0;
      while(x<512)
      {
       printf("%c",sect[x]);
       x++;
      }
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)
    ///END:  Print the raw sector data (to see if it was correctly read)



//Como hacer para mostrar la tecla apretada
//mas reciente? Si la inicial es 0 logicamente,
//si lo ponemos aqui nos va a mostrar la nueva
//pantalla y la tecla asociada que nos llevo ahi.
///
 printf("{%d}{0x%X}",c,LBAFAT32);
 printf("{%d}",sectoff);

 if(OPCODE__FS__FAT__check_valid_entry(sect, sectoff)==0)
 {
  printf("End of Directory (zeroed entry)\n");
 }

 else if((sect[sectoff+11]&FAT_dirent_LFN_record)==FAT_dirent_LFN_record)
 {
  printf("%dfirst entry is LFN",sect[sectoff+11]&FAT_dirent_LFN_record);
  if((sect[sectoff]&64)==64)
  {
   printf(" (last in chain due to OR with 64 at entry offset 0)");
   OPCODE__FS__FAT32LBA__get_last_LFN_Entry(sect, sectoff, sect[sectoff+FAT_dirent_LFN_Checksum]&0xFF);
  }
  printf("\n");
  OPCODE__FS__FAT32__print_8_3_entry__80x25(sect, sectoff);
  printf("<%d>CHECK,CHK:%d",sect[sectoff+FAT_dirent_LFN_Checksum]&0xFF,0);
 }

 else if((sect[sectoff+11]&8)==8)
 {
  printf("%dfirst entry is volume id\n",sect[sectoff+11]&8);
  OPCODE__FS__FAT32__print_8_3_entry__80x25(sect, sectoff);
 }

 else if((sect[sectoff+11]&16)==0 || (sect[sectoff+11]&16)==16)
 {
  if((sect[sectoff+11]&16)==0)
  printf("%dfirst sector entry is 8.3 file\n",sect[sectoff+11]&16);
  else if((sect[sectoff+11]&16)==16)
  printf("%dfirst sector entry is 8.3 directory\n",sect[sectoff+11]&16);
  printf("%d generated CHK\n",OPCODE__FS__FAT__checksum(sect+sectoff)&0xFF);
  OPCODE__FS__FAT32__print_8_3_entry__80x25(sect, sectoff);
  printf("\n");


  sfnoff=0;
  while(sfnoff<32)
  {
   _83_name[sfnoff]=sect[sectoff+sfnoff];
   printf("%c",_83_name[sfnoff]=sect[sectoff+sfnoff]);
   sfnoff++;
  }


 //Show file data:
 ///
  testfileSZ=LowEST_rdw(_83_name,28);  //file size
  printf("\nTamaño: %d\n",testfileSZ);  //Calcular a mano para directorios

  if((LowEST_rb(_83_name,11)&16)==16)
  printf("<DIR>");


  testfile_startclus=(_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16);
  printf("\nClúster inicial: %ld\n",testfile_startclus);  //Calcular a mano para directorios


 while(1)
 {
//Calculate the Cluster to LBA for this directory:
///
  printf("\nClúster a LBA: %ld\n",fat32__data_base+
       (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16))-2)*((_wideword)LowEST_rb(mbr_part0sect, FAT32_partsect_SectorsPerClus)));  //Calcular a mano para directorios


 //Read the specified cluster:
 ///
  OPCODE__ATA__READ_SECTORS(0x1F0, fat32__data_base+
       (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16))-2)*((_wideword)LowEST_rb(mbr_part0sect, FAT32_partsect_SectorsPerClus)), fat32vol_sects_per_clus, 512, sect); //sectors per clus
      x=0;
      printf("\n---\n",fat32vol_clust_SZ);
      //while(x<512)
      //while(x<LowEST_rdw(_83_name,28))  //file size
      //while(x<fat32vol_sects_per_clus*fat32vol_bytes_per_sect)
      while(x<fat32vol_sects_per_clus*fat32vol_bytes_per_sect)
      {
       printf("%c",sect[x]);
       x++;
       if(!(testfileSZ%512)){printf("Next...%c",filescrollc);filescrollc=getch();}
       if(!testfileSZ)break; //We don't decrement it here as for directories it could already be 0
       --testfileSZ;
      }


 //Read the sector for that cluster:
 ///
  OPCODE__ATA__READ_SECTORS(0x1F0, (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16))-2)/512+fat32tbl_base, 1, 512, sect);
//  OPCODE__ATA__READ_SECTORS(0x1F0, fat32tbl_base, 1, 512, sect);


 //Read the value at that cluster.
 //I imagined that if I calculated the modulo
 //I would get the offset into the last partial FAT
 //sector because this entry will never be 512 but a maximum
 //of 508.
 //
 //Turbo C parece no estar preparado para
 //algunas teclas como las flechas, como que
 //el scan code que usaba ya no es exactamente igual
 //a antes así que no las captura bien siempre, y si comparamos
 //si es la misma tecla o no, no funciona, solo con
 //teclas normales alfanuméricas, spacebar, etc...
 //
 ///
  printf("Next %u",
//  (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16)))%512
  //(((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16)))%512 -- máxima desactivación
  (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16)))*4
  );


  testfile_startclus=(unsigned _dword)LowEST_rdwb(sect, (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16)))*4);
  printf("Value 0x%X",
  //LowEST_rdw(sect, (((_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16)))%512)
  //(unsigned _dword)LowEST_rdwb(sect, 8)
  //(unsigned _dword)LowEST_rdwb(sect, 8) -- máxima desactivación
  testfile_startclus
  );


       //while(getch()!=filescrollc);
       
       while(1){filescrollc2=getch();if(filescrollc2!=filescrollc)break;fflush(stdin);}
       //while(1){printf("%c",(getch()==filescrollc)?0:break);fflush(stdin);}
       //while(1){printf("%c",(getch()==filescrollc));fflush(stdin);}
       //while(1);
       /*while(1)
       {
        printf("%d-%d",getch(),filescrollc);break;
       }*/
       filescrollc=0;
//Una tecla diferente para cancelar el fin de archivo,
//buena idea para hacer scrolls larguísimos, una mejora
//de la interfazde usuario.


 //if((unsigned _dword)LowEST_rdwb(sect, 8)==((_dword)-1))
 //printf("MINUSONE %X",LowEST_rdw(sect, 8));

 //Should be >= 0xFFFFFFF8:
 ///
// break;
  if(((unsigned _dword)testfile_startclus)==((_dword)-1))break;

 }


 }



 c=getch();


///END:  Control through keys

}


 return 0;
}






int main(void)
{
 ui();

 return 0;
}







//Funciones para leer el sector,
//para calcular CHS a LBA, etc.


//TASM de TC .01 soporta .386,
//PROCs, y todo lo de un ensamblador normal
//de forma inline, pero el resto de versiones no,
//aunque sea algo extremadamente ventajoso.


void wait_DRQ(_word ATA_base, _byte DEV_bit)
{
/*
 _dword ecx_ctr=0xFFFFF;
 _byte al_iobyte;


 while(1)
 {
  //;Keep waiting for DRQ. If we don't get more,
  //;we have finished our reading:
  //;;
    ATA_base+=ATA_ATAPI_statusReg_R;
     al_iobyte=inportb(ATA_base);
     al_iobyte&=ATA_ATAPI_statusReg_bitDRQ;
    ATA_base-=ATA_ATAPI_statusReg_R;

  //;Terminate waiting for DRQ as soon
  //;as it becomes 1:
  //;;
   if(al_iobyte==ATA_ATAPI_statusReg_bitDRQ)break;

  delay(1);  //try to delay enough as with LOOP
 }
*/



 asm {
  .386

   mov dx,ATA_base

   add dx,6
    mov al,DEV_bit
    out dx,al
   sub dx,6


   //;Keep waiting for DRQ. If we don't get more,
   //;we have finished our reading:
   //;;
    mov ecx,0xFFFFF

   .waitDRQ:
    add dx,ATA_ATAPI_statusReg_R
     in al,dx
     and al,ATA_ATAPI_statusReg_bitDRQ
    sub dx,ATA_ATAPI_statusReg_R

   //;Terminate waiting for DRQ as soon
   //;as it becomes 1:
   //;;
     cmp al,ATA_ATAPI_statusReg_bitDRQ
     je .waitDRQ_END



   //;Keep waiting for DRQ:
   //;;
    loop .waitDRQ
    .waitDRQ_END:
 
 };

}



void wait_DRDY(_word ATA_base, _byte DEV_bit)
{
 asm {
  .386

   mov dx,ATA_base

   add dx,6
    mov al,DEV_bit
    out dx,al
   sub dx,6


   //;Keep waiting for DRQ. If we don't get more,
   //;we have finished our reading:
   //;;
    mov ecx,0xFFFFF

   .waitDRDY:
    add dx,ATA_ATAPI_statusReg_R
     in al,dx
     and al,ATA_ATAPI_statusReg_bitDRDY
    sub dx,ATA_ATAPI_statusReg_R

   //;Terminate waiting for DRQ as soon
   //;as it becomes 1:
   //;;
     cmp al,ATA_ATAPI_statusReg_bitDRDY
     je .waitDRDY_END



   //;Keep waiting for DRDY:
   //;;
    loop .waitDRDY
    .waitDRDY_END:
 
 };

}




/*

Removed code

 printf("%c",LowEST_rb(cccc, 2));getch();




*/



void OPCODE__ATA__READ_SECTORS_CHS(_word ATA_base, _dword CHS_DEV, _word SectCount, _word bytespersect, _byte *ATA_destbuff)
{
 int x;
 _word tmpword;
 _wideword buffoff=0;
 _byte statusreg=0;

 bytespersect/=2;

retryallread:

 //;Write Sector Count:
 //;;
  SectCount&=0xFF; //Only 8 bits are valid
  outportb(ATA_base+2, SectCount);
  if(SectCount==0)SectCount=256;

 //;Write S:
 //;;
  outportb(ATA_base+3, CHS_DEV&0xFF);  //8 bits only

 //;Write C (16 bits):
 //;;
  outportb(ATA_base+4, (CHS_DEV>>16)&0xFF);  //Cylinder Low
  outportb(ATA_base+5, (CHS_DEV>>24)&0xFF);  //Cylinder High

 //;Write H/DEV (4 bits head, bit 4 DEV):
 //;;
  outportb(ATA_base+6, ((CHS_DEV>>8)&0xFF)|ATA_DEV_1bits);

 //;Write command (READ SECTORS, 0x20):
 //;;
  outportb(ATA_base+7, 0x20);



/*
 printf("READ SECTORS error: ");
 byte_bin80x25((_byte)inportb(ATA_base+1));printf("b\n");
 printf("READ SECTORS status: ");
 byte_bin80x25((_byte)statusreg);printf("b\n");
 printf("READ SECTORS alternate status: ");  //Primary Alternate Status
 byte_bin80x25((_byte)inportb(0x3F6));printf("b\n");
 getch();
*/


 retryread:
 while(SectCount!=0)
 {
  //Wait DRQ before reading each sector:
  ///
   wait_DRQ(ATA_base, (CHS_DEV>>8)&0xFF);

  x=0;
  while(x<bytespersect) //ver si se puede contar solo con AND y solo x
  {
   //Using inport is an error in this case.
   //Usar inport es un error en este caso.
   //Lee el byte de menor peso de portid,
   //y el byte de mayor peso de portid+2.
   //outport lee el de menor peso de portid
   //y el de mayor peso de portid+1.
   //
   //Es fácil saber para qué fue ideado si encontramos
   //un puerto que se comporte así para esas funciones,
   //pero aquí necesitamos leer una palabra directamente
   //de un único puerto como 0x1F0.
   //
   //Aprender a hacer ese tipo de cosas sin TASM, solo
   //con regs o a lo sumo con arreglos de bytes con instrucciones
   //crudas para Turbo C.
   //
   //Solo necesito saber la estructura de los programas y saber ensamblar,
   //las demás herramientas ya no serían necesarias para rescatar
   //una plataforma como la Palm.
   //
   //
   //tmpword=inport(ATA_base); 
   tmpword=LowEST__iorw(ATA_base);
   ATA_destbuff[buffoff]=tmpword&0xFF;
   ATA_destbuff[buffoff+1]=(tmpword>>8)&0xFF;

   x++;
   buffoff+=2;
  }

  SectCount--;
 }

   //wait_DRQ(ATA_base, (CHS_DEV>>8)&0xFF);
   //wait_DRQ(ATA_base, (CHS_DEV>>8)&0xFF);
   //wait_DRDY(ATA_base, (CHS_DEV>>8)&0xFF);
   wait_DRDY(ATA_base, (CHS_DEV>>8)&0xFF);


 statusreg=LowEST__iorb(ATA_base+7)&0xFF;

 //Status register bits:
 //
 //
 //0: error bit
 //1: sense data available
 //2: NA or alignment error (ATA4)
 //3: transport dependent (ATA4)
 //4: NA (ATA4)
 //5: device fault (ATA4)
 //6-7: transport dependent (ATA4)
 //

 //If DRQ is on, retry reading (apparently it will do nothing other than
 //clearing the DRQ bit unless we re-read AS FAST AS POSSIBLE,
 //it would be better to retry the whole command
 //until there are no error outputs, and maybe increase the wait DRQ):
 ///
  //if(statusreg&16){printf("read retried chs ");goto retryread;getch();}
  //printf("statusreg&1 %X\n",LowEST__iorb(ATA_base+7)&1);
  //printf("statusreg&1 %d ",(_dword)(statusreg&1));
//  byte_bin80x25((_byte)inportb(ATA_base+7));printf("\n");
  if(statusreg&1){printf("retry whole command ");goto retryallread;getch();}
  //if(LowEST__iorb(ATA_base+7)&0x1){printf("retry whole command ");goto retryallread;getch();}



/*
 Los resultados del comando son diferentes antes de leer
 los datos, no se completa hasta que los hayamos tratado de
 leer todos.
*/

 printf("00READ SECTORS DEVICE: ");
 byte_bin80x25((_byte)inportb(ATA_base+3));printf("b\n");
 printf("00READ SECTORS error: ");
 byte_bin80x25((_byte)inportb(ATA_base+1));printf("b\n");
 printf("READ SECTORS statusz: ");
 byte_bin80x25_2((_byte)(_byte)inportb(ATA_base+7));printf("b\n");
 //byte_bin80x25((_byte)statusreg);printf("b\n");
 //printf("statusreg&1 %d ",bit0_bin80x25((_byte)inportb(ATA_base+7)));
 //printf("statusreg&1 %d ",bit0_bin80x25((_byte)statusreg));
 //putchar(bit0_bin80x25((_byte)statusreg));
 printf("statusreg&1 %d --",bitscero);
 printf("READ SECTORS alternate status: ");  //Primary Alternate Status
 byte_bin80x25((_byte)inportb(0x3F6));printf("b\n");
 //getch();exit(0);


}

//¿Hay READ SECTORS sin retry desde ATA 1?


void byte_bin80x25_2(_byte val0)
{
 int x=0;

 while(x<8)
 {
  //if(val0&1)printf("1");else printf("0");
  if((val0&1)==1){if(x==0)exit(1);printf("1");}else {printf("0");}
  val0>>=1;
  x++;
 }

}


void byte_bin80x25(_byte val0)
{
 int x=0;

 while(x<8)
 {
  //if(val0&1)printf("1");else printf("0");
  if(val0&1){if(x==0)bitscero=1;printf("1");}else {if(x==0)bitscero=0;printf("0");}
  val0>>=1;
  x++;
 }

}

int bit0_bin80x25(_byte val0)
{
 int x=0;

 while(x<8)
 {
  if(val0&1){putc('A',stdout);return 2;}else {putc('B',stdout);return 1;}
 }

}




void OPCODE__ATA__READ_SECTORS(_word ATA_base, _dword LBA_DEV, _word SectCount, _word bytespersect, _byte *ATA_destbuff)
{
 int x;
 _word tmpword;
 _wideword buffoff=0;

 bytespersect/=2;


 //;Write Sector Count:
 //;;
  SectCount&=0xFF; //Only 8 bits are valid
  outportb(ATA_base+2, SectCount);
  if(SectCount==0)SectCount=256;

  LBA_DEV|=ATA_LBA_DEV_Master;  //set LBA bit, Master DEV is 0 so no device changes

  outportb(ATA_base+3, LBA_DEV&0xFF);         //LBA 0-7
  outportb(ATA_base+4, (LBA_DEV>>8)&0xFF);    //LBA 8-15
  outportb(ATA_base+5, (LBA_DEV>>16)&0xFF);   //LBA 16-23
  outportb(ATA_base+6, (LBA_DEV>>24)&0xFF);   //LBA 24-27, DEV/LBA bits
  outportb(ATA_base+7, 0x20);   //READ SECTORS (with retry)


 while(SectCount!=0)
 {
  //Wait DRQ before reading each sector:
  ///
   wait_DRQ(ATA_base, (LBA_DEV>>24)&0xFF);

  x=0;
  while(x<bytespersect) //ver si se puede contar solo con AND y solo x
  {
   tmpword=LowEST__iorw(ATA_base);
   ATA_destbuff[buffoff]=tmpword&0xFF;
   ATA_destbuff[buffoff+1]=(tmpword>>8)&0xFF;

   x++;
   buffoff+=2;
  }

  SectCount--;
 }

   //wait_DRQ(ATA_base, (LBA_DEV>>24)&0xFF);
   //wait_DRQ(ATA_base, (LBA_DEV>>24)&0xFF);
   //wait_DRDY(ATA_base, (LBA_DEV>>24)&0xFF);
   wait_DRDY(ATA_base, (LBA_DEV>>24)&0xFF);
}






void OPCODE__ATA__IDENTIFY_DEVICE(_word ATA_base, _byte ATA_DEV, _byte *buff512)
{
 int x=0;
 _word tmpword;
 _byte *inptr=buff512;


// outportb(ATA_base+6,ATA_DEV);
// outportb(ATA_base+7,0xEC);


 asm {
 mov dx,ATA_base
 add dx,6          //;DEVICE/LBA or head
 mov al,ATA_DEV
 or  al,10100000b
 out dx,al


 mov al,0xEC  //;IDENTIFY DEVICE
 inc dx       //;Command
 out dx,al

 //;The data register is at offset 0 from the I/O
 //;base address, so we just need to read it:
 //;;
  sub dx,7
 };




 wait_DRQ(ATA_base, ATA_DEV);


/*
 asm {
   .386
   mov ecx,512/4
   mov dx,ATA_base
   //mov di,word[inptrs]
   mov di,buff512
   rep insd
 };


goto donee;
*/

 while(x<512)
 {

   tmpword=LowEST__iorw(ATA_base);
  //tmpword=inport(ATA_base);
  buff512[x]=tmpword&0xFF;
  buff512[x+1]=(tmpword>>8)&0xFF;


  x+=2;
 }

donee:



 printf("00READ SECTORS DEVICE: ");
 byte_bin80x25((_byte)inportb(ATA_base+3));printf("b\n");
 printf("00READ SECTORS error: ");
 byte_bin80x25((_byte)inportb(ATA_base+1));printf("b\n");
 printf("READ SECTORS status: ");
 byte_bin80x25((_byte)(_byte)inportb(ATA_base+7));printf("b\n");
 printf("READ SECTORS alternate status: ");  //Primary Alternate Status
 byte_bin80x25((_byte)inportb(0x3F6));printf("b\n");
 //getch();//exit(0);


}






//Cómo hacer un menú suelto que responda a todas las opciones base
//esté donde esté como para implementar un juego que pueda hacer
//cualquier cosa sin importar las acciones anteriores.
//Eso es abslutamente necesario para implementar juegos con
//soltura (hasta los juegos viejos pueden) y GUIs que tengan
//opnciones realmente paralelas.
//
//
//
//
//



//Anotar el valor de getch para todas las teclas,
//tal vez hasta con Shift, Ctrl, etc...,
//el keyup...



//Tal vez para manejar datos externos desde TASM inline
//necesitamos crear una variable puntero que no esté en la pila,
//copiar normalmente el puntero, y después referenciar la variable local,
//no el parámetro.
//







//Poner todas las formas de referenciar punteros
//o implementar GUIs de programas de forma cruda
//a todos los sistemas para tener claro lo que
//están haciendo.

//Hay por lo menos 3 formas de accesar correctamente
//los punteros en estas funciones.


_byte LowEST_rb(void *buff, _wideword offset)
{
 return *((_byte *)buff+offset);           //OK
 return *(_byte *)((_byte *)buff+offset);  //OK
 return (_byte)*((_byte *)buff+offset);    //OK


/*

 //_byte *buf2=buff;

 //(_byte *)buff+=offset;

 (_byte *)buff+=offset;
 return (_byte *)(buff);
// return *buff;
// return (*buff+offset);
 return (*buf2+offset);//(_byte)&buff;
*/
}



_word LowEST_rw(void *buff, _wideword offset)
{
 //return *((_word *)buff+offset);  //OK
 return (*((_byte *)buff+offset))|
        (*((_byte *)buff+offset+1)<<8);

}


//This function contains a double OR error
//that could prevent to OR the result well,
//but it still compiles, so we need to be careful
//with errors like this.

/*
_dword _LowEST_rdw(void *buff, _wideword offset)
{
 //return *((_dword *)buff+offset);  //OK
 //return (_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
 return (_dword)((*((_byte *)buff+offset))|
        |(*((_byte *)buff+offset+1)<<8)
        (*((_byte *)buff+offset+2)<<16)|
        (*((_byte *)buff+offset+3)<<24));
 
 //(_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
}
*/



_dword LowEST_rdw(void *buff, _wideword offset)
{
 //return *((_dword *)buff+offset);  //OK
 //return (_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
 return (_dword)((_dword)(*((_byte *)buff+offset))|
        (_dword)(*((_byte *)buff+offset+1)<<8)|
        (_dword)(*((_byte *)buff+offset+2)<<16)|
        (_dword)(*((_byte *)buff+offset+3)<<24));
 
 return (_dword)((_dword)(*((_word *)buff+offset))|
                 (*((_word *)buff+offset+2)<<16));

 //(_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
}


_dword LowEST_rdwb(void *buff, _wideword offset)
{return 0xFFFFFFFF;
 //return *((_dword *)buff+offset);  //OK
 //return (_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
 return (_dword)((_dword)(*((_byte *)buff+offset))|
        (_dword)(*((_byte *)buff+offset+1)<<8)|
        (_dword)(*((_byte *)buff+offset+2)<<16)|
        (_dword)(*((_byte *)buff+offset+3)<<24));
 
 return (_dword)((_dword)(*((_word *)buff+offset))|
                 (*((_word *)buff+offset+2)<<16));

 //(_byte *)buff[offset+8]|((_byte *)buff[offset+9]<<8)|((_byte *)buff[offset+10]<<16)|((_byte *)buff[offset+11]<<24);
}




_wideword LowEST_rww(void *buff, _wideword offset)
{
 return *((_wideword *)buff+offset);  //OK

}








_byte LowEST_wb(void *buff, _wideword offset)
{

}



_word LowEST_ww(void *buff, _wideword offset)
{

}


_dword LowEST_wdw(void *buff, _wideword offset)
{

}


_wideword LowEST_www(void *buff, _wideword offset)
{

}








void OPCODE__FS__FAT32__print_8_3_entry__80x25(_byte *entry, int offset)
{
 int x=0;
 while(x<11)
 {
  printf("%c",entry[offset+x++]);
//  x++;
 }
}




//It's OK, but it's like C, not like assembly
//for our low level kernel/software:
///
_byte _OPCODE__FS__FAT__checksum(_byte *entry, int offset)
{
 _byte Result=0;
 int x=0;

 while(x<11)
 {
  //Result=(entry[offset+x]<<7)|(entry[offset+x]>>1);
  Result=(Result<<7)|(Result>>1);
  Result+=entry[offset+x++];
  //x++;
 }

 return Result;
}



_byte __OPCODE__FS__FAT__checksum(_byte *str, int offset)
{
 _byte Result=0;
 _byte *tests;
 _byte testsb;

 asm pushad
 
 str+=offset;


 asm mov cl,0
 //while(1)
 {
  asm .loo:
  asm pushad
  /*asm ror byte Result,1*/
  Result=(Result<<7)|(Result>>1);
  //asm mov al,str  //not good for a single char
  //asm mov testsb,al    //not good for a single char

  //testsb=*(_byte *)str; //good pointer to single char
  //asm push test
  /*asm mov bx,word ptr str    //get current local pointer variable value
  asm mov al,byte ptr [bx]   //get byte at that position in AL*/
//asm mov byte ptr testsb,al //put value in the single-byte final variable

  //asm pushad
  //printf("A{%c}L",testsb);
  //asm popad

  //asm mov tests,al

  //asm mov bx,str  //no-bad str pointer
  //asm mov bx,[str] //no-bad str pointer
  //asm mov bx,word ptr[str] //sí-buen puntero de cadena
  //asm mov bx,word ptr[[str]] //sí-buen puntero de cadena
  //asm mov bx,word ptr[[[[[[str]]]]]] //sí-buen puntero de cadena, no importan los corchetes anidados
///////  asm mov bx,word ptr str //sí-buen puntero de cadena, word ptr agrega corchetes
  //asm inc strs
  //tests=str; //sí-buen puntero de cadena
  //asm mov tests,bx
  //asm pushad
  //printf("{%s}",tests);
  //asm popad
  //asm inc strs  //dummy error catches to read good generated assembly code, etc...
  //asm inc test


  //asm mov al,byte ptr str
/////  asm mov al,byte ptr [bx]
/*  asm add Result,al
  asm inc word ptr str
  //str++;
  asm mov testsb,al
  asm pushad
  printf("{%c}",testsb);
  asm popad*/
  printf("{%c}%d",*(_byte *)str,str);
  Result+=*(_byte *)(str);
  str++;
 asm popad

  asm inc cl
  asm cmp cl,11
  asm je .endloo
  asm jmp .loo
 }

 asm .endloo:

 asm popad
 return Result+12;
}









//word ptr es un puntero a un word directo
//byte ptr a un byte directo

//TASM the complete reference


 //;Add the offset to the buffer string
 //;(we could be far from the start of this sector buffer):
 //
 //We can also add it directly to the pointer parameter as needed.
 //
 //;;
  //asm mov ax,offset
  //asm add word ptr str,ax



_byte OPCODE__FS__FAT__checksum(_byte *str)
{
 _byte Result=0;
 int x=0;


 while(x<11)
 {
  asm ror byte ptr Result,1

  asm mov bx,word ptr str    //get current local pointer variable value
  asm mov al,byte ptr [bx]   //get byte at that position in AL
  asm add byte ptr Result,al //put it into the single byte variable

  asm inc word ptr str  //go to the next char

  asm inc word ptr x
 }

 return Result;
}







//It's better to gather LFNs only if we get the last one,
//then we can directly get the total counter and the intended checksum.
//If it doesn't keep until the 8.3 name, we can discard displaying
//the entry.

//Gets up to the LFN entry indexed with 1,
//or the 8.3 name if it matches the provided checksum.
///
void OPCODE__FS__FAT32LBA__get_last_LFN_Entry(_byte *entry, int offset, _byte checksum)
{
 _wideword counter=(*(_byte *)(entry+offset))&0x3F;
 int x,sssslen;
 _dword milba=LBAFAT32;
 _byte *sect_;
 _byte sfnoff=0;


 sect_=malloc(512);
 x=0;
 while(x<512)
 {
  //sect_[x]=entry{x};
  sect_[x]=entry[x];
  x++;
 }


 //OPCODE__ATA__READ_SECTORS(0x1F0, milba, 1, 512, sect_);


 //printf("%d,%d generated CHKchain\n",OPCODE__FS__FAT__checksum(sect_+offset)&0xFF,checksum);

 //printf("%d passed CHKchain\n",checksum);
 printf("%d current counter\n",(*(_byte *)(sect_+offset))&0x3F);  //easy to get it wrong as the entry alone should be enough, but it also needs the current sector offset
 //printf("%d current offset\n",offset);

 x=0;
 while(x<4096)
 {
  LFN_name[x]=0;
  x++;
 }



 //We need to calculate up to which point we will
 //need to read entries, move to that sector,
 //and then read backwards until all data is
 //verified.
 //
 //Each entry has 13 16-bit characters (26 bytes),
 //if we have a counter of 2, we have
 //2 contiguous 32-byte entries, and
 //a 52-byte string, so we can reserve it
 //beforehand.
 //
 //This function searches the last LFN entry,
 //which is actually the 8.3 entry with all
 //the file system data. We must check that each
 //entry has the right checksum and build the rest
 //of the data/strings at the same time. It's the safest
 //and most efficient way.
 //
 //There can be up to 63 entries for an LFN name,
 //so it can need up to 3276 bytes, so knowing
 //the number of entries, how many char bytes per each,
 //we can know from which point to start saving the string.
 //
 ///
  x=(counter-1)*26;  //It will give us the start of the string
                     //from which to start saving, as the string
                     //is backwards.
  if(x==0){x=0;sssslen=26;}else sssslen=(counter)*26;
//  printf("CTR %d,",counter);
//  printf("SL %d,",sssslen);
  //x=0;
  //sssslen=x;
//  counter++;
  while(1)
  {
   if(!counter && *(sect_+offset+FAT_dirent_LFN_Checksum)!=checksum)
   {
    printf("INVALID LFN CHAIN %d,%d",checksum,*(sect_+offset+FAT_dirent_LFN_Checksum));
    break;
   }
   /*
   printf("%c",*(entry+offset+1));
   printf("%c",*(entry+offset+3));
   printf("%c",*(entry+offset+5));
   printf("%c",*(entry+offset+7));
   printf("%c",*(entry+offset+9));

   printf("%c",*(entry+offset+14));
   printf("%c",*(entry+offset+16));
   printf("%c",*(entry+offset+18));
   printf("%c",*(entry+offset+20));
   printf("%c",*(entry+offset+22));
   printf("%c",*(entry+offset+24));

   printf("%c",*(entry+offset+28));
   printf("%c",*(entry+offset+30));
   */


   LFN_name[x++]=*(sect_+offset+1);
   x++;
   LFN_name[x++]=*(sect_+offset+3);
   x++;
   LFN_name[x++]=*(sect_+offset+5);
   x++;
   LFN_name[x++]=*(sect_+offset+7);
   x++;
   LFN_name[x++]=*(sect_+offset+9);
   x++;

   LFN_name[x++]=*(sect_+offset+14);
   x++;
   LFN_name[x++]=*(sect_+offset+16);
   x++;
   LFN_name[x++]=*(sect_+offset+18);
   x++;
   LFN_name[x++]=*(sect_+offset+20);
   x++;
   LFN_name[x++]=*(sect_+offset+22);
   x++;
   LFN_name[x++]=*(sect_+offset+24);
   x++;

   LFN_name[x++]=*(sect_+offset+28);
   x++;
   LFN_name[x++]=*(sect_+offset+30);
   x++;


   //Buscar entradas LFN inválidas en todo el disco

   x-=26*2; //Go to the previous 26 characters, it will reach -1, but it doesn't matter
   if(x<0)x=0;
   //x--; //Go to the previous char

   offset+=32;
//   if(offset>=480)
   if(offset>=512)
   {
    OPCODE__ATA__READ_SECTORS(0x1F0, ++milba, 1, 512, sect_);
    offset=0;
   }
//    else
    {
     //Read previous sector and position to the last 32 bytes:
     ///
//      OPCODE__ATA__READ_SECTORS(0x1F0, ++milba, 1, 512, sect);
      //fix for actual sector, sectors per cluster, hardware sector size, and read buffer
//      offset=0;//480;
    }
   counter--;
   if(counter==0)
   {
    //Process the 8.3 entry:
    ///
      //See if we have exceeded the 512-byte sector
      //and read the next sector:
      ///

   if(offset>=512)
   {
    OPCODE__ATA__READ_SECTORS(0x1F0, ++milba, 1, 512, sect_);
    offset=0;
   }

  while(sfnoff<32)
  {
   _83_name[sfnoff]=sect_[offset+sfnoff];
   printf("%c",_83_name[sfnoff]=sect_[offset+sfnoff]);
   sfnoff++;
  }



     if(_OPCODE__FS__FAT__checksum(sect_, offset)==checksum)
     {
      printf("Checksum OK\n");
     }
     
    break;
   }
  }


 x=0;
// printf("%d slen",sssslen);
 while(x<sssslen)
 {
  printf("%c",LFN_name[x]);
  x++;
 }


 //Show file data:
 ///
  printf("Tamaño: %d",LowEST_rdw(_83_name,28));  //Calcular a mano para directorios

  if((LowEST_rb(_83_name,11)&16)==16)
  printf("<DIR>");

  printf("Clúster inicial: %ld",(_dword)LowEST_rw(_83_name,26)|((_dword)LowEST_rw(_83_name,20)<<16));  //Calcular a mano para directorios



// LBAFAT32=milba;
// sectoff=offset;

 //Implementar un men&uacute en el que podamos navegar
 //así en el orden en el que está en el disco
 //hacia arriba y abajo para solo leer una entrada
 //o una pantalla/ventana de entradas a la vez, manteniendo
 //la posición hacia antes y después de la entrada actualmente mostrada.
 //




 free(sect_);
}


_________________
Live Development (click image links for full size):
PC 1: ImagePC 2: Image


Last edited by ~ on Thu May 28, 2020 1:10 pm, edited 20 times in total.



Thu May 21, 2020 6:26 pm
Profile

Joined: Sun Sep 19, 2010 9:45 am
Posts: 29
Post Re: 2020 Project: FAT disks
Code:
_byte LowEST_rb(void *buff, _wideword offset);
_word LowEST_rw(void *buff, _wideword offset);
_dword LowEST_rdw(void *buff, _wideword offset);
_wideword LowEST_rww(void *buff, _wideword offset);

_byte LowEST_wb(void *buff, _wideword offset);
_word LowEST_ww(void *buff, _wideword offset);
_dword LowEST_wdw(void *buff, _wideword offset);
_wideword LowEST_www(void *buff, _wideword offset);






_byte LowEST_rb(void *buff, _wideword offset)
{
 _byte *buf2=buff;

 //(_byte *)buff+=offset;

 (_byte *)buff+=offset;
 return (_byte *)(buff);
// return *buff;
// return (*buff+offset);
 return (*buf2+offset);//(_byte)&buff;
}



_word LowEST_rw(void *buff, _wideword offset)
{

}


_dword LowEST_rdw(void *buff, _wideword offset)
{

}


_wideword LowEST_rww(void *buff, _wideword offset)
{

}








_byte LowEST_wb(void *buff, _wideword offset)
{

}



_word LowEST_ww(void *buff, _wideword offset)
{

}


_dword LowEST_wdw(void *buff, _wideword offset)
{

}


_wideword LowEST_www(void *buff, _wideword offset)
{

}


_________________
Live Development (click image links for full size):
PC 1: ImagePC 2: Image


Thu May 21, 2020 6:31 pm
Profile
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 


Who is online

Users browsing this forum: No registered users and 27 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by Vjacheslav Trushkin and tweaked by the BF Team.