Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:14

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_bdpart
0007  *
0008  * @brief Block Device Partition Management
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2010 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <string.h>
0041 
0042 #include <rtems.h>
0043 #include <rtems/bdbuf.h>
0044 #include <rtems/bdpart.h>
0045 #include <rtems/endian.h>
0046 
0047 static void rtems_bdpart_write_mbr_partition(
0048   uint8_t *data,
0049   uint32_t begin,
0050   uint32_t size,
0051   uint8_t type,
0052   uint8_t flags
0053 )
0054 {
0055   rtems_uint32_to_little_endian( begin, data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
0056   rtems_uint32_to_little_endian( size, data + RTEMS_BDPART_MBR_OFFSET_SIZE);
0057   data [RTEMS_BDPART_MBR_OFFSET_TYPE] = type;
0058   data [RTEMS_BDPART_MBR_OFFSET_FLAGS] = flags;
0059 }
0060 
0061 static rtems_status_code rtems_bdpart_new_record(
0062   rtems_disk_device *dd,
0063   rtems_blkdev_bnum index,
0064   rtems_bdbuf_buffer **block
0065 )
0066 {
0067   rtems_status_code sc = RTEMS_SUCCESSFUL;
0068 
0069   /* Synchronize previous block if necessary */
0070   if (*block != NULL) {
0071     sc = rtems_bdbuf_sync( *block);
0072     if (sc != RTEMS_SUCCESSFUL) {
0073       return sc;
0074     }
0075   }
0076 
0077   /* Read the new record block (this accounts for disk block sizes > 512) */
0078   sc = rtems_bdbuf_read( dd, index, block);
0079   if (sc != RTEMS_SUCCESSFUL) {
0080     return sc;
0081   }
0082 
0083   /* just in case block did not get filled in */
0084   if ( *block == NULL ) {
0085     return RTEMS_INVALID_ADDRESS;
0086   }
0087 
0088   /* Clear record */
0089   memset( (*block)->buffer, 0, RTEMS_BDPART_BLOCK_SIZE);
0090 
0091   /* Write signature */
0092   (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0] =
0093     RTEMS_BDPART_MBR_SIGNATURE_0;
0094   (*block)->buffer [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1] =
0095     RTEMS_BDPART_MBR_SIGNATURE_1;
0096 
0097   return RTEMS_SUCCESSFUL;
0098 }
0099 
0100 rtems_status_code rtems_bdpart_write(
0101   const char *disk_name,
0102   const rtems_bdpart_format *format,
0103   const rtems_bdpart_partition *pt,
0104   size_t count
0105 )
0106 {
0107   rtems_status_code sc = RTEMS_SUCCESSFUL;
0108   rtems_status_code esc = RTEMS_SUCCESSFUL;
0109   bool dos_compatibility = format != NULL
0110     && format->type == RTEMS_BDPART_FORMAT_MBR
0111     && format->mbr.dos_compatibility;
0112   rtems_bdbuf_buffer *block = NULL;
0113   rtems_blkdev_bnum disk_end = 0;
0114   rtems_blkdev_bnum record_space =
0115     dos_compatibility ? RTEMS_BDPART_MBR_CYLINDER_SIZE : 1;
0116   size_t ppc = 0; /* Primary partition count */
0117   size_t i = 0;
0118   uint8_t *data = NULL;
0119   int fd = -1;
0120   rtems_disk_device *dd = NULL;
0121 
0122   /* Check if we have something to do */
0123   if (count == 0) {
0124     /* Nothing to do */
0125     return RTEMS_SUCCESSFUL;
0126   }
0127 
0128   /* Check parameter */
0129   if (format == NULL || pt == NULL) {
0130     return RTEMS_INVALID_ADDRESS;
0131   }
0132 
0133   /* Get disk data */
0134   sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
0135   if (sc != RTEMS_SUCCESSFUL) {
0136     return sc;
0137   }
0138 
0139   /* Align end of disk on cylinder boundary if necessary */
0140   if (dos_compatibility) {
0141     disk_end -= (disk_end % record_space);
0142   }
0143 
0144   /* Check that we have a consistent partition table */
0145   for (i = 0; i < count; ++i) {
0146     const rtems_bdpart_partition *p = pt + i;
0147 
0148     /* Check that begin and end are proper within the disk */
0149     if (p->begin >= disk_end || p->end > disk_end) {
0150       esc = RTEMS_INVALID_NUMBER;
0151       goto cleanup;
0152     }
0153 
0154     /* Check that begin and end are valid */
0155     if (p->begin >= p->end) {
0156       esc = RTEMS_INVALID_NUMBER;
0157       goto cleanup;
0158     }
0159 
0160     /* Check that partitions do not overlap */
0161     if (i > 0 && pt [i - 1].end > p->begin) {
0162       esc = RTEMS_INVALID_NUMBER;
0163       goto cleanup;
0164     }
0165   }
0166 
0167   /* Check format */
0168   if (format->type != RTEMS_BDPART_FORMAT_MBR) {
0169     esc = RTEMS_NOT_IMPLEMENTED;
0170     goto cleanup;
0171   }
0172 
0173   /*
0174    * Set primary partition count.  If we have more than four partitions we need
0175    * an extended partition which will contain the partitions of number four and
0176    * above as logical partitions.  If we have four or less partitions we can
0177    * use the primary partition table.
0178    */
0179   ppc = count <= 4 ? count : 3;
0180 
0181   /*
0182    * Check that the first primary partition starts at head one and sector one
0183    * under the virtual one head and 63 sectors geometry if necessary.
0184    */
0185   if (dos_compatibility && pt [0].begin != RTEMS_BDPART_MBR_CYLINDER_SIZE) {
0186     esc = RTEMS_INVALID_NUMBER;
0187     goto cleanup;
0188   }
0189 
0190   /*
0191    * Check that we have enough space for the EBRs.  The partitions with number
0192    * four and above are logical partitions if we have more than four partitions
0193    * in total.  The logical partitions are contained in the extended partition.
0194    * Each logical partition is described via one EBR preceding the partition.
0195    * The space for the EBR and maybe some space which is needed for DOS
0196    * compatibility resides between the partitions.  So there have to be gaps of
0197    * the appropriate size between the partitions.
0198    */
0199   for (i = ppc; i < count; ++i) {
0200     if ((pt [i].begin - pt [i - 1].end) < record_space) {
0201       esc = RTEMS_INVALID_NUMBER;
0202       goto cleanup;
0203     }
0204   }
0205 
0206   /* Check that we can convert the parition descriptions to the MBR format */
0207   for (i = 0; i < count; ++i) {
0208     uint8_t type = 0;
0209 
0210     const rtems_bdpart_partition *p = pt + i;
0211 
0212     /* Check type */
0213     if (!rtems_bdpart_to_mbr_partition_type( p->type, &type)) {
0214       esc =  RTEMS_INVALID_ID;
0215       goto cleanup;
0216     }
0217 
0218     /* Check flags */
0219     if (p->flags > 0xffU) {
0220       esc = RTEMS_INVALID_ID;
0221       goto cleanup;
0222     }
0223 
0224     /* Check ID */
0225     /* TODO */
0226   }
0227 
0228   /* New MBR */
0229   sc = rtems_bdpart_new_record( dd, 0, &block);
0230   if (sc != RTEMS_SUCCESSFUL) {
0231     esc = sc;
0232     goto cleanup;
0233   }
0234 
0235   /* Write disk ID */
0236   rtems_uint32_to_little_endian(
0237     format->mbr.disk_id,
0238     block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
0239   );
0240 
0241   /* Write primary partition table */
0242   data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
0243   for (i = 0; i < ppc; ++i) {
0244     const rtems_bdpart_partition *p = pt + i;
0245 
0246     /* Write partition entry */
0247     rtems_bdpart_write_mbr_partition(
0248       data,
0249       p->begin,
0250       p->end - p->begin,
0251       rtems_bdpart_mbr_partition_type( p->type),
0252       (uint8_t) p->flags
0253     );
0254 
0255     data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
0256   }
0257 
0258   /* Write extended partition with logical partitions if necessary */
0259   if (ppc != count) {
0260     rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
0261 
0262     /* Begin of extended partition */
0263     rtems_blkdev_bnum ep_begin = pt [ppc].begin - record_space;
0264 
0265     /* Write extended partition */
0266     rtems_bdpart_write_mbr_partition(
0267       data,
0268       ep_begin,
0269       disk_end - ep_begin,
0270       RTEMS_BDPART_MBR_EXTENDED,
0271       0
0272     );
0273 
0274     /* Write logical partitions */
0275     for (i = ppc; i < count; ++i) {
0276       const rtems_bdpart_partition *p = pt + i;
0277 
0278       /* Write second partition entry */
0279       if (i > ppc) {
0280         rtems_blkdev_bnum begin = p->begin - record_space;
0281 
0282         rtems_bdpart_write_mbr_partition(
0283           block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1,
0284           begin - ep_begin,
0285           disk_end - begin,
0286           RTEMS_BDPART_MBR_EXTENDED,
0287           0
0288         );
0289       }
0290 
0291       /* New EBR */
0292       ebr = p->begin - record_space;
0293       sc = rtems_bdpart_new_record( dd, ebr, &block);
0294       if (sc != RTEMS_SUCCESSFUL) {
0295         esc = sc;
0296         goto cleanup;
0297       }
0298 
0299       /* Write first partition entry */
0300       rtems_bdpart_write_mbr_partition(
0301         block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
0302         record_space,
0303         p->end - p->begin,
0304         rtems_bdpart_mbr_partition_type( p->type),
0305         (uint8_t) p->flags
0306       );
0307     }
0308   }
0309 
0310 cleanup:
0311 
0312   if (fd >= 0) {
0313     close( fd);
0314   }
0315 
0316   if (block != NULL) {
0317     rtems_bdbuf_sync( block);
0318   }
0319 
0320   return esc;
0321 }