Subversion Repositories SvarDOS

Rev

Rev 1939 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1939 Rev 1940
Line 601... Line 601...
601
  }
601
  }
602
  return(result);
602
  return(result);
603
}
603
}
604
 
604
 
605
 
605
 
606
/* computes a BSD sum of a block of 512 bytes */
-
 
607
static unsigned short bootsum(void *buff) {
-
 
608
  unsigned short b, sum = 0;
-
 
609
  for (b = 0; b < 256; b++) { /* 256 because I read 16 bits at a time */
-
 
610
    sum <<= 1;
-
 
611
    sum += ((unsigned short *)buff)[b];
-
 
612
  }
-
 
613
  return(sum);
-
 
614
}
-
 
615
 
-
 
616
 
-
 
617
/* read one sector from driveid (0x80, 0x81..) at C,H,S into buff */
606
/* read MBR of driveid (0x80, 0x81..) into buff */
618
static int READSEC_CHS(char *buff, unsigned char driveid, unsigned short cyl, unsigned char head, unsigned char sec);
607
static int READMBR(char *buff, unsigned char driveid);
619
#pragma aux READSEC_CHS = \
608
#pragma aux READMBR = \
620
"push es" \
609
"push es" \
621
"mov ch, al" \
-
 
622
"shl ah, 1" \
-
 
623
"shl ah, 1" \
-
 
624
"shl ah, 1" \
-
 
625
"shl ah, 1" \
-
 
626
"shl ah, 1" \
-
 
627
"shl ah, 1" \
-
 
628
"or cl, ah" \
-
 
629
"mov ax, 0x0201"  /* read 1 sector into memory */ \
610
"mov ax, 0x0201"  /* read 1 sector into memory */ \
-
 
611
"mov cx, 0x0001"  /* cylinder 0, sector 1 */ \
-
 
612
"xor dh, dh"      /* head 0 */ \
630
"push ds" \
613
"push ds" \
631
"pop es" \
614
"pop es" \
632
"int 0x13" \
615
"int 0x13" \
633
"mov ax, 0" /* do not do "xor ax, ax", CF needs to be preserved */ \
616
"mov ax, 0" /* do not do "xor ax, ax", CF needs to be preserved */ \
634
"jnc DONE" \
617
"jnc DONE" \
635
"inc ax" \
618
"inc ax" \
636
"DONE:" \
619
"DONE:" \
637
"pop es" \
620
"pop es" \
638
parm [bx] [dl] [ax] [dh] [cl] \
621
parm [bx] [dl] \
639
modify [cx] \
622
modify [cx dx] \
640
value [ax]
623
value [ax]
641
 
624
 
642
 
625
 
643
/*
626
/*
644
 * MBR structure:
627
 * MBR structure:
Line 664... Line 647...
664
 * 0x08  LBA addr of first sector (4 bytes) - used sometimes instead of CHS
647
 * 0x08  LBA addr of first sector (4 bytes) - used sometimes instead of CHS
665
 * 0x0C  number of sectors in partition (4 bytes)
648
 * 0x0C  number of sectors in partition (4 bytes)
666
 */
649
 */
667
 
650
 
668
struct drivelist {
651
struct drivelist {
669
  union {
-
 
670
    unsigned long lbasector;
652
  unsigned long start_lba;
671
    struct {
-
 
672
      unsigned short c;
653
  unsigned long tot_sect; /* size (of partition), in sectors */
673
      unsigned char h;
-
 
674
      unsigned char s;
654
  unsigned short tot_size; /* size in MiB */
675
    } chs;
-
 
676
  } start;
-
 
677
  unsigned char active;
655
  unsigned char active;
678
  unsigned char fstype; /* fat16 chs, fat16 lba, fat32 chs, fat32 lba... */
-
 
679
  unsigned char hd; /* 0x80, 0x81... */
656
  unsigned char hd; /* 0x80, 0x81... */
680
  unsigned char dos_id;  /* A=1, B=2, C=3, etc... 0 = unknown */
657
  unsigned char dosid;   /* DOS drive id (A=1, B=2...)*/
-
 
658
};
-
 
659
 
-
 
660
 
-
 
661
/* a (very partial) struct mimicking what EDR-DOS uses in int 2Fh,AX=0803h */
-
 
662
#pragma pack (push)
-
 
663
#pragma pack (0) /* disable the automatic alignment of struct members */
-
 
664
struct dos_udsc {
681
  unsigned short dos_size; /* size, as provided by DOS (in MiB) */
665
  unsigned short next_off;   /* offset FFFFh if last */
-
 
666
  unsigned short next_seg;
-
 
667
  unsigned char hd;     /* physical unit, as used by int 13h */
-
 
668
  unsigned char letter; /* DOS letter drive (A=0, B=1, C=2, ...) */
682
  unsigned short bootsum; /* hash-like sum of the bootcode area */
669
  unsigned short sectsize; /* bytes per sector */
-
 
670
  unsigned char unknown[15];
-
 
671
  unsigned long start_lba; /* LBA address of the partition (only for primary partitions) */
683
};
672
};
-
 
673
#pragma pack (pop)
-
 
674
 
-
 
675
 
-
 
676
/* get the DOS drive data table list */
-
 
677
static struct dos_udsc far *get_dos_udsc(void)  {
-
 
678
  unsigned short udsc_seg = 0, udsc_off = 0;
-
 
679
  _asm {
-
 
680
    push ds
-
 
681
    push di
-
 
682
 
-
 
683
    mov ax, 0x0803
-
 
684
    int 0x2f
-
 
685
    /* drive data table list is in DS:DI now */
-
 
686
    mov udsc_seg, ds
-
 
687
    mov udsc_off, di
-
 
688
 
-
 
689
    pop di
-
 
690
    pop ds
-
 
691
  }
-
 
692
  if (udsc_off == 0xffff) return(NULL);
-
 
693
  return(MK_FP(udsc_seg, udsc_off));
-
 
694
}
-
 
695
 
684
 
696
 
-
 
697
/* reads the MBR and matches its entries to DOS drives
-
 
698
 * see https://github.com/SvarDOS/bugz/issues/89 */
685
int get_drives_list(char *buff, struct drivelist *drives) {
699
int get_drives_list(char *buff, struct drivelist *drives) {
686
  int i;
700
  int i;
-
 
701
  struct dos_udsc far *udsc_root = get_dos_udsc();
-
 
702
  struct dos_udsc far *udsc_node;
-
 
703
 
687
  if (READSEC_CHS(buff, 0x80, 0, 0, 1) != 0) return(1);
704
  if (READMBR(buff, 0x80) != 0) return(1);
688
 
705
 
689
  /* check boot signature at 0x01fe */
706
  /* check boot signature at 0x01fe */
690
  if (*(unsigned short *)(buff + 0x01fe) != 0xAA55) return(2);
707
  if (*(unsigned short *)(buff + 0x01fe) != 0xAA55) return(2);
691
 
708
 
692
  /* iterate over the 4 partitions */
709
  /* iterate over the 4 partitions in the MBR */
693
  for (i = 0; i < 4; i++) {
710
  for (i = 0; i < 4; i++) {
694
    unsigned char *entry;
711
    unsigned char *entry;
695
    bzero(&(drives[i]), sizeof(struct drivelist));
712
    bzero(&(drives[i]), sizeof(struct drivelist));
696
 
713
 
697
    entry = buff + 0x01BE + (i * 16);
714
    entry = buff + 0x01BE + (i * 16);
698
 
715
 
699
    if ((entry[4] == 0x0E) || (entry[4] == 0x0C)) { /* LBA FAT */
716
    /* ignore partition if fs is unknown (non-FAT) */
700
      drives[i].start.lbasector = ((unsigned long *)entry)[2];
717
    if ((entry[4] != 0x0E) && (entry[4] != 0x0C)  /* LBA FAT */
701
    } else if ((entry[4] == 0x01) || (entry[4] == 0x06) || (entry[4] == 0x08)) { /* CHS FAT */
718
     && (entry[4] != 0x01) && (entry[4] != 0x06) && (entry[4] != 0x08)) { /* CHS FAT */
702
      drives[i].start.chs.c = entry[0x02] & 0xC0;
-
 
703
      drives[i].start.chs.c <<= 2;
-
 
704
      drives[i].start.chs.c |= entry[0x03];
-
 
705
      drives[i].start.chs.h = entry[0x01];
-
 
706
      drives[i].start.chs.s = entry[0x02] & 63;
-
 
707
    } else { /* unknown filesystem (non-FAT) */
-
 
708
      continue;
719
      continue;
709
    }
720
    }
710
    drives[i].hd = 0x80;
721
    drives[i].hd = 0x80;
711
    drives[i].active = entry[0] >> 7;
722
    drives[i].active = entry[0] >> 7;
-
 
723
    drives[i].start_lba = ((unsigned long *)entry)[2];
712
    drives[i].fstype = entry[4];
724
    drives[i].tot_sect = ((unsigned long *)entry)[3];
713
  }
-
 
714
 
725
 
715
  /* load the boot sector of each (valid) partition and compute its sum */
726
    /* now iterate over DOS drives and try to match ont to this MBR entry */
-
 
727
    udsc_node = udsc_root;
716
  for (i = 0; i < 4; i++) {
728
    while (udsc_node != NULL) {
717
    if (drives[i].hd == 0) continue;
729
      if (udsc_node->hd != 0x80) goto NEXT;
718
    if ((drives[i].fstype == 0x0E) || (drives[i].fstype == 0x0C)) { /* LBA */
730
      if (udsc_node->start_lba != drives[i].start_lba) goto NEXT;
-
 
731
 
719
      printf("LBA!\n");
732
      /* FOUND! */
-
 
733
      drives[i].dosid = udsc_node->letter + 1;
720
    } else { /* CHS */
734
      {
721
      if (READSEC_CHS(buff, 0x80, drives[i].start.chs.c, drives[i].start.chs.h, drives[i].start.chs.s) == 0) {
735
        unsigned long sz = (drives[i].tot_sect * udsc_node->sectsize) >> 20;
722
        drives[i].bootsum = bootsum(buff);
736
        drives[i].tot_size = (unsigned short)sz;
723
      }
737
      }
724
    }
-
 
725
  }
-
 
726
 
-
 
727
  /* now iterate over DOS drives and try to match them to an entry in drives[] */
-
 
728
  for (i = 3; i < 8; i++) {
-
 
729
    unsigned short err = 0, sum, b;
-
 
730
    if (isdriveremovable(i) <= 0) {
-
 
731
      printf("SKIPPED = %u\n", i);
-
 
732
      continue;
-
 
733
    }
-
 
734
    _asm {
-
 
735
      push ax
-
 
736
      push bx
-
 
737
      push cx
-
 
738
      push dx
-
 
739
      push di
-
 
740
      push si
-
 
741
      pushf
-
 
742
 
-
 
743
      mov ax, i
-
 
744
      dec ax     /* int 25h takes zero-based drive id (A=0, B=1, C=3, ...) */
-
 
745
      mov cx, 1
-
 
746
      mov dx, 0
-
 
747
      mov bx, buff
-
 
748
      int 0x25
-
 
749
      jnc GOOD
-
 
750
      mov err, 1
-
 
751
      GOOD:
-
 
752
      pop dx     /* int 25h leaves a word on stack, needs to be POPed */
-
 
753
 
-
 
754
      /* extensive push/pop saving of registers because according to RBIL
-
 
755
       * int25h may destroy all registers except segment registers */
-
 
756
 
-
 
757
      popf
-
 
758
      pop si
-
 
759
      pop di
-
 
760
      pop dx
-
 
761
      pop cx
-
 
762
      pop bx
-
 
763
      pop ax
738
      break;
764
    }
-
 
765
 
-
 
766
    if (err != 0) {
-
 
767
      printf("INT25 ERR FOR DRV %u!\n", i);
-
 
768
      continue;
-
 
769
    }
-
 
770
 
739
 
771
    /* compute the sum of this sector */
-
 
772
    sum = bootsum(buff);
740
      NEXT:
773
 
-
 
774
    /* try to match the sum to something in drives[] */
-
 
775
    for (b = 0; b < 4; b++) {
-
 
776
      if (drives[b].hd == 0) continue;
741
      if (udsc_node->next_off == 0xffff) break;
777
      printf("%c: sum = %04X  /  drive[%u].sum = %04X\n", '@' + i, sum, b, drives[b].bootsum);
742
      udsc_node = MK_FP(udsc_node->next_seg, udsc_node->next_off);
778
      if (drives[b].bootsum == sum) {
-
 
779
        drives[b].dos_id = i;
-
 
780
        drives[b].dos_size = disksize(i);
-
 
781
        break;
-
 
782
      }
-
 
783
    }
743
    }
784
  }
744
  }
785
 
745
 
786
  return(0);
746
  return(0);
787
}
747
}
788
 
748
 
789
 
749
 
790
static int preparedrive(void) {
750
static int preparedrive(void) {
791
  int selecteddrive;
751
  int selecteddrive;
792
  char cselecteddrive;
752
  char cselecteddrive;
793
  int ds;
-
 
794
  int choice;
753
  int choice;
795
  char buff[512];
754
  char buff[512];
796
  int driveid = 1; /* fdisk runs on first drive (unless USB boot) */
755
  int driveid = 1; /* fdisk runs on first drive (unless USB boot) */
797
  struct drivelist drives[4];
756
  struct drivelist drives[4];
798
 
757
 
799
  for (;;) {
-
 
800
    char drvlist[4][32]; /* C: [2048 MB] */
-
 
801
    int i, drvlistlen = 0;
758
  /* read MBR of first HDD */
802
 
759
  {
803
    /* read MBR of first HDD */
760
    int i;
804
    i = get_drives_list(buff, drives);
761
    i = get_drives_list(buff, drives);
805
    if (i) {
762
    if (i) {
806
      printf("get_drives_list() error = %d", i);
763
      printf("get_drives_list() error = %d", i);
807
    }
764
    }
-
 
765
  }
808
 
766
 
809
    sleep(5);
767
  for (;;) {
-
 
768
    char drvlist[4][40]; /* C: [2048 MB] */
-
 
769
    int i, drvlistlen = 0;
810
 
770
 
811
    /* build a menu with all non-removable drives from C to F */
771
    /* build a menu with all drives */
812
    for (i = 3; i < 7; i++) {
772
    for (i = 0; i < 4; i++) {
813
      if (isdriveremovable(i) >= 0) {
773
      if (drives[i].hd == 0) continue;
814
        unsigned char drvid;
-
 
815
        /* is it in drives? */
-
 
816
        for (drvid = 0; drvid < 4; drvid++) if (drives[drvid].dos_id == i) break;
-
 
817
        if (drvid < 4) {
-
 
818
          snprintf(drvlist[drvlistlen], sizeof(drvlist[0]), "%c: [%u MiB, #%u, act=%u]", '@' + i, drives[drvid].dos_size, drvid, drives[drvid].active);
774
      snprintf(drvlist[drvlistlen], sizeof(drvlist[0]), "%c: [%u MiB, hd%c%u, act=%u]", '@' + drives[i].dosid, drives[i].tot_size, 'a' + (drives[i].hd & 127), i, drives[i].active);
819
        } else if (disksize(i) == 0xffff) {
-
 
820
          snprintf(drvlist[drvlistlen], sizeof(drvlist[0]), "%c: (unformatted)", '@' + i);
-
 
821
        } else {
-
 
822
          continue;
-
 
823
        }
-
 
824
        drvlistlen++;
775
      drvlistlen++;
825
      }
-
 
826
    }
776
    }
827
 
777
 
828
    /* if no drive found - disk not partitioned? */
778
    /* if no drive found - disk not partitioned? */
829
    if (drvlistlen == 0) {
779
    if (drvlistlen == 0) {
830
      const char *list[4];
780
      const char *list[4];
Line 904... Line 854...
904
      exec(buff);
854
      exec(buff);
905
      continue;
855
      continue;
906
    }
856
    }
907
 
857
 
908
    /* check total disk space */
858
    /* check total disk space */
-
 
859
    {
909
    ds = disksize(selecteddrive);
860
      int ds = disksize(selecteddrive);
910
    if (ds < SVARDOS_DISK_REQ) {
861
      if (ds < SVARDOS_DISK_REQ) {
911
      int y = 9;
862
        int y = 9;
912
      newscreen(2);
863
        newscreen(2);
913
      snprintf(buff, sizeof(buff), svarlang_strid(0x0304), cselecteddrive, SVARDOS_DISK_REQ); /* "ERROR: Drive %c: is not big enough! SvarDOS requires a disk of at least %d MiB." */
864
        snprintf(buff, sizeof(buff), svarlang_strid(0x0304), cselecteddrive, SVARDOS_DISK_REQ); /* "ERROR: Drive %c: is not big enough! SvarDOS requires a disk of at least %d MiB." */
914
      y += putstringwrap(y, 1, COLOR_BODY, buff);
865
        y += putstringwrap(y, 1, COLOR_BODY, buff);
915
      putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
866
        putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
916
      mdr_dos_getkey();
867
        mdr_dos_getkey();
917
      return(MENUQUIT);
868
        return(MENUQUIT);
-
 
869
      }
918
    }
870
    }
919
 
871
 
920
    /* is the disk empty? */
872
    /* is the disk empty? */
921
    newscreen(0);
873
    newscreen(0);
922
    if (diskempty(selecteddrive) != 0) {
874
    if (diskempty(selecteddrive) != 0) {