Logo Search packages:      
Sourcecode: acorn-fdisk version File versions  Download package

riscix.c

/*
 * lib/scheme/riscix.c
 *
 * Copyright (C) 1997,1998 Russell King
 */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "util/debug.h"
#include "util/error.h"
#include "part/part.h"
#include "part/utils.h"
#include "blkio/filecore.h"
#include "scheme/filecore.h"

#define RISCIX_DEBUG
#define RISCIX_SAVE

#define RISCIX_MAX_PARTITIONS 10
#define MAX_RISCIX_NAME_LEN   16

union partition_sector_u {
  struct {
    u32 magic;
    u32 date;
    struct {
      u32 start;
      u32 length;
      u32 one;
      char name[MAX_RISCIX_NAME_LEN];
    } p[RISCIX_MAX_PARTITIONS];
  } p;
  u8 sector[FILECORE_SECTOR_SIZE];
};

static u_int
riscix_detect(part_t *part)
{
  u_char sector[FILECORE_SECTOR_SIZE];
  disc_record_t *disc_record;
  u_int ret = 0;

  dbg_printf("riscix_detect()");
  dbg_level_up();
  assert(part != NULL);

  do {
    u_int disc_csum, calc_csum;

    if (blkio_setblocksize(part->blkio, FILECORE_SECTOR_SIZE) != FILECORE_SECTOR_SIZE)
      break;

    if (blkio_read(part->blkio, sector, FILECORE_BOOT_SECTOR, 1) != 1)
      break;

    disc_csum = sector[511];
    calc_csum = filecore_checksum(sector);
    dbg_printf("-riscix disc checksum: %02X", disc_csum);
    dbg_printf("-riscix calc checksum: %02X", calc_csum);
    if (calc_csum != disc_csum)
      break;

    part->data.riscix.disc_record = *disc_record;
    part->data.riscix.boot_checksum = sector[511];

    /*
     * Check that we do not have a sector filled with zero
     */
    disc_record = (disc_record_t *)(sector + 0x1c0);
    if (disc_record->d.disc_size == 0 && disc_record->d.disc_size_high == 0)
      break;

    ret = 1;
  } while (0);

  dbg_level_down();
  dbg_printf("ret%s detected", ret ? "" : " not");

  return ret;
}

static u_int
riscix_readinfo(part_t *part)
{
  u_int ret = 0;

  dbg_printf("riscix_readinfo()");
  dbg_level_up();
  assert(part != NULL);

  do {
    disc_record_t *disc_record = &part->data.filecore_linux.disc_record;
    union partition_sector_u sector;
    partinfo_i_t pinfo;
    blk_t parttable_start;
    u_int pnr;

    /*
     * First partition is the filecore image
     */
    pinfo.info.chs_valid    = 0;
    pinfo.info.blk_start    = 0;
    pinfo.info.blk_end      = (disc_record->d.disc_size_high << (32 - 9) |
                         disc_record->d.disc_size >> 9) - 1;
    pinfo.info.type         = ptyp_filecore;
    pinfo.info.kern_part_no = 1;

    /*
     * Locate the start of the non-filecore image, and add that as
     * partition 2.  (It is always partition 2).
     */
    parttable_start = (disc_record->packing[509 - 0x1c0] |
                   disc_record->packing[510 - 0x1c0] << 8) *
                  disc_record->d.heads * disc_record->d.secspertrack;
    /*
     * If we don't have a non-filecore image, then we don't have a Linux
     * partition table, and therefore no Linux partitions.
     */
    switch (disc_record->packing[508 - 0x1c0]) {
    case 0:
      if (!part_add(part, 1, &pinfo))
        break;

      pinfo.info.chs_valid    = 0;
      pinfo.info.blk_start    = pinfo.info.blk_end + 1;
      pinfo.info.blk_end      = pinfo.info.blk_start;
      pinfo.info.type         = ptyp_reserved;
      pinfo.info.kern_part_no = 2;
      if (!part_add(part, 2, &pinfo))
        goto quit;
      ret = 1;
      goto quit;

    case 2:
      pinfo.info.blk_end = parttable_start - 1;

    case 1:
      if (!part_add(part, 1, &pinfo))
        break;

      pinfo.info.chs_valid    = 0;
      pinfo.info.blk_start    = parttable_start;
      pinfo.info.blk_end      = pinfo.info.blk_start;
      pinfo.info.type         = ptyp_linux_table;
      pinfo.info.kern_part_no = 2;

      if (blkio_read(part->blkio, &sector, parttable_start, 1) != 1)
        break;

      if (sector.p.magic != 0x4a657320)
        break;

      if (!part_add(part, 2, &pinfo))
        break;

      for (pnr = 0; pnr < RISCIX_MAX_PARTITIONS - 2; pnr++) {
        if (sector.p.p[pnr].one == 0 || memcmp(sector.p.p[pnr].name, "All", 4) == 0)
          continue;

        pinfo.info.chs_valid = 0;
        pinfo.info.blk_start = sector.p.p[pnr].start;
        pinfo.info.blk_end   = sector.p.p[pnr].start + sector.p.p[pnr].length - 1;

        if (memcmp(sector.p.p[pnr].name, "LSwap", 6) == 0)
          pinfo.info.type    = ptyp_linux_swap;
        else if (memcmp(sector.p.p[pnr].name, "LNative", 8) == 0)
          pinfo.info.type    = ptyp_linux_native;
        else
          pinfo.info.type      = ptyp_reserved;

        pinfo.info.kern_part_no = 3 + pnr;

        if (!part_add(part, pnr + 3, &pinfo))
          break;
      }

      ret = 1;
    }
  } while (0);
quit:

  dbg_level_down();
  dbg_printf("ret %s", ret ? "ok" : "error");

  return ret;
}

static u_int
riscix_writeinfo(part_t *part)
{
  u_int ret = 0;

  dbg_printf("riscix_writeinfo()");
  dbg_level_up();

  do {
    disc_record_t *disc_record = &part->data.filecore_linux.disc_record;
    union partition_sector_u sector;

    if (blkio_read(part->blkio, sector.sector, FILECORE_BOOT_SECTOR, 1) != 1)
      break;

    /*
     * Ensure that the information we read was a valid boot sector.
     * Ok, I'm being paranoid... but then partitioning is dangerous.
     */
    if (filecore_checksum(sector.sector) != sector.sector[511]) {
      set_error("filecore boot sector is corrupt");
      break;
    }
    /*
     * We check to make sure that the checksum we have here is
     * identical to that when we read the sector in riscix_readinfo.
     * If it's different, we're in trouble!
     */
    if (sector.sector[511] != part->data.filecore_linux.boot_checksum) {
      set_error("filecore boot sector has been changed by another program");
      break;
    }
    /*
     * If we have partitions > 2, then we  ave a non-ADFS descriptor.
     * Otherwise, we remove the non-ADFS descriptor  (If it wasn't a
     * RiscIX descriptor, we shouldn't be here).
     */
    if (part->nr_partitions > 2 && part->partinfo[2]) {
      u_int start_cyl;
      u_int type;

      start_cyl = part->partinfo[2]->info.blk_start /
                    (disc_record->d.heads * disc_record->d.secspertrack);

      if (part->partinfo[1]->info.blk_end ==
            (disc_record->d.disc_size_high << (32 - 9) |
           disc_record->d.disc_size >> 9) - 1)
      type = 1;
      else
        type = 2;

      /*
       * This should always be true.  If it's incorrect, then you've
       * been playing, and I'm confused.
       */
      assert(start_cyl == part->partinfo[2]->info.chs_start.cylinder);
      sector.sector[508] = type;
      sector.sector[509] = start_cyl & 255;
      sector.sector[510] = start_cyl >> 8;
    } else {
      sector.sector[508] = 0;
      sector.sector[509] = 0;
      sector.sector[510] = 0;
    }

    /*
     * We have made our changes to the boot sector.  Recalculate
     * the checksum, and don't forget to update our own copy.
     */
    sector.sector[511] = filecore_checksum(sector.sector);
    part->data.filecore_linux.boot_checksum = sector.sector[511];

#ifdef RISCIX_DEBUG
    dbg_printf("Filecore boot sector (0xc00):");
    dbg_memdump(sector.sector, FILECORE_SECTOR_SIZE);
#endif
#ifdef RISCIX_SAVE
    if (blkio_write(part->blkio, sector.sector, FILECORE_BOOT_SECTOR, 1) != 1) {
      set_error("unable to write filecore boot sector");
      break;
    }
#endif

    if (part->nr_partitions > 2 && part->partinfo[2]) {
      blk_t parttable_start = part->partinfo[2]->info.blk_start;
      u_int i;

      if (blkio_read(part->blkio, sector.sector, parttable_start, 1) != 1)
        break;

      /*
       * Now, write the partition information to the
       * RiscIX partition sectors.
       */
      if (sector.p.magic != 0x4a657320) {
        memset(sector.sector, 0, sizeof(sector.sector));

        sector.p.magic = 0x4a657320;
      }
      sector.p.date = time(NULL);

      for (i = 0; i < part->nr_partitions - 3; i++) {
        partinfo_i_t *info = part->partinfo[i + 3];

        if (info && info->info.type != ptyp_none) {
          sector.p.p[i].start  = info->info.blk_start;
          sector.p.p[i].length = info->info.blk_end - info->info.blk_start + 1;
          sector.p.p[i].one    = 1;

          switch(info->info.type) {
          case ptyp_linux_native:
          strcpy(sector.p.p[i].name, "LNative");
          break;

        case ptyp_linux_swap:
          strcpy(sector.p.p[i].name, "LSwap");
          break;

        case ptyp_reserved:
          break;

        default:
          assert(0);
        }
      }
      }
#ifdef RISCIX_DEBUG
      dbg_printf("RiscIX partition sector (0x%X):", parttable_start);
      dbg_memdump(sector.sector, FILECORE_SECTOR_SIZE);
#endif
#ifdef RISCIX_SAVE
      if (blkio_write(part->blkio, sector.sector, parttable_start, 1) != 1) {
        set_error("unable to write linux partition sector");
        break;
      }
      ret = 1;
#endif
    }
  } while (0);

#ifndef RISCIX_SAVE
  set_error("filecore-riscix partition information cannot be saved with this build");
#endif

  dbg_level_down();
  dbg_printf("ret %s", ret ? "ok" : "error");

  return ret;
}

/* Prototype: u_int riscix_allocate(part_t *part, partinfo_t *pnew)
 * Function : allocate a partition entry number and a kernel
 *            partition number for a new partition
 * Params   : part - partitionable device
 * Returns  : partition number, or PARN_ERROR on error
 */
static u_int
riscix_allocate(part_t *part, partinfo_t *pnew)
{
  u_int parn;

  dbg_printf("riscix_allocate()");
  dbg_level_up();
  assert(pnew != NULL);

  if (part->nr_partitions < 2) {
    set_error("Partition table missing");
    parn = PARN_ERROR;
  } else {
    for (parn = 3; parn < part->nr_partitions; parn++)
      if (part->partinfo[parn] == NULL)
        break;

    if (parn >= RISCIX_MAX_PARTITIONS) {
      set_error("partition table is full");
      parn = PARN_ERROR;
    } else {
      pnew->kern_part_no = parn;
      pnew->type = ptyp_linux_native;
    }
  }

  dbg_level_down();
  dbg_printf("ret %d", parn);

  return parn;
}

/* Prototype: u_int riscix_validate_change(part_t *part, u_int parn,
 *                                         const partinfo_t *pold, const partinfo_t *pnew)
 * Function : validate changes made to a partition
 * Params   : part - partitionable device
 *          : parn - partition number
 *          : pold - old partition information
 *          : pnew - new partition information
 * Returns  : FALSE if we reject the change
 */
static u_int
riscix_validate_change(part_t *part, u_int parn, const partinfo_t *pold, const partinfo_t *pnew)
{
  u_int ret = 0;

  dbg_printf("riscix_validate_change(parn=%d)", parn);
  dbg_level_up();
  assert(parn < part->nr_partitions);

  do {
    if (pnew) {
      if (pnew->type != ptyp_linux_native &&
          pnew->type != ptyp_linux_swap) {
        set_error("invalid partition type");
        break;
      }

      if (check_overlap(part, parn, pnew)) {
        set_error("the modified partition overlaps an existing partition");
        break;
      }
    }

    if (parn >= 3 && parn < part->nr_partitions)
      ret = 1;
  } while (0);

  dbg_level_down();
  dbg_printf("ret %svalid", ret ? "" : "in");

  return ret;
}

/* Prototype: u_int riscix_validate_creation(part_t *part, u_int parn,
 *                                           const partinfo_t *pold, const partinfo_t *pnew)
 * Function : validate changes made to a partition
 * Params   : part - partitionable device
 *          : parn - partition number
 *          : pold - old partition information (NULL if none)
 *          : pnew - new partition information
 * Returns  : FALSE if we reject the creation
 */
static u_int
riscix_validate_creation(part_t *part, u_int parn, const partinfo_t *pold, const partinfo_t *pnew)
{
  u_int ret = 0;

  dbg_printf("riscix_validate_creation(parn=%d)", parn);
  dbg_level_up();
  assert(parn < part->nr_partitions);

  do {
    if (pold != NULL) {
      set_error("unable to create partition in this slot");
      break;
    }

    if (pnew) {
      if (pnew->type != ptyp_linux_native &&
          pnew->type != ptyp_linux_swap) {
        set_error("invalid partition type");
        break;
      }

      if (check_overlap(part, parn, pnew)) {
        set_error("the new partition overlaps an existing partition");
        break;
      }
    }

    if (part->partinfo[2] &&
        part->partinfo[2]->info.type == ptyp_reserved)
      part->partinfo[2]->info.type = ptyp_linux_table;

    ret = 1;
  } while (0);

  dbg_level_down();
  dbg_printf("ret %svalid", ret ? "" : "in");

  return ret;
}

/* Prototype: u_int riscix_validate_deletion(part_t *part, u_int parn, const partinfo_t *pold)
 * Function : validate a deletion of a partition
 * Params   : part - partitionable device
 *          : parn - partition number
 *          : pold - old partition information
 * Returns  : FALSE if we reject the deletion
 */
static u_int
riscix_validate_deletion(part_t *part, u_int parn, const partinfo_t *pold)
{
  u_int ret = 0;

  dbg_printf("riscix_validate_deletion(parn=%d)", parn);
  dbg_level_up();
  assert(pold != NULL);
  assert(parn < part->nr_partitions);

  switch (pold->kern_part_no) {
  case 0:
  case 1: /* filecore partition */
    set_error("unable to delete filecore partition");
    break;

  case 2:
    {
      int i;

      for (i = 3; i < part->nr_partitions; i++)
        if (part->partinfo[i])
          break;

      if (i >= part->nr_partitions)
        ret = 1;
      else
        set_error("delete all partitions contained within first");
    }
    break;

  default:
    ret = 1;
    break;
  }

  dbg_level_down();
  dbg_printf("ret %svalid", ret ? "" : "in");

  return ret;
}

/* Prototype: u_int riscix_validate_partno(part_t *part, u_int parn)
 * Function : validate a partition number
 * Params   : part - partitionable device
 *          : parn - partition number
 * Returns  : FALSE if we reject the partition number
 */
static u_int
riscix_validate_partno(part_t *part, u_int parn)
{
  u_int ret = 0;

  dbg_printf("riscix_validate_partno(parn=%d)", parn);
  dbg_level_up();

  if (parn < RISCIX_MAX_PARTITIONS)
    ret = 1;
  else
    set_error("the requested partition is invalid");

  dbg_level_down();
  dbg_printf("ret %svalid", ret ? "" : "in");

  return ret;
}

scheme_t filecore_riscix_scheme = {
  "Filecore/RISCiX",
  riscix_detect,
  riscix_readinfo,
  riscix_writeinfo,
  riscix_allocate,
  riscix_validate_change,
  riscix_validate_creation,
  riscix_validate_deletion,
  riscix_validate_partno
};

Generated by  Doxygen 1.6.0   Back to index