static int fec_init(struct eth_device *dev, bd_t *bd) #endif { #ifdef CONFIG_DM_ETH struct fec_priv *fec = dev_get_priv(dev); #else struct fec_priv *fec = (struct fec_priv *)dev->priv; #endif uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop; int i; /* Initialize MAC address */ #ifdef CONFIG_DM_ETH fecmxc_set_hwaddr(dev); #else fec_set_hwaddr(dev); #endif /* Setup transmit descriptors, there are two in total. */ fec_tbd_init(fec); /* Setup receive descriptors. */ fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE); fec_reg_setup(fec); if (fec->xcv_type != SEVENWIRE) fec_mii_setspeed(fec->bus->priv); /* Set Opcode/Pause Duration Register */ writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */ writel(0x2, &fec->eth->x_wmrk); /* Set multicast address filter */ writel(0x00000000, &fec->eth->gaddr1); writel(0x00000000, &fec->eth->gaddr2); /* Do not access reserved register for i.MX6UL */ if (!is_mx6ul()) { /* clear MIB RAM */ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4) writel(0, i); /* FIFO receive start register */ writel(0x520, &fec->eth->r_fstart); } /* size and address of each buffer */ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr); writel((uint32_t)fec->tbd_base, &fec->eth->etdsr); writel((uint32_t)fec->rbd_base, &fec->eth->erdsr); #ifndef CONFIG_PHYLIB if (fec->xcv_type != SEVENWIRE) miiphy_restart_aneg(dev); #endif fec_open(dev); return 0; }
static int fec_init(struct eth_device *dev, bd_t* bd) { uint32_t base; struct fec_priv *fec = (struct fec_priv *)dev->priv; uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop; uint32_t rcntrl; int i; /* Initialize MAC address */ fec_set_hwaddr(dev); /* * reserve memory for both buffer descriptor chains at once * Datasheet forces the startaddress of each chain is 16 byte * aligned */ if (fec->base_ptr == NULL) fec->base_ptr = malloc((2 + FEC_RBD_NUM) * sizeof(struct fec_bd) + DB_ALIGNMENT); base = (uint32_t)fec->base_ptr; if (!base) { puts("fec_mxc: not enough malloc memory\n"); return -ENOMEM; } memset((void *)base, 0, (2 + FEC_RBD_NUM) * sizeof(struct fec_bd) + DB_ALIGNMENT); base += (DB_ALIGNMENT-1); base &= ~(DB_ALIGNMENT-1); fec->rbd_base = (struct fec_bd *)base; base += FEC_RBD_NUM * sizeof(struct fec_bd); fec->tbd_base = (struct fec_bd *)base; /* * Set interrupt mask register */ writel(0x00000000, &fec->eth->imask); /* * Clear FEC-Lite interrupt event register(IEVENT) */ writel(0xffffffff, &fec->eth->ievent); /* * Set FEC-Lite receive control register(R_CNTRL): */ /* Start with frame length = 1518, common for all modes. */ rcntrl = PKTSIZE << FEC_RCNTRL_MAX_FL_SHIFT; if (fec->xcv_type == SEVENWIRE) rcntrl |= FEC_RCNTRL_FCE; else if (fec->xcv_type == RGMII) rcntrl |= FEC_RCNTRL_RGMII; else if (fec->xcv_type == RMII) rcntrl |= FEC_RCNTRL_RMII; else /* MII mode */ rcntrl |= FEC_RCNTRL_FCE | FEC_RCNTRL_MII_MODE; writel(rcntrl, &fec->eth->r_cntrl); if (fec->xcv_type == MII10 || fec->xcv_type == MII100) fec_mii_setspeed(fec); /* * Set Opcode/Pause Duration Register */ writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */ writel(0x2, &fec->eth->x_wmrk); /* * Set multicast address filter */ writel(0x00000000, &fec->eth->gaddr1); writel(0x00000000, &fec->eth->gaddr2); /* clear MIB RAM */ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4) writel(0, i); /* FIFO receive start register */ writel(0x520, &fec->eth->r_fstart); /* size and address of each buffer */ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr); writel((uint32_t)fec->tbd_base, &fec->eth->etdsr); writel((uint32_t)fec->rbd_base, &fec->eth->erdsr); /* * Initialize RxBD/TxBD rings */ if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) { free(fec->base_ptr); fec->base_ptr = NULL; return -ENOMEM; } fec_tbd_init(fec); if (fec->xcv_type != SEVENWIRE) miiphy_restart_aneg(dev); fec_open(dev); return 0; }
// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for // mount. The 'wait_for_verity_dev' parameter makes this function wait for the // verity device to get created before return int fs_mgr_setup_verity(FstabEntry* entry, bool wait_for_verity_dev) { int retval = FS_MGR_SETUP_VERITY_FAIL; int fd = -1; std::string verity_blk_name; struct fec_handle *f = NULL; struct fec_verity_metadata verity; struct verity_table_params params = { .table = NULL }; const std::string mount_point(basename(entry->mount_point.c_str())); bool verified_at_boot = false; android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); if (fec_open(&f, entry->blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) < 0) { PERROR << "Failed to open '" << entry->blk_device << "'"; return retval; } // read verity metadata if (fec_verity_get_metadata(f, &verity) < 0) { PERROR << "Failed to get verity metadata '" << entry->blk_device << "'"; // Allow verity disabled when the device is unlocked without metadata if (fs_mgr_is_device_unlocked()) { retval = FS_MGR_SETUP_VERITY_SKIPPED; LWARNING << "Allow invalid metadata when the device is unlocked"; } goto out; } #ifdef ALLOW_ADBD_DISABLE_VERITY if (verity.disabled) { retval = FS_MGR_SETUP_VERITY_DISABLED; LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG/ENG"; goto out; } #endif // read ecc metadata if (fec_ecc_get_metadata(f, ¶ms.ecc) < 0) { params.ecc.valid = false; } params.ecc_dev = entry->blk_device.c_str(); if (load_verity_state(*entry, ¶ms.mode) < 0) { /* if accessing or updating the state failed, switch to the default * safe mode. This makes sure the device won't end up in an endless * restart loop, and no corrupted data will be exposed to userspace * without a warning. */ params.mode = VERITY_MODE_EIO; } if (!verity.table) { goto out; } params.table = strdup(verity.table); if (!params.table) { goto out; } // verify the signature on the table if (verify_verity_signature(verity) < 0) { // Allow signature verification error when the device is unlocked if (fs_mgr_is_device_unlocked()) { retval = FS_MGR_SETUP_VERITY_SKIPPED; LWARNING << "Allow signature verification error when the device is unlocked"; goto out; } if (params.mode == VERITY_MODE_LOGGING) { // the user has been warned, allow mounting without dm-verity retval = FS_MGR_SETUP_VERITY_SKIPPED; goto out; } // invalidate root hash and salt to trigger device-specific recovery if (invalidate_table(params.table, verity.table_length) < 0) { goto out; } } LINFO << "Enabling dm-verity for " << mount_point.c_str() << " (mode " << params.mode << ")"; // Update the verity params using the actual block device path update_verity_table_blk_device(entry->blk_device, ¶ms.table, entry->fs_mgr_flags.slot_select); // load the verity mapping table if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_verity_table) == 0) { goto loaded; } if (params.ecc.valid) { // kernel may not support error correction, try without LINFO << "Disabling error correction for " << mount_point.c_str(); params.ecc.valid = false; if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_verity_table) == 0) { goto loaded; } } // try the legacy format for backwards compatibility if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_legacy_verity_table) == 0) { goto loaded; } if (params.mode != VERITY_MODE_EIO) { // as a last resort, EIO mode should always be supported LINFO << "Falling back to EIO mode for " << mount_point.c_str(); params.mode = VERITY_MODE_EIO; if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_legacy_verity_table) == 0) { goto loaded; } } LERROR << "Failed to load verity table for " << mount_point.c_str(); goto out; loaded: if (!dm.GetDmDevicePathByName(mount_point, &verity_blk_name)) { LERROR << "Couldn't get verity device number!"; goto out; } // mark the underlying block device as read-only fs_mgr_set_blk_ro(entry->blk_device); // Verify the entire partition in one go // If there is an error, allow it to mount as a normal verity partition. if (entry->fs_mgr_flags.verify_at_boot) { LINFO << "Verifying partition " << entry->blk_device << " at boot"; int err = read_partition(verity_blk_name.c_str(), verity.data_size); if (!err) { LINFO << "Verified verity partition " << entry->blk_device << " at boot"; verified_at_boot = true; } } // assign the new verity block device as the block device if (!verified_at_boot) { entry->blk_device = verity_blk_name; } else if (!dm.DeleteDevice(mount_point)) { LERROR << "Failed to remove verity device " << mount_point.c_str(); goto out; } // make sure we've set everything up properly if (wait_for_verity_dev && !fs_mgr_wait_for_file(entry->blk_device, 1s)) { goto out; } retval = FS_MGR_SETUP_VERITY_SUCCESS; out: if (fd != -1) { close(fd); } fec_close(f); free(params.table); return retval; }
static int compare_last_signature(const FstabEntry& entry, int* match) { char tag[METADATA_TAG_MAX_LENGTH + 1]; int fd = -1; int rc = -1; off64_t offset = 0; struct fec_handle *f = NULL; struct fec_verity_metadata verity; uint8_t curr[SHA256_DIGEST_LENGTH]; uint8_t prev[SHA256_DIGEST_LENGTH]; *match = 1; if (fec_open(&f, entry.blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) == -1) { PERROR << "Failed to open '" << entry.blk_device << "'"; return rc; } // read verity metadata if (fec_verity_get_metadata(f, &verity) == -1) { PERROR << "Failed to get verity metadata '" << entry.blk_device << "'"; goto out; } SHA256(verity.signature, sizeof(verity.signature), curr); if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s", basename(entry.mount_point.c_str())) >= (int)sizeof(tag)) { LERROR << "Metadata tag name too long for " << entry.mount_point; goto out; } if (metadata_find(entry.verity_loc.c_str(), tag, SHA256_DIGEST_LENGTH, &offset) < 0) { goto out; } fd = TEMP_FAILURE_RETRY(open(entry.verity_loc.c_str(), O_RDWR | O_SYNC | O_CLOEXEC)); if (fd == -1) { PERROR << "Failed to open " << entry.verity_loc; goto out; } if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev), offset)) != sizeof(prev)) { PERROR << "Failed to read " << sizeof(prev) << " bytes from " << entry.verity_loc << " offset " << offset; goto out; } *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH); if (!*match) { /* update current signature hash */ if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr), offset)) != sizeof(curr)) { PERROR << "Failed to write " << sizeof(curr) << " bytes to " << entry.verity_loc << " offset " << offset; goto out; } } rc = 0; out: fec_close(f); return rc; }
static int fec_init(struct eth_device *dev, bd_t* bd) { struct fec_priv *fec = (struct fec_priv *)dev->priv; uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop; uint32_t size; int i, ret; /* Initialize MAC address */ fec_set_hwaddr(dev); /* * Allocate transmit descriptors, there are two in total. This * allocation respects cache alignment. */ if (!fec->tbd_base) { size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); fec->tbd_base = memalign(ARCH_DMA_MINALIGN, size); if (!fec->tbd_base) { ret = -ENOMEM; goto err1; } memset(fec->tbd_base, 0, size); fec_tbd_init(fec); } /* * Allocate receive descriptors. This allocation respects cache * alignment. */ if (!fec->rbd_base) { size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd), ARCH_DMA_MINALIGN); fec->rbd_base = memalign(ARCH_DMA_MINALIGN, size); if (!fec->rbd_base) { ret = -ENOMEM; goto err2; } memset(fec->rbd_base, 0, size); /* * Initialize RxBD ring */ if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) { ret = -ENOMEM; goto err3; } flush_dcache_range((unsigned)fec->rbd_base, (unsigned)fec->rbd_base + size); } fec_reg_setup(fec); if (fec->xcv_type != SEVENWIRE) fec_mii_setspeed(fec->bus->priv); /* * Set Opcode/Pause Duration Register */ writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */ writel(0x2, &fec->eth->x_wmrk); /* * Set multicast address filter */ writel(0x00000000, &fec->eth->gaddr1); writel(0x00000000, &fec->eth->gaddr2); /* clear MIB RAM */ for (i = mib_ptr; i <= mib_ptr + 0xfc; i += 4) writel(0, i); /* FIFO receive start register */ writel(0x520, &fec->eth->r_fstart); /* size and address of each buffer */ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr); writel((uint32_t)fec->tbd_base, &fec->eth->etdsr); writel((uint32_t)fec->rbd_base, &fec->eth->erdsr); #ifndef CONFIG_PHYLIB if (fec->xcv_type != SEVENWIRE) miiphy_restart_aneg(dev); #endif fec_open(dev); return 0; err3: free(fec->rbd_base); err2: free(fec->tbd_base); err1: return ret; }