/ duct-tape / xnu / osfmk / kern / kern_cdata.c
kern_cdata.c
   1  /*
   2   * Copyright (c) 2015 Apple Inc. All rights reserved.
   3   *
   4   * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
   5   *
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. The rights granted to you under the License
  10   * may not be used to create, or enable the creation or redistribution of,
  11   * unlawful or unlicensed copies of an Apple operating system, or to
  12   * circumvent, violate, or enable the circumvention or violation of, any
  13   * terms of an Apple operating system software license agreement.
  14   *
  15   * Please obtain a copy of the License at
  16   * http://www.opensource.apple.com/apsl/ and read it before using this file.
  17   *
  18   * The Original Code and all software distributed under the License are
  19   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  20   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  21   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  22   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  23   * Please see the License for the specific language governing rights and
  24   * limitations under the License.
  25   *
  26   * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  27   */
  28  
  29  #include <kern/assert.h>
  30  #include <mach/mach_types.h>
  31  #include <mach/boolean.h>
  32  #include <mach/vm_param.h>
  33  #include <kern/kern_types.h>
  34  #include <kern/mach_param.h>
  35  #include <kern/thread.h>
  36  #include <kern/task.h>
  37  #include <kern/kern_cdata.h>
  38  #include <kern/kalloc.h>
  39  #include <mach/mach_vm.h>
  40  
  41  static kern_return_t kcdata_get_memory_addr_with_flavor(kcdata_descriptor_t data, uint32_t type, uint32_t size, uint64_t flags, mach_vm_address_t *user_addr);
  42  static size_t kcdata_get_memory_size_for_data(uint32_t size);
  43  static kern_return_t kcdata_compress_chunk_with_flags(kcdata_descriptor_t data, uint32_t type, const void *input_data, uint32_t input_size, uint64_t flags);
  44  static kern_return_t kcdata_compress_chunk(kcdata_descriptor_t data, uint32_t type, const void *input_data, uint32_t input_size);
  45  static kern_return_t kcdata_write_compression_stats(kcdata_descriptor_t data);
  46  static kern_return_t kcdata_get_compression_stats(kcdata_descriptor_t data, uint64_t *totalout, uint64_t *totalin);
  47  
  48  /*
  49   * zlib will need to store its metadata and this value is indifferent from the
  50   * window bits and other zlib internals
  51   */
  52  #define ZLIB_METADATA_SIZE 1440
  53  
  54  /* #define kcdata_debug_printf printf */
  55  #define kcdata_debug_printf(...) ;
  56  
  57  #pragma pack(push, 4)
  58  
  59  /* Internal structs for convenience */
  60  struct _uint64_with_description_data {
  61  	char desc[KCDATA_DESC_MAXLEN];
  62  	uint64_t data;
  63  };
  64  
  65  struct _uint32_with_description_data {
  66  	char     desc[KCDATA_DESC_MAXLEN];
  67  	uint32_t data;
  68  };
  69  
  70  #pragma pack(pop)
  71  
  72  /*
  73   * Estimates how large of a buffer that should be allocated for a buffer that will contain
  74   * num_items items of known types with overall length payload_size.
  75   *
  76   * NOTE: This function will not give an accurate estimate for buffers that will
  77   *       contain unknown types (those with string descriptions).
  78   */
  79  uint32_t
  80  kcdata_estimate_required_buffer_size(uint32_t num_items, uint32_t payload_size)
  81  {
  82  	/*
  83  	 * In the worst case each item will need (KCDATA_ALIGNMENT_SIZE - 1) padding
  84  	 */
  85  	uint32_t max_padding_bytes = 0;
  86  	uint32_t max_padding_with_item_description_bytes = 0;
  87  	uint32_t estimated_required_buffer_size = 0;
  88  	const uint32_t begin_and_end_marker_bytes = 2 * sizeof(struct kcdata_item);
  89  
  90  	if (os_mul_overflow(num_items, KCDATA_ALIGNMENT_SIZE - 1, &max_padding_bytes)) {
  91  		panic("%s: Overflow in required buffer size estimate", __func__);
  92  	}
  93  
  94  	if (os_mul_and_add_overflow(num_items, sizeof(struct kcdata_item), max_padding_bytes, &max_padding_with_item_description_bytes)) {
  95  		panic("%s: Overflow in required buffer size estimate", __func__);
  96  	}
  97  
  98  	if (os_add3_overflow(max_padding_with_item_description_bytes, begin_and_end_marker_bytes, payload_size, &estimated_required_buffer_size)) {
  99  		panic("%s: Overflow in required buffer size estimate", __func__);
 100  	}
 101  
 102  	return estimated_required_buffer_size;
 103  }
 104  
 105  kcdata_descriptor_t
 106  kcdata_memory_alloc_init(mach_vm_address_t buffer_addr_p, unsigned data_type, unsigned size, unsigned flags)
 107  {
 108  	kcdata_descriptor_t data = NULL;
 109  	mach_vm_address_t user_addr = 0;
 110  	uint16_t clamped_flags = (uint16_t) flags;
 111  
 112  	data = kalloc_flags(sizeof(struct kcdata_descriptor), Z_WAITOK | Z_ZERO);
 113  	if (data == NULL) {
 114  		return NULL;
 115  	}
 116  	data->kcd_addr_begin = buffer_addr_p;
 117  	data->kcd_addr_end = buffer_addr_p;
 118  	data->kcd_flags = (clamped_flags & KCFLAG_USE_COPYOUT) ? clamped_flags : clamped_flags | KCFLAG_USE_MEMCOPY;
 119  	data->kcd_length = size;
 120  
 121  	/* Initialize the BEGIN header */
 122  	if (KERN_SUCCESS != kcdata_get_memory_addr(data, data_type, 0, &user_addr)) {
 123  		kcdata_memory_destroy(data);
 124  		return NULL;
 125  	}
 126  
 127  	return data;
 128  }
 129  
 130  kern_return_t
 131  kcdata_memory_static_init(kcdata_descriptor_t data, mach_vm_address_t buffer_addr_p, unsigned data_type, unsigned size, unsigned flags)
 132  {
 133  	mach_vm_address_t user_addr = 0;
 134  	uint16_t clamped_flags = (uint16_t) flags;
 135  
 136  	if (data == NULL) {
 137  		return KERN_INVALID_ARGUMENT;
 138  	}
 139  	bzero(data, sizeof(struct kcdata_descriptor));
 140  	data->kcd_addr_begin = buffer_addr_p;
 141  	data->kcd_addr_end = buffer_addr_p;
 142  	data->kcd_flags = (clamped_flags & KCFLAG_USE_COPYOUT) ? clamped_flags : clamped_flags | KCFLAG_USE_MEMCOPY;
 143  	data->kcd_length = size;
 144  
 145  	/* Initialize the BEGIN header */
 146  	return kcdata_get_memory_addr(data, data_type, 0, &user_addr);
 147  }
 148  
 149  void *
 150  kcdata_memory_get_begin_addr(kcdata_descriptor_t data)
 151  {
 152  	if (data == NULL) {
 153  		return NULL;
 154  	}
 155  
 156  	return (void *)data->kcd_addr_begin;
 157  }
 158  
 159  uint64_t
 160  kcdata_memory_get_used_bytes(kcdata_descriptor_t kcd)
 161  {
 162  	assert(kcd != NULL);
 163  	return ((uint64_t)kcd->kcd_addr_end - (uint64_t)kcd->kcd_addr_begin) + sizeof(struct kcdata_item);
 164  }
 165  
 166  uint64_t
 167  kcdata_memory_get_uncompressed_bytes(kcdata_descriptor_t kcd)
 168  {
 169  	kern_return_t kr;
 170  
 171  	assert(kcd != NULL);
 172  	if (kcd->kcd_flags & KCFLAG_USE_COMPRESSION) {
 173  		uint64_t totalout, totalin;
 174  
 175  		kr = kcdata_get_compression_stats(kcd, &totalout, &totalin);
 176  		if (kr == KERN_SUCCESS) {
 177  			return totalin;
 178  		} else {
 179  			return 0;
 180  		}
 181  	} else {
 182  		/* If compression wasn't used, get the number of bytes used  */
 183  		return kcdata_memory_get_used_bytes(kcd);
 184  	}
 185  }
 186  
 187  /*
 188   * Free up the memory associated with kcdata
 189   */
 190  kern_return_t
 191  kcdata_memory_destroy(kcdata_descriptor_t data)
 192  {
 193  	if (!data) {
 194  		return KERN_INVALID_ARGUMENT;
 195  	}
 196  
 197  	/*
 198  	 * data->kcd_addr_begin points to memory in not tracked by
 199  	 * kcdata lib. So not clearing that here.
 200  	 */
 201  	kfree(data, sizeof(struct kcdata_descriptor));
 202  	return KERN_SUCCESS;
 203  }
 204  
 205  /* Used by zlib to allocate space in its metadata section */
 206  static void *
 207  kcdata_compress_zalloc(void *opaque, u_int items, u_int size)
 208  {
 209  	void *result;
 210  	struct kcdata_compress_descriptor *cd = opaque;
 211  	int alloc_size = ~31L & (31 + (items * size));
 212  
 213  	result = (void *)(cd->kcd_cd_base + cd->kcd_cd_offset);
 214  	if ((uintptr_t) result + alloc_size > (uintptr_t) cd->kcd_cd_base + cd->kcd_cd_maxoffset) {
 215  		result = Z_NULL;
 216  	} else {
 217  		cd->kcd_cd_offset += alloc_size;
 218  	}
 219  
 220  	kcdata_debug_printf("%s: %d * %d = %d  => %p\n", __func__, items, size, items * size, result);
 221  
 222  	return result;
 223  }
 224  
 225  /* Used by zlib to free previously allocated space in its metadata section */
 226  static void
 227  kcdata_compress_zfree(void *opaque, void *ptr)
 228  {
 229  	(void) opaque;
 230  	(void) ptr;
 231  
 232  	kcdata_debug_printf("%s: ptr %p\n", __func__, ptr);
 233  
 234  	/*
 235  	 * Since the buffers we are using are temporary, we don't worry about
 236  	 * freeing memory for now. Besides, testing has shown that zlib only calls
 237  	 * this at the end, near deflateEnd() or a Z_FINISH deflate() call.
 238  	 */
 239  }
 240  
 241  /* Used to initialize the selected compression algorithm's internal state (if any) */
 242  static kern_return_t
 243  kcdata_init_compress_state(kcdata_descriptor_t data, void (*memcpy_f)(void *, const void *, size_t), uint64_t type, mach_vm_address_t totalout_addr, mach_vm_address_t totalin_addr)
 244  {
 245  	kern_return_t ret = KERN_SUCCESS;
 246  	size_t size;
 247  	int wbits = 12, memlevel = 3;
 248  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 249  
 250  	cd->kcd_cd_memcpy_f = memcpy_f;
 251  	cd->kcd_cd_compression_type = type;
 252  	cd->kcd_cd_totalout_addr = totalout_addr;
 253  	cd->kcd_cd_totalin_addr = totalin_addr;
 254  
 255  	switch (type) {
 256  	case KCDCT_ZLIB:
 257  		/* allocate space for the metadata used by zlib */
 258  		size = round_page(ZLIB_METADATA_SIZE + zlib_deflate_memory_size(wbits, memlevel));
 259  		kcdata_debug_printf("%s: size = %zu kcd_length: %d\n", __func__, size, data->kcd_length);
 260  		kcdata_debug_printf("%s: kcd buffer [%p - %p]\n", __func__, (void *) data->kcd_addr_begin, (void *) data->kcd_addr_begin + data->kcd_length);
 261  
 262  		if (4 * size > data->kcd_length) {
 263  			return KERN_INSUFFICIENT_BUFFER_SIZE;
 264  		}
 265  
 266  		cd->kcd_cd_zs.avail_in = 0;
 267  		cd->kcd_cd_zs.next_in = NULL;
 268  		cd->kcd_cd_zs.avail_out = 0;
 269  		cd->kcd_cd_zs.next_out = NULL;
 270  		cd->kcd_cd_zs.opaque = cd;
 271  		cd->kcd_cd_zs.zalloc = kcdata_compress_zalloc;
 272  		cd->kcd_cd_zs.zfree = kcdata_compress_zfree;
 273  		cd->kcd_cd_base = (void *) data->kcd_addr_begin + data->kcd_length - size;
 274  		data->kcd_length -= size;
 275  		cd->kcd_cd_offset = 0;
 276  		cd->kcd_cd_maxoffset = size;
 277  		cd->kcd_cd_flags = 0;
 278  
 279  		kcdata_debug_printf("%s: buffer [%p - %p]\n", __func__, cd->kcd_cd_base, cd->kcd_cd_base + size);
 280  
 281  		if (deflateInit2(&cd->kcd_cd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits, memlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
 282  			kcdata_debug_printf("EMERGENCY: deflateInit2 failed!\n");
 283  			ret = KERN_INVALID_ARGUMENT;
 284  		}
 285  		break;
 286  	default:
 287  		panic("kcdata_init_compress_state: invalid compression type: %d", (int) type);
 288  	}
 289  
 290  	return ret;
 291  }
 292  
 293  
 294  /*
 295   * Turn on the compression logic for kcdata
 296   */
 297  kern_return_t
 298  kcdata_init_compress(kcdata_descriptor_t data, int hdr_tag, void (*memcpy_f)(void *, const void *, size_t), uint64_t type)
 299  {
 300  	kern_return_t kr;
 301  	mach_vm_address_t user_addr, totalout_addr, totalin_addr;
 302  	struct _uint64_with_description_data save_data;
 303  	const uint64_t size_req = sizeof(save_data);
 304  
 305  	assert(data && (data->kcd_flags & KCFLAG_USE_COMPRESSION) == 0);
 306  
 307  	/* reset the compression descriptor */
 308  	bzero(&data->kcd_comp_d, sizeof(struct kcdata_compress_descriptor));
 309  
 310  	/* add the header information */
 311  	kcdata_add_uint64_with_description(data, type, "kcd_c_type");
 312  
 313  	/* reserve space to write total out */
 314  	bzero(&save_data, size_req);
 315  	strlcpy(&(save_data.desc[0]), "kcd_c_totalout", sizeof(save_data.desc));
 316  	kr = kcdata_get_memory_addr(data, KCDATA_TYPE_UINT64_DESC, size_req, &totalout_addr);
 317  	if (kr != KERN_SUCCESS) {
 318  		return kr;
 319  	}
 320  	memcpy((void *)totalout_addr, &save_data, size_req);
 321  
 322  	/* space for total in */
 323  	bzero(&save_data, size_req);
 324  	strlcpy(&(save_data.desc[0]), "kcd_c_totalin", sizeof(save_data.desc));
 325  	kr = kcdata_get_memory_addr(data, KCDATA_TYPE_UINT64_DESC, size_req, &totalin_addr);
 326  	if (kr != KERN_SUCCESS) {
 327  		return kr;
 328  	}
 329  	memcpy((void *)totalin_addr, &save_data, size_req);
 330  
 331  	/* add the inner buffer */
 332  	kcdata_get_memory_addr(data, hdr_tag, 0, &user_addr);
 333  
 334  	/* save the flag */
 335  	data->kcd_flags |= KCFLAG_USE_COMPRESSION;
 336  
 337  	/* initialize algorithm specific state */
 338  	kr = kcdata_init_compress_state(data, memcpy_f, type, totalout_addr + offsetof(struct _uint64_with_description_data, data), totalin_addr + offsetof(struct _uint64_with_description_data, data));
 339  	if (kr != KERN_SUCCESS) {
 340  		kcdata_debug_printf("%s: failed to initialize compression state!\n", __func__);
 341  		return kr;
 342  	}
 343  
 344  	return KERN_SUCCESS;
 345  }
 346  
 347  static inline
 348  int
 349  kcdata_zlib_translate_kcd_cf_flag(enum kcdata_compression_flush flush)
 350  {
 351  	switch (flush) {
 352  	case KCDCF_NO_FLUSH: return Z_NO_FLUSH;
 353  	case KCDCF_SYNC_FLUSH: return Z_SYNC_FLUSH;
 354  	case KCDCF_FINISH: return Z_FINISH;
 355  	default: panic("invalid kcdata_zlib_translate_kcd_cf_flag flag");
 356  	}
 357  }
 358  
 359  static inline
 360  int
 361  kcdata_zlib_translate_kcd_cf_expected_ret(enum kcdata_compression_flush flush)
 362  {
 363  	switch (flush) {
 364  	case KCDCF_NO_FLUSH:         /* fall through */
 365  	case KCDCF_SYNC_FLUSH: return Z_OK;
 366  	case KCDCF_FINISH: return Z_STREAM_END;
 367  	default: panic("invalid kcdata_zlib_translate_kcd_cf_expected_ret flag");
 368  	}
 369  }
 370  
 371  /* Called by kcdata_do_compress() when the configured compression algorithm is zlib */
 372  static kern_return_t
 373  kcdata_do_compress_zlib(kcdata_descriptor_t data, void *inbuffer,
 374      size_t insize, void *outbuffer, size_t outsize, size_t *wrote,
 375      enum kcdata_compression_flush flush)
 376  {
 377  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 378  	z_stream *zs = &cd->kcd_cd_zs;
 379  	int expected_ret, ret;
 380  
 381  	zs->next_out = outbuffer;
 382  	zs->avail_out = (unsigned int) outsize;
 383  	zs->next_in = inbuffer;
 384  	zs->avail_in = (unsigned int) insize;
 385  	ret = deflate(zs, kcdata_zlib_translate_kcd_cf_flag(flush));
 386  	if (zs->avail_in != 0 || zs->avail_out <= 0) {
 387  		return KERN_INSUFFICIENT_BUFFER_SIZE;
 388  	}
 389  
 390  	expected_ret = kcdata_zlib_translate_kcd_cf_expected_ret(flush);
 391  	if (ret != expected_ret) {
 392  		/*
 393  		 * Should only fail with catastrophic, unrecoverable cases (i.e.,
 394  		 * corrupted z_stream, or incorrect configuration)
 395  		 */
 396  		panic("zlib kcdata compression ret = %d\n", ret);
 397  	}
 398  
 399  	kcdata_debug_printf("%s: %p (%zu) <- %p (%zu); flush: %d; ret = %ld\n",
 400  	    __func__, outbuffer, outsize, inbuffer, insize, flush, outsize - zs->avail_out);
 401  	if (wrote) {
 402  		*wrote = outsize - zs->avail_out;
 403  	}
 404  	return KERN_SUCCESS;
 405  }
 406  
 407  /*
 408   * Compress the buffer at @inbuffer (of size @insize) into the kcdata buffer
 409   * @outbuffer (of size @outsize). Flush based on the @flush parameter.
 410   *
 411   * Returns KERN_SUCCESS on success, or KERN_INSUFFICIENT_BUFFER_SIZE if
 412   * @outsize isn't sufficient. Also, writes the number of bytes written in the
 413   * @outbuffer to @wrote.
 414   */
 415  static kern_return_t
 416  kcdata_do_compress(kcdata_descriptor_t data, void *inbuffer, size_t insize,
 417      void *outbuffer, size_t outsize, size_t *wrote, enum kcdata_compression_flush flush)
 418  {
 419  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 420  
 421  	assert(data->kcd_flags & KCFLAG_USE_COMPRESSION);
 422  
 423  	kcdata_debug_printf("%s: %p (%zu) <- %p (%zu); flush: %d\n",
 424  	    __func__, outbuffer, outsize, inbuffer, insize, flush);
 425  
 426  	/* don't compress if we are in a window */
 427  	if (cd->kcd_cd_flags & KCD_CD_FLAG_IN_MARK || data->kcd_comp_d.kcd_cd_compression_type == KCDCT_NONE) {
 428  		assert(cd->kcd_cd_memcpy_f);
 429  		if (outsize >= insize) {
 430  			cd->kcd_cd_memcpy_f(outbuffer, inbuffer, insize);
 431  			if (wrote) {
 432  				*wrote = insize;
 433  			}
 434  			return KERN_SUCCESS;
 435  		} else {
 436  			return KERN_INSUFFICIENT_BUFFER_SIZE;
 437  		}
 438  	}
 439  
 440  	switch (data->kcd_comp_d.kcd_cd_compression_type) {
 441  	case KCDCT_ZLIB:
 442  		return kcdata_do_compress_zlib(data, inbuffer, insize, outbuffer, outsize, wrote, flush);
 443  	default:
 444  		panic("invalid compression type 0x%llx in kcdata_do_compress", data->kcd_comp_d.kcd_cd_compression_type);
 445  	}
 446  }
 447  
 448  static size_t
 449  kcdata_compression_bound_zlib(kcdata_descriptor_t data, size_t size)
 450  {
 451  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 452  	z_stream *zs = &cd->kcd_cd_zs;
 453  
 454  	return (size_t) deflateBound(zs, (unsigned long) size);
 455  }
 456  
 457  
 458  /*
 459   * returns the worst-case, maximum length of the compressed data when
 460   * compressing a buffer of size @size using the configured algorithm.
 461   */
 462  static size_t
 463  kcdata_compression_bound(kcdata_descriptor_t data, size_t size)
 464  {
 465  	switch (data->kcd_comp_d.kcd_cd_compression_type) {
 466  	case KCDCT_ZLIB:
 467  		return kcdata_compression_bound_zlib(data, size);
 468  	case KCDCT_NONE:
 469  		return size;
 470  	default:
 471  		panic("%s: unknown compression method", __func__);
 472  	}
 473  }
 474  
 475  /*
 476   * kcdata_compress_chunk_with_flags:
 477   *		Compress buffer found at @input_data (length @input_size) to the kcdata
 478   *		buffer described by @data. This method will construct the kcdata_item_t
 479   *		required by parsers using the type information @type and flags @flags.
 480   *
 481   *	Returns KERN_SUCCESS when successful. Currently, asserts on failure.
 482   */
 483  kern_return_t
 484  kcdata_compress_chunk_with_flags(kcdata_descriptor_t data, uint32_t type, const void *input_data, uint32_t input_size, uint64_t kcdata_flags)
 485  {
 486  	assert(data);
 487  	assert((data->kcd_flags & KCFLAG_USE_COMPRESSION));
 488  	assert(input_data);
 489  	struct kcdata_item info;
 490  	char padding_data[16] = {0};
 491  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 492  	size_t wrote = 0;
 493  	kern_return_t kr;
 494  
 495  	kcdata_debug_printf("%s: type: %d input_data: %p (%d) kcdata_flags: 0x%llx\n",
 496  	    __func__, type, input_data, input_size, kcdata_flags);
 497  
 498  	/*
 499  	 * first, get memory space. The uncompressed size must fit in the remained
 500  	 * of the kcdata buffer, in case the compression algorithm doesn't actually
 501  	 * compress the data at all.
 502  	 */
 503  	size_t total_uncompressed_size = kcdata_compression_bound(data, (size_t) kcdata_get_memory_size_for_data(input_size));
 504  	if (total_uncompressed_size > data->kcd_length ||
 505  	    data->kcd_length - total_uncompressed_size < data->kcd_addr_end - data->kcd_addr_begin) {
 506  		kcdata_debug_printf("%s: insufficient buffer size: kcd_length => %d e-b=> %lld our size: %zu\n",
 507  		    __func__, data->kcd_length, data->kcd_addr_end - data->kcd_addr_begin, total_uncompressed_size);
 508  		return KERN_INSUFFICIENT_BUFFER_SIZE;
 509  	}
 510  	uint32_t padding = kcdata_calc_padding(input_size);
 511  	assert(padding < sizeof(padding_data));
 512  
 513  	void *space_start = (void *) data->kcd_addr_end;
 514  	void *space_ptr = space_start;
 515  
 516  	/* create the output stream */
 517  	size_t total_uncompressed_space_remaining = total_uncompressed_size;
 518  
 519  	/* create the info data */
 520  	bzero(&info, sizeof(info));
 521  	info.type = type;
 522  	info.size = input_size + padding;
 523  	info.flags = kcdata_flags;
 524  
 525  	/*
 526  	 * The next possibly three compresses are needed separately because of the
 527  	 * scatter-gather nature of this operation. The kcdata item header (info)
 528  	 * and padding are on the stack, while the actual data is somewhere else.
 529  	 * */
 530  
 531  	/* create the input stream for info & compress */
 532  	enum kcdata_compression_flush flush = (padding || input_size) ? KCDCF_NO_FLUSH :
 533  	    cd->kcd_cd_flags & KCD_CD_FLAG_FINALIZE ? KCDCF_FINISH :
 534  	    KCDCF_SYNC_FLUSH;
 535  	kr = kcdata_do_compress(data, &info, sizeof(info), space_ptr, total_uncompressed_space_remaining, &wrote, flush);
 536  	if (kr != KERN_SUCCESS) {
 537  		return kr;
 538  	}
 539  	kcdata_debug_printf("%s: first wrote = %zu\n", __func__, wrote);
 540  	space_ptr  += wrote;
 541  	total_uncompressed_space_remaining -= wrote;
 542  
 543  	/* If there is input provided, compress that here */
 544  	if (input_size) {
 545  		flush = padding ? KCDCF_NO_FLUSH :
 546  		    cd->kcd_cd_flags & KCD_CD_FLAG_FINALIZE ? KCDCF_FINISH :
 547  		    KCDCF_SYNC_FLUSH;
 548  		kr = kcdata_do_compress(data, (void *) (uintptr_t) input_data, input_size, space_ptr, total_uncompressed_space_remaining, &wrote, flush);
 549  		if (kr != KERN_SUCCESS) {
 550  			return kr;
 551  		}
 552  		kcdata_debug_printf("%s: 2nd wrote = %zu\n", __func__, wrote);
 553  		space_ptr  += wrote;
 554  		total_uncompressed_space_remaining -= wrote;
 555  	}
 556  
 557  	/* If the item and its data require padding to maintain alignment,
 558  	 * "compress" that into the output buffer. */
 559  	if (padding) {
 560  		/* write the padding */
 561  		kr = kcdata_do_compress(data, padding_data, padding, space_ptr, total_uncompressed_space_remaining, &wrote,
 562  		    cd->kcd_cd_flags & KCD_CD_FLAG_FINALIZE ? KCDCF_FINISH : KCDCF_SYNC_FLUSH);
 563  		if (kr != KERN_SUCCESS) {
 564  			return kr;
 565  		}
 566  		kcdata_debug_printf("%s: 3rd wrote = %zu\n", __func__, wrote);
 567  		if (wrote == 0) {
 568  			return KERN_FAILURE;
 569  		}
 570  		space_ptr  += wrote;
 571  		total_uncompressed_space_remaining -= wrote;
 572  	}
 573  
 574  	assert((size_t)(space_ptr - space_start) <= total_uncompressed_size);
 575  
 576  	/* move the end marker forward */
 577  	data->kcd_addr_end = (mach_vm_address_t) (space_start + (total_uncompressed_size - total_uncompressed_space_remaining));
 578  
 579  	return KERN_SUCCESS;
 580  }
 581  
 582  /*
 583   * kcdata_compress_chunk:
 584   *		Like kcdata_compress_chunk_with_flags(), but uses the default set of kcdata flags,
 585   *		i.e. padding and also saves the amount of padding bytes.
 586   *
 587   * Returns are the same as in kcdata_compress_chunk_with_flags()
 588   */
 589  kern_return_t
 590  kcdata_compress_chunk(kcdata_descriptor_t data, uint32_t type, const void *input_data, uint32_t input_size)
 591  {
 592  	/* these flags are for kcdata - store that the struct is padded and store the amount of padding bytes */
 593  	uint64_t flags = (KCDATA_FLAGS_STRUCT_PADDING_MASK & kcdata_calc_padding(input_size)) | KCDATA_FLAGS_STRUCT_HAS_PADDING;
 594  	return kcdata_compress_chunk_with_flags(data, type, input_data, input_size, flags);
 595  }
 596  
 597  kern_return_t
 598  kcdata_push_data(kcdata_descriptor_t data, uint32_t type, uint32_t size, const void *input_data)
 599  {
 600  	if (data->kcd_flags & KCFLAG_USE_COMPRESSION) {
 601  		return kcdata_compress_chunk(data, type, input_data, size);
 602  	} else {
 603  		kern_return_t ret;
 604  		mach_vm_address_t uaddr = 0;
 605  		ret = kcdata_get_memory_addr(data, type, size, &uaddr);
 606  		if (ret != KERN_SUCCESS) {
 607  			return ret;
 608  		}
 609  
 610  		kcdata_memcpy(data, uaddr, input_data, size);
 611  		return KERN_SUCCESS;
 612  	}
 613  }
 614  
 615  kern_return_t
 616  kcdata_push_array(kcdata_descriptor_t data, uint32_t type_of_element, uint32_t size_of_element, uint32_t count, const void *input_data)
 617  {
 618  	uint64_t flags      = type_of_element;
 619  	flags               = (flags << 32) | count;
 620  	uint32_t total_size = count * size_of_element;
 621  	uint32_t pad        = kcdata_calc_padding(total_size);
 622  
 623  	if (data->kcd_flags & KCFLAG_USE_COMPRESSION) {
 624  		return kcdata_compress_chunk_with_flags(data, KCDATA_TYPE_ARRAY_PAD0 | pad, input_data, total_size, flags);
 625  	} else {
 626  		kern_return_t ret;
 627  		mach_vm_address_t uaddr = 0;
 628  		ret = kcdata_get_memory_addr_with_flavor(data, KCDATA_TYPE_ARRAY_PAD0 | pad, total_size, flags, &uaddr);
 629  		if (ret != KERN_SUCCESS) {
 630  			return ret;
 631  		}
 632  
 633  		kcdata_memcpy(data, uaddr, input_data, total_size);
 634  		return KERN_SUCCESS;
 635  	}
 636  }
 637  
 638  /* A few words on how window compression works:
 639   *
 640   * This is how the buffer looks when the window is opened:
 641   *
 642   * X---------------------------------------------------------------------X
 643   * |                                |                                    |
 644   * |   Filled with stackshot data   |            Zero bytes              |
 645   * |                                |                                    |
 646   * X---------------------------------------------------------------------X
 647   *                                  ^
 648   *									\ - kcd_addr_end
 649   *
 650   * Opening a window will save the current kcd_addr_end to kcd_cd_mark_begin.
 651   *
 652   * Any kcdata_* operation will then push data to the buffer like normal. (If
 653   * you call any compressing functions they will pass-through, i.e. no
 654   * compression will be done) Once the window is closed, the following takes
 655   * place:
 656   *
 657   * X---------------------------------------------------------------------X
 658   * |               |                    |                    |           |
 659   * | Existing data |     New data       |   Scratch buffer   |           |
 660   * |               |                    |                    |           |
 661   * X---------------------------------------------------------------------X
 662   *				   ^                    ^                    ^
 663   *				   |                    |                    |
 664   *				   \ -kcd_cd_mark_begin |                    |
 665   *							            |                    |
 666   *							            \ - kcd_addr_end     |
 667   *							                                 |
 668   *		 kcd_addr_end + (kcd_addr_end - kcd_cd_mark_begin) - /
 669   *
 670   *	(1) The data between kcd_cd_mark_begin and kcd_addr_end is fed to the
 671   *      compression algorithm to compress to the scratch buffer.
 672   *  (2) The scratch buffer's contents are copied into the area denoted "New
 673   *      data" above. Effectively overwriting the uncompressed data with the
 674   *      compressed one.
 675   *  (3) kcd_addr_end is then rewound to kcd_cd_mark_begin + sizeof_compressed_data
 676   */
 677  
 678  /* Record the state, and restart compression from this later */
 679  void
 680  kcdata_compression_window_open(kcdata_descriptor_t data)
 681  {
 682  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 683  	assert((cd->kcd_cd_flags & KCD_CD_FLAG_IN_MARK) == 0);
 684  
 685  	if (data->kcd_flags & KCFLAG_USE_COMPRESSION) {
 686  		cd->kcd_cd_flags |= KCD_CD_FLAG_IN_MARK;
 687  		cd->kcd_cd_mark_begin = data->kcd_addr_end;
 688  	}
 689  }
 690  
 691  /* Compress the region between the mark and the current end */
 692  kern_return_t
 693  kcdata_compression_window_close(kcdata_descriptor_t data)
 694  {
 695  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 696  	uint64_t total_size, max_size;
 697  	void *space_start, *space_ptr;
 698  	size_t total_uncompressed_space_remaining, wrote = 0;
 699  	kern_return_t kr;
 700  
 701  	if ((data->kcd_flags & KCFLAG_USE_COMPRESSION) == 0) {
 702  		return KERN_SUCCESS;
 703  	}
 704  
 705  	assert(cd->kcd_cd_flags & KCD_CD_FLAG_IN_MARK);
 706  
 707  	if (data->kcd_addr_end == (mach_vm_address_t) cd->kcd_cd_mark_begin) {
 708  		/* clear the window marker and return, this is a no-op */
 709  		cd->kcd_cd_flags &= ~KCD_CD_FLAG_IN_MARK;
 710  		return KERN_SUCCESS;
 711  	}
 712  
 713  	assert(cd->kcd_cd_mark_begin < data->kcd_addr_end);
 714  	total_size = data->kcd_addr_end - (uint64_t) cd->kcd_cd_mark_begin;
 715  	max_size = (uint64_t) kcdata_compression_bound(data, total_size);
 716  	kcdata_debug_printf("%s: total_size = %lld\n", __func__, total_size);
 717  
 718  	/*
 719  	 * first, get memory space. The uncompressed size must fit in the remained
 720  	 * of the kcdata buffer, in case the compression algorithm doesn't actually
 721  	 * compress the data at all.
 722  	 */
 723  	if (max_size > data->kcd_length ||
 724  	    data->kcd_length - max_size < data->kcd_addr_end - data->kcd_addr_begin) {
 725  		kcdata_debug_printf("%s: insufficient buffer size: kcd_length => %d e-b=> %lld our size: %lld\n",
 726  		    __func__, data->kcd_length, data->kcd_addr_end - data->kcd_addr_begin, max_size);
 727  		return KERN_INSUFFICIENT_BUFFER_SIZE;
 728  	}
 729  
 730  	/* clear the window marker */
 731  	cd->kcd_cd_flags &= ~KCD_CD_FLAG_IN_MARK;
 732  
 733  	space_start = (void *) data->kcd_addr_end;
 734  	space_ptr = space_start;
 735  	total_uncompressed_space_remaining = (unsigned int) max_size;
 736  	kr = kcdata_do_compress(data, (void *) cd->kcd_cd_mark_begin, total_size, space_ptr,
 737  	    total_uncompressed_space_remaining, &wrote, KCDCF_SYNC_FLUSH);
 738  	if (kr != KERN_SUCCESS) {
 739  		return kr;
 740  	}
 741  	kcdata_debug_printf("%s: first wrote = %zu\n", __func__, wrote);
 742  	if (wrote == 0) {
 743  		return KERN_FAILURE;
 744  	}
 745  	space_ptr   += wrote;
 746  	total_uncompressed_space_remaining  -= wrote;
 747  
 748  	assert((size_t)(space_ptr - space_start) <= max_size);
 749  
 750  	/* copy to the original location */
 751  	kcdata_memcpy(data, cd->kcd_cd_mark_begin, space_start, (uint32_t) (max_size - total_uncompressed_space_remaining));
 752  
 753  	/* rewind the end marker */
 754  	data->kcd_addr_end = cd->kcd_cd_mark_begin + (max_size - total_uncompressed_space_remaining);
 755  
 756  	return KERN_SUCCESS;
 757  }
 758  
 759  static kern_return_t
 760  kcdata_get_compression_stats_zlib(kcdata_descriptor_t data, uint64_t *totalout, uint64_t *totalin)
 761  {
 762  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 763  	z_stream *zs = &cd->kcd_cd_zs;
 764  
 765  	assert((cd->kcd_cd_flags & KCD_CD_FLAG_IN_MARK) == 0);
 766  
 767  	*totalout = (uint64_t) zs->total_out;
 768  	*totalin = (uint64_t) zs->total_in;
 769  
 770  	return KERN_SUCCESS;
 771  }
 772  
 773  static kern_return_t
 774  kcdata_get_compression_stats(kcdata_descriptor_t data, uint64_t *totalout, uint64_t *totalin)
 775  {
 776  	kern_return_t kr;
 777  
 778  	switch (data->kcd_comp_d.kcd_cd_compression_type) {
 779  	case KCDCT_ZLIB:
 780  		kr = kcdata_get_compression_stats_zlib(data, totalout, totalin);
 781  		break;
 782  	case KCDCT_NONE:
 783  		kr = KERN_SUCCESS;
 784  		break;
 785  	default:
 786  		panic("invalid compression flag 0x%llx in kcdata_write_compression_stats", (data->kcd_comp_d.kcd_cd_compression_type));
 787  	}
 788  
 789  	return kr;
 790  }
 791  
 792  kern_return_t
 793  kcdata_write_compression_stats(kcdata_descriptor_t data)
 794  {
 795  	kern_return_t kr;
 796  	uint64_t totalout, totalin;
 797  
 798  	kr = kcdata_get_compression_stats(data, &totalout, &totalin);
 799  	if (kr != KERN_SUCCESS) {
 800  		return kr;
 801  	}
 802  
 803  	*(uint64_t *)data->kcd_comp_d.kcd_cd_totalout_addr = totalout;
 804  	*(uint64_t *)data->kcd_comp_d.kcd_cd_totalin_addr = totalin;
 805  
 806  	return kr;
 807  }
 808  
 809  static kern_return_t
 810  kcdata_finish_compression_zlib(kcdata_descriptor_t data)
 811  {
 812  	struct kcdata_compress_descriptor *cd = &data->kcd_comp_d;
 813  	z_stream *zs = &cd->kcd_cd_zs;
 814  
 815  	/*
 816  	 * macOS on x86 w/ coprocessor ver. 2 and later context: Stackshot compression leaves artifacts
 817  	 * in the panic buffer which interferes with CRC checks. The CRC is calculated here over the full
 818  	 * buffer but only the portion with valid panic data is sent to iBoot via the SMC. When iBoot
 819  	 * calculates the CRC to compare with the value in the header it uses a zero-filled buffer.
 820  	 * The stackshot compression leaves non-zero bytes behind so those must be cleared prior to the CRC calculation.
 821  	 *
 822  	 * All other contexts: The stackshot compression artifacts are present in its panic buffer but the CRC check
 823  	 * is done on the same buffer for the before and after calculation so there's nothing functionally
 824  	 * broken. The same buffer cleanup is done here for completeness' sake.
 825  	 * From rdar://problem/64381661
 826  	 */
 827  
 828  	void* stackshot_end = (char*)data->kcd_addr_begin + kcdata_memory_get_used_bytes(data);
 829  	uint32_t zero_fill_size = data->kcd_length - kcdata_memory_get_used_bytes(data);
 830  	bzero(stackshot_end, zero_fill_size);
 831  
 832  	if (deflateEnd(zs) == Z_OK) {
 833  		return KERN_SUCCESS;
 834  	} else {
 835  		return KERN_FAILURE;
 836  	}
 837  }
 838  
 839  kern_return_t
 840  kcdata_finish_compression(kcdata_descriptor_t data)
 841  {
 842  	kcdata_write_compression_stats(data);
 843  
 844  	switch (data->kcd_comp_d.kcd_cd_compression_type) {
 845  	case KCDCT_ZLIB:
 846  		data->kcd_length += data->kcd_comp_d.kcd_cd_maxoffset;
 847  		return kcdata_finish_compression_zlib(data);
 848  	case KCDCT_NONE:
 849  		return KERN_SUCCESS;
 850  	default:
 851  		panic("invalid compression type 0x%llxin kcdata_finish_compression", data->kcd_comp_d.kcd_cd_compression_type);
 852  	}
 853  }
 854  
 855  void
 856  kcd_finalize_compression(kcdata_descriptor_t data)
 857  {
 858  	if (data->kcd_flags & KCFLAG_USE_COMPRESSION) {
 859  		data->kcd_comp_d.kcd_cd_flags |= KCD_CD_FLAG_FINALIZE;
 860  	}
 861  }
 862  
 863  /*
 864   * Routine: kcdata_get_memory_addr
 865   * Desc: get memory address in the userspace memory for corpse info
 866   *       NOTE: The caller is responsible for zeroing the resulting memory or
 867   *             using other means to mark memory if it has failed populating the
 868   *             data in middle of operation.
 869   * params:  data - pointer describing the crash info allocation
 870   *	        type - type of data to be put. See corpse.h for defined types
 871   *          size - size requested. The header describes this size
 872   * returns: mach_vm_address_t address in user memory for copyout().
 873   */
 874  kern_return_t
 875  kcdata_get_memory_addr(kcdata_descriptor_t data, uint32_t type, uint32_t size, mach_vm_address_t * user_addr)
 876  {
 877  	/* record number of padding bytes as lower 4 bits of flags */
 878  	uint64_t flags = (KCDATA_FLAGS_STRUCT_PADDING_MASK & kcdata_calc_padding(size)) | KCDATA_FLAGS_STRUCT_HAS_PADDING;
 879  	return kcdata_get_memory_addr_with_flavor(data, type, size, flags, user_addr);
 880  }
 881  
 882  /*
 883   * Routine: kcdata_add_buffer_end
 884   *
 885   * Desc: Write buffer end marker.  This does not advance the end pointer in the
 886   * kcdata_descriptor_t, so it may be used conservatively before additional data
 887   * is added, as long as it is at least called after the last time data is added.
 888   *
 889   * params:  data - pointer describing the crash info allocation
 890   */
 891  
 892  kern_return_t
 893  kcdata_write_buffer_end(kcdata_descriptor_t data)
 894  {
 895  	struct kcdata_item info;
 896  	bzero(&info, sizeof(info));
 897  	info.type = KCDATA_TYPE_BUFFER_END;
 898  	info.size = 0;
 899  	return kcdata_memcpy(data, data->kcd_addr_end, &info, sizeof(info));
 900  }
 901  
 902  /*
 903   * Routine: kcdata_get_memory_addr_with_flavor
 904   * Desc: internal function with flags field. See documentation for kcdata_get_memory_addr for details
 905   */
 906  
 907  static kern_return_t
 908  kcdata_get_memory_addr_with_flavor(
 909  	kcdata_descriptor_t data,
 910  	uint32_t type,
 911  	uint32_t size,
 912  	uint64_t flags,
 913  	mach_vm_address_t *user_addr)
 914  {
 915  	kern_return_t kr;
 916  	struct kcdata_item info;
 917  
 918  	uint32_t orig_size = size;
 919  	/* make sure 16 byte aligned */
 920  	uint32_t padding = kcdata_calc_padding(size);
 921  	size += padding;
 922  	uint32_t total_size  = size + sizeof(info);
 923  
 924  	if (user_addr == NULL || data == NULL || total_size + sizeof(info) < orig_size) {
 925  		return KERN_INVALID_ARGUMENT;
 926  	}
 927  
 928  	assert(((data->kcd_flags & KCFLAG_USE_COMPRESSION) && (data->kcd_comp_d.kcd_cd_flags & KCD_CD_FLAG_IN_MARK))
 929  	    || ((data->kcd_flags & KCFLAG_USE_COMPRESSION) == 0));
 930  
 931  	bzero(&info, sizeof(info));
 932  	info.type  = type;
 933  	info.size = size;
 934  	info.flags = flags;
 935  
 936  	/* check available memory, including trailer size for KCDATA_TYPE_BUFFER_END */
 937  	if (total_size + sizeof(info) > data->kcd_length ||
 938  	    data->kcd_length - (total_size + sizeof(info)) < data->kcd_addr_end - data->kcd_addr_begin) {
 939  		return KERN_INSUFFICIENT_BUFFER_SIZE;
 940  	}
 941  
 942  	kr = kcdata_memcpy(data, data->kcd_addr_end, &info, sizeof(info));
 943  	if (kr) {
 944  		return kr;
 945  	}
 946  
 947  	data->kcd_addr_end += sizeof(info);
 948  
 949  	if (padding) {
 950  		kr = kcdata_bzero(data, data->kcd_addr_end + size - padding, padding);
 951  		if (kr) {
 952  			return kr;
 953  		}
 954  	}
 955  
 956  	*user_addr = data->kcd_addr_end;
 957  	data->kcd_addr_end += size;
 958  
 959  	if (!(data->kcd_flags & KCFLAG_NO_AUTO_ENDBUFFER)) {
 960  		/* setup the end header as well */
 961  		return kcdata_write_buffer_end(data);
 962  	} else {
 963  		return KERN_SUCCESS;
 964  	}
 965  }
 966  
 967  /* Routine: kcdata_get_memory_size_for_data
 968   * Desc: returns the amount of memory that is required to store the information
 969   *       in kcdata
 970   */
 971  static size_t
 972  kcdata_get_memory_size_for_data(uint32_t size)
 973  {
 974  	return size + kcdata_calc_padding(size) + sizeof(struct kcdata_item);
 975  }
 976  
 977  /*
 978   * Routine: kcdata_get_memory_addr_for_array
 979   * Desc: get memory address in the userspace memory for corpse info
 980   *       NOTE: The caller is responsible to zero the resulting memory or
 981   *             user other means to mark memory if it has failed populating the
 982   *             data in middle of operation.
 983   * params:  data - pointer describing the crash info allocation
 984   *          type_of_element - type of data to be put. See kern_cdata.h for defined types
 985   *          size_of_element - size of element. The header describes this size
 986   *          count - num of elements in array.
 987   * returns: mach_vm_address_t address in user memory for copyout().
 988   */
 989  
 990  kern_return_t
 991  kcdata_get_memory_addr_for_array(
 992  	kcdata_descriptor_t data,
 993  	uint32_t type_of_element,
 994  	uint32_t size_of_element,
 995  	uint32_t count,
 996  	mach_vm_address_t *user_addr)
 997  {
 998  	/* for arrays we record the number of padding bytes as the low-order 4 bits
 999  	 * of the type field.  KCDATA_TYPE_ARRAY_PAD{x} means x bytes of pad. */
1000  	uint64_t flags      = type_of_element;
1001  	flags               = (flags << 32) | count;
1002  	uint32_t total_size = count * size_of_element;
1003  	uint32_t pad        = kcdata_calc_padding(total_size);
1004  
1005  	return kcdata_get_memory_addr_with_flavor(data, KCDATA_TYPE_ARRAY_PAD0 | pad, total_size, flags, user_addr);
1006  }
1007  
1008  /*
1009   * Routine: kcdata_add_container_marker
1010   * Desc: Add a container marker in the buffer for type and identifier.
1011   * params:  data - pointer describing the crash info allocation
1012   *          header_type - one of (KCDATA_TYPE_CONTAINER_BEGIN ,KCDATA_TYPE_CONTAINER_END)
1013   *          container_type - type of data to be put. See kern_cdata.h for defined types
1014   *          identifier - unique identifier. This is required to match nested containers.
1015   * returns: return value of kcdata_get_memory_addr()
1016   */
1017  
1018  kern_return_t
1019  kcdata_add_container_marker(
1020  	kcdata_descriptor_t data,
1021  	uint32_t header_type,
1022  	uint32_t container_type,
1023  	uint64_t identifier)
1024  {
1025  	mach_vm_address_t user_addr;
1026  	kern_return_t kr;
1027  	uint32_t data_size;
1028  
1029  	assert(header_type == KCDATA_TYPE_CONTAINER_END || header_type == KCDATA_TYPE_CONTAINER_BEGIN);
1030  
1031  	data_size = (header_type == KCDATA_TYPE_CONTAINER_BEGIN)? sizeof(uint32_t): 0;
1032  
1033  	if (!(data->kcd_flags & KCFLAG_USE_COMPRESSION)) {
1034  		kr = kcdata_get_memory_addr_with_flavor(data, header_type, data_size, identifier, &user_addr);
1035  		if (kr != KERN_SUCCESS) {
1036  			return kr;
1037  		}
1038  
1039  		if (data_size) {
1040  			kr = kcdata_memcpy(data, user_addr, &container_type, data_size);
1041  		}
1042  	} else {
1043  		kr = kcdata_compress_chunk_with_flags(data, header_type, &container_type, data_size, identifier);
1044  	}
1045  
1046  	return kr;
1047  }
1048  
1049  /*
1050   * Routine: kcdata_undo_addcontainer_begin
1051   * Desc: call this after adding a container begin but before adding anything else to revert.
1052   */
1053  kern_return_t
1054  kcdata_undo_add_container_begin(kcdata_descriptor_t data)
1055  {
1056  	/*
1057  	 * the payload of a container begin is a single uint64_t.  It is padded out
1058  	 * to 16 bytes.
1059  	 */
1060  	const mach_vm_address_t padded_payload_size = 16;
1061  	data->kcd_addr_end -= sizeof(struct kcdata_item) + padded_payload_size;
1062  
1063  	if (!(data->kcd_flags & KCFLAG_NO_AUTO_ENDBUFFER)) {
1064  		/* setup the end header as well */
1065  		return kcdata_write_buffer_end(data);
1066  	} else {
1067  		return KERN_SUCCESS;
1068  	}
1069  }
1070  
1071  /*
1072   * Routine: kcdata_memcpy
1073   * Desc: a common function to copy data out based on either copyout or memcopy flags
1074   * params:  data - pointer describing the kcdata buffer
1075   *          dst_addr - destination address
1076   *          src_addr - source address
1077   *          size - size in bytes to copy.
1078   * returns: KERN_NO_ACCESS if copyout fails.
1079   */
1080  
1081  kern_return_t
1082  kcdata_memcpy(kcdata_descriptor_t data, mach_vm_address_t dst_addr, const void *src_addr, uint32_t size)
1083  {
1084  	if (data->kcd_flags & KCFLAG_USE_COPYOUT) {
1085  		if (copyout(src_addr, dst_addr, size)) {
1086  			return KERN_NO_ACCESS;
1087  		}
1088  	} else {
1089  		memcpy((void *)dst_addr, src_addr, size);
1090  	}
1091  	return KERN_SUCCESS;
1092  }
1093  
1094  /*
1095   * Routine: kcdata_bzero
1096   * Desc: zero out a portion of a kcdata buffer.
1097   */
1098  kern_return_t
1099  kcdata_bzero(kcdata_descriptor_t data, mach_vm_address_t dst_addr, uint32_t size)
1100  {
1101  	kern_return_t kr = KERN_SUCCESS;
1102  	if (data->kcd_flags & KCFLAG_USE_COPYOUT) {
1103  		uint8_t zeros[16] = {};
1104  		while (size) {
1105  			uint32_t block_size = MIN(size, 16);
1106  			kr = copyout(&zeros, dst_addr, block_size);
1107  			if (kr) {
1108  				return KERN_NO_ACCESS;
1109  			}
1110  			size -= block_size;
1111  		}
1112  		return KERN_SUCCESS;
1113  	} else {
1114  		bzero((void*)dst_addr, size);
1115  		return KERN_SUCCESS;
1116  	}
1117  }
1118  
1119  /*
1120   * Routine: kcdata_add_type_definition
1121   * Desc: add type definition to kcdata buffer.
1122   *       see feature description in documentation above.
1123   * params:  data - pointer describing the kcdata buffer
1124   *          type_id - unique type identifier for this data
1125   *          type_name - a string of max KCDATA_DESC_MAXLEN size for name of type
1126   *          elements_array - address to descriptors for each field in struct
1127   *          elements_count - count of how many fields are there in struct.
1128   * returns: return code from kcdata_get_memory_addr in case of failure.
1129   */
1130  
1131  kern_return_t
1132  kcdata_add_type_definition(
1133  	kcdata_descriptor_t data,
1134  	uint32_t type_id,
1135  	char *type_name,
1136  	struct kcdata_subtype_descriptor *elements_array_addr,
1137  	uint32_t elements_count)
1138  {
1139  	kern_return_t kr = KERN_SUCCESS;
1140  	struct kcdata_type_definition kc_type_definition;
1141  	mach_vm_address_t user_addr;
1142  	uint32_t total_size = sizeof(struct kcdata_type_definition);
1143  	bzero(&kc_type_definition, sizeof(kc_type_definition));
1144  
1145  	if (strlen(type_name) >= KCDATA_DESC_MAXLEN) {
1146  		return KERN_INVALID_ARGUMENT;
1147  	}
1148  	strlcpy(&kc_type_definition.kct_name[0], type_name, KCDATA_DESC_MAXLEN);
1149  	kc_type_definition.kct_num_elements = elements_count;
1150  	kc_type_definition.kct_type_identifier = type_id;
1151  
1152  	total_size += elements_count * sizeof(struct kcdata_subtype_descriptor);
1153  	/* record number of padding bytes as lower 4 bits of flags */
1154  	if (KERN_SUCCESS != (kr = kcdata_get_memory_addr_with_flavor(data, KCDATA_TYPE_TYPEDEFINTION, total_size,
1155  	    kcdata_calc_padding(total_size), &user_addr))) {
1156  		return kr;
1157  	}
1158  	if (KERN_SUCCESS != (kr = kcdata_memcpy(data, user_addr, (void *)&kc_type_definition, sizeof(struct kcdata_type_definition)))) {
1159  		return kr;
1160  	}
1161  	user_addr += sizeof(struct kcdata_type_definition);
1162  	if (KERN_SUCCESS != (kr = kcdata_memcpy(data, user_addr, (void *)elements_array_addr, elements_count * sizeof(struct kcdata_subtype_descriptor)))) {
1163  		return kr;
1164  	}
1165  	return kr;
1166  }
1167  
1168  kern_return_t
1169  kcdata_add_uint64_with_description(kcdata_descriptor_t data_desc, uint64_t data, const char * description)
1170  {
1171  	if (strlen(description) >= KCDATA_DESC_MAXLEN) {
1172  		return KERN_INVALID_ARGUMENT;
1173  	}
1174  
1175  	kern_return_t kr = 0;
1176  	mach_vm_address_t user_addr;
1177  	struct _uint64_with_description_data save_data;
1178  	const uint64_t size_req = sizeof(save_data);
1179  	bzero(&save_data, size_req);
1180  
1181  	strlcpy(&(save_data.desc[0]), description, sizeof(save_data.desc));
1182  	save_data.data = data;
1183  
1184  	if (data_desc->kcd_flags & KCFLAG_USE_COMPRESSION) {
1185  		/* allocate space for the output */
1186  		return kcdata_compress_chunk(data_desc, KCDATA_TYPE_UINT64_DESC, &save_data, size_req);
1187  	}
1188  
1189  	kr = kcdata_get_memory_addr(data_desc, KCDATA_TYPE_UINT64_DESC, size_req, &user_addr);
1190  	if (kr != KERN_SUCCESS) {
1191  		return kr;
1192  	}
1193  
1194  	if (data_desc->kcd_flags & KCFLAG_USE_COPYOUT) {
1195  		if (copyout(&save_data, user_addr, size_req)) {
1196  			return KERN_NO_ACCESS;
1197  		}
1198  	} else {
1199  		memcpy((void *)user_addr, &save_data, size_req);
1200  	}
1201  	return KERN_SUCCESS;
1202  }
1203  
1204  kern_return_t
1205  kcdata_add_uint32_with_description(
1206  	kcdata_descriptor_t data_desc,
1207  	uint32_t data,
1208  	const char *description)
1209  {
1210  	assert(strlen(description) < KCDATA_DESC_MAXLEN);
1211  	if (strlen(description) >= KCDATA_DESC_MAXLEN) {
1212  		return KERN_INVALID_ARGUMENT;
1213  	}
1214  	kern_return_t kr = 0;
1215  	mach_vm_address_t user_addr;
1216  	struct _uint32_with_description_data save_data;
1217  	const uint64_t size_req = sizeof(save_data);
1218  
1219  	bzero(&save_data, size_req);
1220  	strlcpy(&(save_data.desc[0]), description, sizeof(save_data.desc));
1221  	save_data.data = data;
1222  
1223  	if (data_desc->kcd_flags & KCFLAG_USE_COMPRESSION) {
1224  		/* allocate space for the output */
1225  		return kcdata_compress_chunk(data_desc, KCDATA_TYPE_UINT32_DESC, &save_data, size_req);
1226  	}
1227  
1228  	kr = kcdata_get_memory_addr(data_desc, KCDATA_TYPE_UINT32_DESC, size_req, &user_addr);
1229  	if (kr != KERN_SUCCESS) {
1230  		return kr;
1231  	}
1232  
1233  	if (data_desc->kcd_flags & KCFLAG_USE_COPYOUT) {
1234  		if (copyout(&save_data, user_addr, size_req)) {
1235  			return KERN_NO_ACCESS;
1236  		}
1237  	} else {
1238  		memcpy((void *)user_addr, &save_data, size_req);
1239  	}
1240  
1241  	return KERN_SUCCESS;
1242  }
1243  
1244  
1245  /* end buffer management api */