/* Send a SCSI request for DISK: write the data stored in BUF to SIZE sectors starting with SECTOR. */ static grub_err_t grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) { grub_scsi_t scsi; struct grub_scsi_write12 wr; grub_err_t err; grub_err_t err_sense; scsi = disk->data; wr.opcode = grub_scsi_cmd_write12; wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; wr.lba = grub_cpu_to_be32 (sector); wr.size = grub_cpu_to_be32 (size); wr.reserved = 0; wr.control = 0; err = scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * scsi->blocksize, buf); /* Each SCSI command should be followed by Request Sense. If not so, many devices STALLs or definitely freezes. */ err_sense = grub_scsi_request_sense (scsi); if (err_sense != GRUB_ERR_NONE) grub_errno = err; /* err_sense is ignored for now and Request Sense Data also... */ return err; }
/* Send a SCSI request for DISK: write the data stored in BUF to SIZE sectors starting with SECTOR. */ static grub_err_t grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) { grub_scsi_t scsi; struct grub_scsi_write10 wr; scsi = disk->data; wr.opcode = grub_scsi_cmd_write12; wr.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; wr.lba = grub_cpu_to_be32 (sector); wr.size = grub_cpu_to_be32 (size); wr.reserved = 0; wr.pad = 0; return scsi->dev->write (scsi, sizeof (wr), (char *) &wr, size * 512, buf); }
/* Send a SCSI request for DISK: read SIZE sectors starting with sector SECTOR to BUF. */ static grub_err_t grub_scsi_read12 (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) { grub_scsi_t scsi; struct grub_scsi_read12 rd; scsi = disk->data; rd.opcode = grub_scsi_cmd_read12; rd.lun = scsi->lun << GRUB_SCSI_LUN_SHIFT; rd.lba = grub_cpu_to_be32 (sector); rd.size = grub_cpu_to_be32 (size); rd.reserved = 0; rd.control = 0; return scsi->dev->read (scsi, sizeof (rd), (char *) &rd, size * 512, buf); }
/* Mount the filesystem on the disk DISK. */ static struct grub_hfs_data * grub_hfs_mount (grub_disk_t disk) { struct grub_hfs_data *data; struct grub_hfs_catalog_key key; struct grub_hfs_dirrec dir; int first_block; struct { struct grub_hfs_node node; struct grub_hfs_treeheader head; } treehead; data = grub_malloc (sizeof (struct grub_hfs_data)); if (!data) return 0; /* Read the superblock. */ if (grub_disk_read (disk, GRUB_HFS_SBLOCK, 0, sizeof (struct grub_hfs_sblock), &data->sblock)) goto fail; /* Check if this is a HFS filesystem. */ if (grub_be_to_cpu16 (data->sblock.magic) != GRUB_HFS_MAGIC) { grub_error (GRUB_ERR_BAD_FS, "not an HFS filesystem"); goto fail; } /* Check if this is an embedded HFS+ filesystem. */ if (grub_be_to_cpu16 (data->sblock.embed_sig) == GRUB_HFS_EMBED_HFSPLUS_SIG) { grub_error (GRUB_ERR_BAD_FS, "embedded HFS+ filesystem"); goto fail; } data->blksz = grub_be_to_cpu32 (data->sblock.blksz); data->disk = disk; /* Lookup the root node of the extent overflow tree. */ first_block = ((grub_be_to_cpu16 (data->sblock.extent_recs[0].first_block) * GRUB_HFS_BLKS) + grub_be_to_cpu16 (data->sblock.first_block)); if (grub_disk_read (data->disk, first_block, 0, sizeof (treehead), &treehead)) goto fail; data->ext_root = grub_be_to_cpu32 (treehead.head.root_node); data->ext_size = grub_be_to_cpu16 (treehead.head.node_size); /* Lookup the root node of the catalog tree. */ first_block = ((grub_be_to_cpu16 (data->sblock.catalog_recs[0].first_block) * GRUB_HFS_BLKS) + grub_be_to_cpu16 (data->sblock.first_block)); if (grub_disk_read (data->disk, first_block, 0, sizeof (treehead), &treehead)) goto fail; data->cat_root = grub_be_to_cpu32 (treehead.head.root_node); data->cat_size = grub_be_to_cpu16 (treehead.head.node_size); /* Lookup the root directory node in the catalog tree using the volume name. */ key.parent_dir = grub_cpu_to_be32 (1); key.strlen = data->sblock.volname[0]; grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1)); if (grub_hfs_find_node (data, (char *) &key, data->cat_root, 0, (char *) &dir, sizeof (dir)) == 0) { grub_error (GRUB_ERR_BAD_FS, "cannot find the HFS root directory"); goto fail; } if (grub_errno) goto fail; data->rootdir = grub_be_to_cpu32 (dir.dirid); return data; fail: grub_free (data); if (grub_errno == GRUB_ERR_OUT_OF_RANGE) grub_error (GRUB_ERR_BAD_FS, "not a HFS filesystem"); return 0; }
/* Find block BLOCK of the file FILE in the mounted UFS filesystem DATA. The first 3 extents are described by DAT. If cache is set, using caching to improve non-random reads. */ static unsigned int grub_hfs_block (struct grub_hfs_data *data, grub_hfs_datarecord_t dat, int file, int block, int cache) { grub_hfs_datarecord_t dr; int pos = 0; struct grub_hfs_extent_key key; int tree = 0; static int cache_file = 0; static int cache_pos = 0; static grub_hfs_datarecord_t cache_dr; grub_memcpy (dr, dat, sizeof (dr)); key.forktype = 0; key.fileid = grub_cpu_to_be32 (file); if (cache && cache_file == file && block > cache_pos) { pos = cache_pos; key.first_block = grub_cpu_to_be16 (pos); grub_memcpy (dr, cache_dr, sizeof (cache_dr)); } for (;;) { int i; /* Try all 3 extents. */ for (i = 0; i < 3; i++) { /* Check if the block is stored in this extent. */ if (grub_be_to_cpu16 (dr[i].count) + pos > block) { int first = grub_be_to_cpu16 (dr[i].first_block); /* If the cache is enabled, store the current position in the tree. */ if (tree && cache) { cache_file = file; cache_pos = pos; grub_memcpy (cache_dr, dr, sizeof (cache_dr)); } return (grub_be_to_cpu16 (data->sblock.first_block) + (first + block - pos) * GRUB_HFS_BLKS); } /* Try the next extent. */ pos += grub_be_to_cpu16 (dr[i].count); } /* Lookup the block in the extent overflow file. */ key.first_block = grub_cpu_to_be16 (pos); tree = 1; grub_hfs_find_node (data, (char *) &key, data->ext_root, 1, (char *) &dr, sizeof (dr)); if (grub_errno) return 0; } }
int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name, const void *val, grub_uint32_t len) { grub_uint32_t *prop; int prop_name_present = 0; grub_uint32_t nameoff = 0; if ((nodeoffset >= grub_fdt_get_size_dt_struct (fdt)) || (nodeoffset & 0x3) || (grub_be_to_cpu32(*(grub_uint32_t *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt) + nodeoffset)) != FDT_BEGIN_NODE)) return -1; prop = find_prop (fdt, nodeoffset, name); if (prop) { grub_uint32_t prop_len = ALIGN_UP(grub_be_to_cpu32 (*(prop + 1)), sizeof(grub_uint32_t)); grub_uint32_t i; prop_name_present = 1; for (i = 0; i < prop_len / sizeof(grub_uint32_t); i++) *(prop + 3 + i) = grub_cpu_to_be32_compile_time (FDT_NOP); if (len > ALIGN_UP(prop_len, sizeof(grub_uint32_t))) { /* Length of new property value is greater than the space allocated for the current value: a new entry needs to be created, so save the nameoff field of the current entry and replace the current entry with NOP tokens. */ nameoff = grub_be_to_cpu32 (*(prop + 2)); *prop = *(prop + 1) = *(prop + 2) = grub_cpu_to_be32_compile_time (FDT_NOP); prop = NULL; } } if (!prop || !prop_name_present) { unsigned int needed_space = 0; if (!prop) needed_space = prop_entry_size(len); if (!prop_name_present) needed_space += grub_strlen (name) + 1; if (needed_space > get_free_space (fdt)) return -1; if (rearrange_blocks (fdt, !prop ? prop_entry_size(len) : 0) < 0) return -1; } if (!prop_name_present) { /* Append the property name at the end of the strings block. */ nameoff = grub_fdt_get_size_dt_strings (fdt); grub_strcpy ((char *) fdt + grub_fdt_get_off_dt_strings (fdt) + nameoff, name); grub_fdt_set_size_dt_strings (fdt, grub_fdt_get_size_dt_strings (fdt) + grub_strlen (name) + 1); } if (!prop) { char *node_name = (char *) ((grub_addr_t) fdt + grub_fdt_get_off_dt_struct (fdt) + nodeoffset + sizeof(grub_uint32_t)); prop = (void *) (node_name + ALIGN_UP(grub_strlen(node_name) + 1, 4)); grub_memmove (prop + prop_entry_size(len) / sizeof(*prop), prop, struct_end(fdt) - (grub_addr_t) prop); grub_fdt_set_size_dt_struct (fdt, grub_fdt_get_size_dt_struct (fdt) + prop_entry_size(len)); *prop = grub_cpu_to_be32_compile_time (FDT_PROP); *(prop + 2) = grub_cpu_to_be32 (nameoff); } *(prop + 1) = grub_cpu_to_be32 (len); /* Insert padding bytes at the end of the value; if they are not needed, they will be overwritten by the following memcpy. */ *(prop + prop_entry_size(len) / sizeof(grub_uint32_t) - 1) = 0; grub_memcpy (prop + 3, val, len); return 0; }