sunpc.c 3.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/* sunpc.c - Read SUN PC style partition tables.  */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2002,2005,2006,2007,2009  Free Software Foundation, Inc.
 *
 *  GRUB is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GRUB is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <grub/partition.h>
#include <grub/disk.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/dl.h>
#include <grub/symbol.h>
#include <grub/types.h>
#include <grub/err.h>

29 30
GRUB_MOD_LICENSE ("GPLv3+");

31 32 33 34 35 36 37 38 39 40
#define GRUB_PARTMAP_SUN_PC_MAGIC 0xDABE
#define GRUB_PARTMAP_SUN_PC_MAX_PARTS 16
#define GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID 0x05

struct grub_sun_pc_partition_descriptor
{
  grub_uint16_t id;
  grub_uint16_t unused;
  grub_uint32_t start_sector;
  grub_uint32_t num_sectors;
41
} GRUB_PACKED;
42 43 44 45 46 47 48 49

struct grub_sun_pc_block
{
  grub_uint8_t unused[72];
  struct grub_sun_pc_partition_descriptor partitions[GRUB_PARTMAP_SUN_PC_MAX_PARTS];
  grub_uint8_t unused2[244];
  grub_uint16_t  magic;         /* Magic number.  */
  grub_uint16_t  csum;          /* Label xor'd checksum.  */
50
} GRUB_PACKED;
51 52 53 54 55

static struct grub_partition_map grub_sun_pc_partition_map;

/* Verify checksum (true=ok).  */
static int
56
grub_sun_is_valid (grub_uint16_t *label)
57 58 59 60
{
  grub_uint16_t *pos;
  grub_uint16_t sum = 0;

61 62
  for (pos = label;
       pos < (label + sizeof (struct grub_sun_pc_block) / 2);
63 64 65 66 67 68 69 70
       pos++)
    sum ^= *pos;

  return ! sum;
}

static grub_err_t
sun_pc_partition_map_iterate (grub_disk_t disk,
71 72
			      grub_partition_iterate_hook_t hook,
			      void *hook_data)
73 74
{
  grub_partition_t p;
75 76
  union
  {
77
    struct grub_sun_pc_block sun_block;
78 79
    grub_uint16_t raw[0];
  } block;
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
  int partnum;
  grub_err_t err;

  p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
  if (! p)
    return grub_errno;

  p->partmap = &grub_sun_pc_partition_map;
  err = grub_disk_read (disk, 1, 0, sizeof (struct grub_sun_pc_block), &block);
  if (err)
    {
      grub_free (p);
      return err;
    }
  
95
  if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sun_block.magic))
96 97 98 99 100 101
    {
      grub_free (p);
      return grub_error (GRUB_ERR_BAD_PART_TABLE, 
			 "not a sun_pc partition table");
    }

102
  if (! grub_sun_is_valid (block.raw))
103 104 105 106 107 108 109 110 111 112 113
    {
      grub_free (p);
      return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum");
    }

  /* Maybe another error value would be better, because partition
     table _is_ recognized but invalid.  */
  for (partnum = 0; partnum < GRUB_PARTMAP_SUN_PC_MAX_PARTS; partnum++)
    {
      struct grub_sun_pc_partition_descriptor *desc;

114 115
      if (block.sun_block.partitions[partnum].id == 0
	  || block.sun_block.partitions[partnum].id
116
	  == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID)
117 118
	continue;

119
      desc = &block.sun_block.partitions[partnum];
120 121 122 123 124
      p->start = grub_le_to_cpu32 (desc->start_sector);
      p->len = grub_le_to_cpu32 (desc->num_sectors);
      p->number = partnum;
      if (p->len)
	{
125
	  if (hook (disk, p, hook_data))
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	    partnum = GRUB_PARTMAP_SUN_PC_MAX_PARTS;
	}
    }

  grub_free (p);

  return grub_errno;
}

/* Partition map type.  */
static struct grub_partition_map grub_sun_pc_partition_map =
  {
    .name = "sunpc",
    .iterate = sun_pc_partition_map_iterate,
  };

142
GRUB_MOD_INIT(part_sunpc)
143 144 145 146
{
  grub_partition_map_register (&grub_sun_pc_partition_map);
}

147
GRUB_MOD_FINI(part_sunpc)
148 149 150 151
{
  grub_partition_map_unregister (&grub_sun_pc_partition_map);
}