cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

aix.c (6131B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  fs/partitions/aix.c
      4 *
      5 *  Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
      6 */
      7
      8#include "check.h"
      9
     10struct lvm_rec {
     11	char lvm_id[4]; /* "_LVM" */
     12	char reserved4[16];
     13	__be32 lvmarea_len;
     14	__be32 vgda_len;
     15	__be32 vgda_psn[2];
     16	char reserved36[10];
     17	__be16 pp_size; /* log2(pp_size) */
     18	char reserved46[12];
     19	__be16 version;
     20	};
     21
     22struct vgda {
     23	__be32 secs;
     24	__be32 usec;
     25	char reserved8[16];
     26	__be16 numlvs;
     27	__be16 maxlvs;
     28	__be16 pp_size;
     29	__be16 numpvs;
     30	__be16 total_vgdas;
     31	__be16 vgda_size;
     32	};
     33
     34struct lvd {
     35	__be16 lv_ix;
     36	__be16 res2;
     37	__be16 res4;
     38	__be16 maxsize;
     39	__be16 lv_state;
     40	__be16 mirror;
     41	__be16 mirror_policy;
     42	__be16 num_lps;
     43	__be16 res10[8];
     44	};
     45
     46struct lvname {
     47	char name[64];
     48	};
     49
     50struct ppe {
     51	__be16 lv_ix;
     52	unsigned short res2;
     53	unsigned short res4;
     54	__be16 lp_ix;
     55	unsigned short res8[12];
     56	};
     57
     58struct pvd {
     59	char reserved0[16];
     60	__be16 pp_count;
     61	char reserved18[2];
     62	__be32 psn_part1;
     63	char reserved24[8];
     64	struct ppe ppe[1016];
     65	};
     66
     67#define LVM_MAXLVS 256
     68
     69/**
     70 * read_lba(): Read bytes from disk, starting at given LBA
     71 * @state
     72 * @lba
     73 * @buffer
     74 * @count
     75 *
     76 * Description:  Reads @count bytes from @state->disk into @buffer.
     77 * Returns number of bytes read on success, 0 on error.
     78 */
     79static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer,
     80			size_t count)
     81{
     82	size_t totalreadcount = 0;
     83
     84	if (!buffer || lba + count / 512 > get_capacity(state->disk) - 1ULL)
     85		return 0;
     86
     87	while (count) {
     88		int copied = 512;
     89		Sector sect;
     90		unsigned char *data = read_part_sector(state, lba++, &sect);
     91		if (!data)
     92			break;
     93		if (copied > count)
     94			copied = count;
     95		memcpy(buffer, data, copied);
     96		put_dev_sector(sect);
     97		buffer += copied;
     98		totalreadcount += copied;
     99		count -= copied;
    100	}
    101	return totalreadcount;
    102}
    103
    104/**
    105 * alloc_pvd(): reads physical volume descriptor
    106 * @state
    107 * @lba
    108 *
    109 * Description: Returns pvd on success,  NULL on error.
    110 * Allocates space for pvd and fill it with disk blocks at @lba
    111 * Notes: remember to free pvd when you're done!
    112 */
    113static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba)
    114{
    115	size_t count = sizeof(struct pvd);
    116	struct pvd *p;
    117
    118	p = kmalloc(count, GFP_KERNEL);
    119	if (!p)
    120		return NULL;
    121
    122	if (read_lba(state, lba, (u8 *) p, count) < count) {
    123		kfree(p);
    124		return NULL;
    125	}
    126	return p;
    127}
    128
    129/**
    130 * alloc_lvn(): reads logical volume names
    131 * @state
    132 * @lba
    133 *
    134 * Description: Returns lvn on success,  NULL on error.
    135 * Allocates space for lvn and fill it with disk blocks at @lba
    136 * Notes: remember to free lvn when you're done!
    137 */
    138static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba)
    139{
    140	size_t count = sizeof(struct lvname) * LVM_MAXLVS;
    141	struct lvname *p;
    142
    143	p = kmalloc(count, GFP_KERNEL);
    144	if (!p)
    145		return NULL;
    146
    147	if (read_lba(state, lba, (u8 *) p, count) < count) {
    148		kfree(p);
    149		return NULL;
    150	}
    151	return p;
    152}
    153
    154int aix_partition(struct parsed_partitions *state)
    155{
    156	int ret = 0;
    157	Sector sect;
    158	unsigned char *d;
    159	u32 pp_bytes_size;
    160	u32 pp_blocks_size = 0;
    161	u32 vgda_sector = 0;
    162	u32 vgda_len = 0;
    163	int numlvs = 0;
    164	struct pvd *pvd = NULL;
    165	struct lv_info {
    166		unsigned short pps_per_lv;
    167		unsigned short pps_found;
    168		unsigned char lv_is_contiguous;
    169	} *lvip;
    170	struct lvname *n = NULL;
    171
    172	d = read_part_sector(state, 7, &sect);
    173	if (d) {
    174		struct lvm_rec *p = (struct lvm_rec *)d;
    175		u16 lvm_version = be16_to_cpu(p->version);
    176		char tmp[64];
    177
    178		if (lvm_version == 1) {
    179			int pp_size_log2 = be16_to_cpu(p->pp_size);
    180
    181			pp_bytes_size = 1 << pp_size_log2;
    182			pp_blocks_size = pp_bytes_size / 512;
    183			snprintf(tmp, sizeof(tmp),
    184				" AIX LVM header version %u found\n",
    185				lvm_version);
    186			vgda_len = be32_to_cpu(p->vgda_len);
    187			vgda_sector = be32_to_cpu(p->vgda_psn[0]);
    188		} else {
    189			snprintf(tmp, sizeof(tmp),
    190				" unsupported AIX LVM version %d found\n",
    191				lvm_version);
    192		}
    193		strlcat(state->pp_buf, tmp, PAGE_SIZE);
    194		put_dev_sector(sect);
    195	}
    196	if (vgda_sector && (d = read_part_sector(state, vgda_sector, &sect))) {
    197		struct vgda *p = (struct vgda *)d;
    198
    199		numlvs = be16_to_cpu(p->numlvs);
    200		put_dev_sector(sect);
    201	}
    202	lvip = kcalloc(state->limit, sizeof(struct lv_info), GFP_KERNEL);
    203	if (!lvip)
    204		return 0;
    205	if (numlvs && (d = read_part_sector(state, vgda_sector + 1, &sect))) {
    206		struct lvd *p = (struct lvd *)d;
    207		int i;
    208
    209		n = alloc_lvn(state, vgda_sector + vgda_len - 33);
    210		if (n) {
    211			int foundlvs = 0;
    212
    213			for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
    214				lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
    215				if (lvip[i].pps_per_lv)
    216					foundlvs += 1;
    217			}
    218			/* pvd loops depend on n[].name and lvip[].pps_per_lv */
    219			pvd = alloc_pvd(state, vgda_sector + 17);
    220		}
    221		put_dev_sector(sect);
    222	}
    223	if (pvd) {
    224		int numpps = be16_to_cpu(pvd->pp_count);
    225		int psn_part1 = be32_to_cpu(pvd->psn_part1);
    226		int i;
    227		int cur_lv_ix = -1;
    228		int next_lp_ix = 1;
    229		int lp_ix;
    230
    231		for (i = 0; i < numpps; i += 1) {
    232			struct ppe *p = pvd->ppe + i;
    233			unsigned int lv_ix;
    234
    235			lp_ix = be16_to_cpu(p->lp_ix);
    236			if (!lp_ix) {
    237				next_lp_ix = 1;
    238				continue;
    239			}
    240			lv_ix = be16_to_cpu(p->lv_ix) - 1;
    241			if (lv_ix >= state->limit) {
    242				cur_lv_ix = -1;
    243				continue;
    244			}
    245			lvip[lv_ix].pps_found += 1;
    246			if (lp_ix == 1) {
    247				cur_lv_ix = lv_ix;
    248				next_lp_ix = 1;
    249			} else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) {
    250				next_lp_ix = 1;
    251				continue;
    252			}
    253			if (lp_ix == lvip[lv_ix].pps_per_lv) {
    254				char tmp[70];
    255
    256				put_partition(state, lv_ix + 1,
    257				  (i + 1 - lp_ix) * pp_blocks_size + psn_part1,
    258				  lvip[lv_ix].pps_per_lv * pp_blocks_size);
    259				snprintf(tmp, sizeof(tmp), " <%s>\n",
    260					 n[lv_ix].name);
    261				strlcat(state->pp_buf, tmp, PAGE_SIZE);
    262				lvip[lv_ix].lv_is_contiguous = 1;
    263				ret = 1;
    264				next_lp_ix = 1;
    265			} else
    266				next_lp_ix += 1;
    267		}
    268		for (i = 0; i < state->limit; i += 1)
    269			if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) {
    270				char tmp[sizeof(n[i].name) + 1]; // null char
    271
    272				snprintf(tmp, sizeof(tmp), "%s", n[i].name);
    273				pr_warn("partition %s (%u pp's found) is "
    274					"not contiguous\n",
    275					tmp, lvip[i].pps_found);
    276			}
    277		kfree(pvd);
    278	}
    279	kfree(n);
    280	kfree(lvip);
    281	return ret;
    282}