0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033 #include <linux/export.h>
0034 #include <linux/kernel.h>
0035
0036 #include <asm/octeon/cvmx.h>
0037 #include <asm/octeon/cvmx-spinlock.h>
0038 #include <asm/octeon/cvmx-bootmem.h>
0039
0040
0041
0042
0043 static struct cvmx_bootmem_desc *cvmx_bootmem_desc;
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058 #define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field) \
0059 __cvmx_bootmem_desc_get(addr, \
0060 offsetof(struct cvmx_bootmem_named_block_desc, field), \
0061 sizeof_field(struct cvmx_bootmem_named_block_desc, field))
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 static inline uint64_t __cvmx_bootmem_desc_get(uint64_t base, int offset,
0076 int size)
0077 {
0078 base = (1ull << 63) | (base + offset);
0079 switch (size) {
0080 case 4:
0081 return cvmx_read64_uint32(base);
0082 case 8:
0083 return cvmx_read64_uint64(base);
0084 default:
0085 return 0;
0086 }
0087 }
0088
0089
0090
0091
0092
0093
0094
0095 #define NEXT_OFFSET 0
0096 #define SIZE_OFFSET 8
0097
0098 static void cvmx_bootmem_phy_set_size(uint64_t addr, uint64_t size)
0099 {
0100 cvmx_write64_uint64((addr + SIZE_OFFSET) | (1ull << 63), size);
0101 }
0102
0103 static void cvmx_bootmem_phy_set_next(uint64_t addr, uint64_t next)
0104 {
0105 cvmx_write64_uint64((addr + NEXT_OFFSET) | (1ull << 63), next);
0106 }
0107
0108 static uint64_t cvmx_bootmem_phy_get_size(uint64_t addr)
0109 {
0110 return cvmx_read64_uint64((addr + SIZE_OFFSET) | (1ull << 63));
0111 }
0112
0113 static uint64_t cvmx_bootmem_phy_get_next(uint64_t addr)
0114 {
0115 return cvmx_read64_uint64((addr + NEXT_OFFSET) | (1ull << 63));
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 static void *cvmx_bootmem_alloc_range(uint64_t size, uint64_t alignment,
0132 uint64_t min_addr, uint64_t max_addr)
0133 {
0134 int64_t address;
0135 address =
0136 cvmx_bootmem_phy_alloc(size, min_addr, max_addr, alignment, 0);
0137
0138 if (address > 0)
0139 return cvmx_phys_to_ptr(address);
0140 else
0141 return NULL;
0142 }
0143
0144 void *cvmx_bootmem_alloc_address(uint64_t size, uint64_t address,
0145 uint64_t alignment)
0146 {
0147 return cvmx_bootmem_alloc_range(size, alignment, address,
0148 address + size);
0149 }
0150
0151 void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr,
0152 uint64_t max_addr, uint64_t align,
0153 char *name)
0154 {
0155 int64_t addr;
0156
0157 addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr,
0158 align, name, 0);
0159 if (addr >= 0)
0160 return cvmx_phys_to_ptr(addr);
0161 else
0162 return NULL;
0163 }
0164
0165 void *cvmx_bootmem_alloc_named(uint64_t size, uint64_t alignment, char *name)
0166 {
0167 return cvmx_bootmem_alloc_named_range(size, 0, 0, alignment, name);
0168 }
0169 EXPORT_SYMBOL(cvmx_bootmem_alloc_named);
0170
0171 void cvmx_bootmem_lock(void)
0172 {
0173 cvmx_spinlock_lock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock));
0174 }
0175
0176 void cvmx_bootmem_unlock(void)
0177 {
0178 cvmx_spinlock_unlock((cvmx_spinlock_t *) &(cvmx_bootmem_desc->lock));
0179 }
0180
0181 int cvmx_bootmem_init(void *mem_desc_ptr)
0182 {
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 if (!cvmx_bootmem_desc) {
0198 #if defined(CVMX_ABI_64)
0199
0200 cvmx_bootmem_desc = cvmx_phys_to_ptr(CAST64(mem_desc_ptr));
0201 #else
0202 cvmx_bootmem_desc = (struct cvmx_bootmem_desc *) mem_desc_ptr;
0203 #endif
0204 }
0205
0206 return 0;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min,
0218 uint64_t address_max, uint64_t alignment,
0219 uint32_t flags)
0220 {
0221
0222 uint64_t head_addr;
0223 uint64_t ent_addr;
0224
0225 uint64_t prev_addr = 0;
0226 uint64_t new_ent_addr = 0;
0227 uint64_t desired_min_addr;
0228
0229 #ifdef DEBUG
0230 cvmx_dprintf("cvmx_bootmem_phy_alloc: req_size: 0x%llx, "
0231 "min_addr: 0x%llx, max_addr: 0x%llx, align: 0x%llx\n",
0232 (unsigned long long)req_size,
0233 (unsigned long long)address_min,
0234 (unsigned long long)address_max,
0235 (unsigned long long)alignment);
0236 #endif
0237
0238 if (cvmx_bootmem_desc->major_version > 3) {
0239 cvmx_dprintf("ERROR: Incompatible bootmem descriptor "
0240 "version: %d.%d at addr: %p\n",
0241 (int)cvmx_bootmem_desc->major_version,
0242 (int)cvmx_bootmem_desc->minor_version,
0243 cvmx_bootmem_desc);
0244 goto error_out;
0245 }
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256 if (!req_size)
0257 goto error_out;
0258
0259
0260 req_size = (req_size + (CVMX_BOOTMEM_ALIGNMENT_SIZE - 1)) &
0261 ~(CVMX_BOOTMEM_ALIGNMENT_SIZE - 1);
0262
0263
0264
0265
0266
0267
0268
0269 if (address_min && !address_max)
0270 address_max = address_min + req_size;
0271 else if (!address_min && !address_max)
0272 address_max = ~0ull;
0273
0274
0275
0276
0277
0278
0279 if (alignment < CVMX_BOOTMEM_ALIGNMENT_SIZE)
0280 alignment = CVMX_BOOTMEM_ALIGNMENT_SIZE;
0281
0282
0283
0284
0285
0286
0287 if (alignment)
0288 address_min = ALIGN(address_min, alignment);
0289
0290
0291
0292
0293
0294
0295 if (req_size > address_max - address_min)
0296 goto error_out;
0297
0298
0299
0300 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0301 cvmx_bootmem_lock();
0302 head_addr = cvmx_bootmem_desc->head_addr;
0303 ent_addr = head_addr;
0304 for (; ent_addr;
0305 prev_addr = ent_addr,
0306 ent_addr = cvmx_bootmem_phy_get_next(ent_addr)) {
0307 uint64_t usable_base, usable_max;
0308 uint64_t ent_size = cvmx_bootmem_phy_get_size(ent_addr);
0309
0310 if (cvmx_bootmem_phy_get_next(ent_addr)
0311 && ent_addr > cvmx_bootmem_phy_get_next(ent_addr)) {
0312 cvmx_dprintf("Internal bootmem_alloc() error: ent: "
0313 "0x%llx, next: 0x%llx\n",
0314 (unsigned long long)ent_addr,
0315 (unsigned long long)
0316 cvmx_bootmem_phy_get_next(ent_addr));
0317 goto error_out;
0318 }
0319
0320
0321
0322
0323
0324
0325 usable_base =
0326 ALIGN(max(address_min, ent_addr), alignment);
0327 usable_max = min(address_max, ent_addr + ent_size);
0328
0329
0330
0331
0332
0333 desired_min_addr = usable_base;
0334
0335
0336
0337
0338 if (!((ent_addr + ent_size) > usable_base
0339 && ent_addr < address_max
0340 && req_size <= usable_max - usable_base))
0341 continue;
0342
0343
0344
0345
0346
0347
0348 if (flags & CVMX_BOOTMEM_FLAG_END_ALLOC) {
0349 desired_min_addr = usable_max - req_size;
0350
0351
0352
0353
0354 desired_min_addr &= ~(alignment - 1);
0355 }
0356
0357
0358 if (desired_min_addr == ent_addr) {
0359 if (req_size < ent_size) {
0360
0361
0362
0363
0364 new_ent_addr = ent_addr + req_size;
0365 cvmx_bootmem_phy_set_next(new_ent_addr,
0366 cvmx_bootmem_phy_get_next(ent_addr));
0367 cvmx_bootmem_phy_set_size(new_ent_addr,
0368 ent_size -
0369 req_size);
0370
0371
0372
0373
0374
0375 cvmx_bootmem_phy_set_next(ent_addr,
0376 new_ent_addr);
0377 }
0378
0379
0380
0381
0382
0383 if (prev_addr)
0384 cvmx_bootmem_phy_set_next(prev_addr,
0385 cvmx_bootmem_phy_get_next(ent_addr));
0386 else
0387
0388
0389
0390
0391 cvmx_bootmem_desc->head_addr =
0392 cvmx_bootmem_phy_get_next(ent_addr);
0393
0394 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0395 cvmx_bootmem_unlock();
0396 return desired_min_addr;
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409 new_ent_addr = desired_min_addr;
0410 cvmx_bootmem_phy_set_next(new_ent_addr,
0411 cvmx_bootmem_phy_get_next
0412 (ent_addr));
0413 cvmx_bootmem_phy_set_size(new_ent_addr,
0414 cvmx_bootmem_phy_get_size
0415 (ent_addr) -
0416 (desired_min_addr -
0417 ent_addr));
0418 cvmx_bootmem_phy_set_size(ent_addr,
0419 desired_min_addr - ent_addr);
0420 cvmx_bootmem_phy_set_next(ent_addr, new_ent_addr);
0421
0422 }
0423 error_out:
0424
0425 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0426 cvmx_bootmem_unlock();
0427 return -1;
0428 }
0429
0430 int __cvmx_bootmem_phy_free(uint64_t phy_addr, uint64_t size, uint32_t flags)
0431 {
0432 uint64_t cur_addr;
0433 uint64_t prev_addr = 0;
0434 int retval = 0;
0435
0436 #ifdef DEBUG
0437 cvmx_dprintf("__cvmx_bootmem_phy_free addr: 0x%llx, size: 0x%llx\n",
0438 (unsigned long long)phy_addr, (unsigned long long)size);
0439 #endif
0440 if (cvmx_bootmem_desc->major_version > 3) {
0441 cvmx_dprintf("ERROR: Incompatible bootmem descriptor "
0442 "version: %d.%d at addr: %p\n",
0443 (int)cvmx_bootmem_desc->major_version,
0444 (int)cvmx_bootmem_desc->minor_version,
0445 cvmx_bootmem_desc);
0446 return 0;
0447 }
0448
0449
0450 if (!size)
0451 return 0;
0452
0453 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0454 cvmx_bootmem_lock();
0455 cur_addr = cvmx_bootmem_desc->head_addr;
0456 if (cur_addr == 0 || phy_addr < cur_addr) {
0457
0458 if (cur_addr && phy_addr + size > cur_addr)
0459 goto bootmem_free_done;
0460 else if (phy_addr + size == cur_addr) {
0461
0462 cvmx_bootmem_phy_set_next(phy_addr,
0463 cvmx_bootmem_phy_get_next
0464 (cur_addr));
0465 cvmx_bootmem_phy_set_size(phy_addr,
0466 cvmx_bootmem_phy_get_size
0467 (cur_addr) + size);
0468 cvmx_bootmem_desc->head_addr = phy_addr;
0469
0470 } else {
0471
0472 cvmx_bootmem_phy_set_next(phy_addr, cur_addr);
0473 cvmx_bootmem_phy_set_size(phy_addr, size);
0474 cvmx_bootmem_desc->head_addr = phy_addr;
0475 }
0476 retval = 1;
0477 goto bootmem_free_done;
0478 }
0479
0480
0481 while (cur_addr && phy_addr > cur_addr) {
0482 prev_addr = cur_addr;
0483 cur_addr = cvmx_bootmem_phy_get_next(cur_addr);
0484 }
0485
0486 if (!cur_addr) {
0487
0488
0489
0490
0491
0492 if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) ==
0493 phy_addr) {
0494 cvmx_bootmem_phy_set_size(prev_addr,
0495 cvmx_bootmem_phy_get_size
0496 (prev_addr) + size);
0497 } else {
0498 cvmx_bootmem_phy_set_next(prev_addr, phy_addr);
0499 cvmx_bootmem_phy_set_size(phy_addr, size);
0500 cvmx_bootmem_phy_set_next(phy_addr, 0);
0501 }
0502 retval = 1;
0503 goto bootmem_free_done;
0504 } else {
0505
0506
0507
0508
0509 if (prev_addr + cvmx_bootmem_phy_get_size(prev_addr) ==
0510 phy_addr) {
0511
0512 cvmx_bootmem_phy_set_size(prev_addr,
0513 cvmx_bootmem_phy_get_size
0514 (prev_addr) + size);
0515 if (phy_addr + size == cur_addr) {
0516
0517 cvmx_bootmem_phy_set_size(prev_addr,
0518 cvmx_bootmem_phy_get_size(cur_addr) +
0519 cvmx_bootmem_phy_get_size(prev_addr));
0520 cvmx_bootmem_phy_set_next(prev_addr,
0521 cvmx_bootmem_phy_get_next(cur_addr));
0522 }
0523 retval = 1;
0524 goto bootmem_free_done;
0525 } else if (phy_addr + size == cur_addr) {
0526
0527 cvmx_bootmem_phy_set_size(phy_addr,
0528 cvmx_bootmem_phy_get_size
0529 (cur_addr) + size);
0530 cvmx_bootmem_phy_set_next(phy_addr,
0531 cvmx_bootmem_phy_get_next
0532 (cur_addr));
0533 cvmx_bootmem_phy_set_next(prev_addr, phy_addr);
0534 retval = 1;
0535 goto bootmem_free_done;
0536 }
0537
0538
0539 cvmx_bootmem_phy_set_size(phy_addr, size);
0540 cvmx_bootmem_phy_set_next(phy_addr, cur_addr);
0541 cvmx_bootmem_phy_set_next(prev_addr, phy_addr);
0542
0543 }
0544 retval = 1;
0545
0546 bootmem_free_done:
0547 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0548 cvmx_bootmem_unlock();
0549 return retval;
0550
0551 }
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566 static struct cvmx_bootmem_named_block_desc *
0567 cvmx_bootmem_phy_named_block_find(char *name, uint32_t flags)
0568 {
0569 unsigned int i;
0570 struct cvmx_bootmem_named_block_desc *named_block_array_ptr;
0571
0572 #ifdef DEBUG
0573 cvmx_dprintf("cvmx_bootmem_phy_named_block_find: %s\n", name);
0574 #endif
0575
0576
0577
0578
0579 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0580 cvmx_bootmem_lock();
0581
0582
0583 named_block_array_ptr = (struct cvmx_bootmem_named_block_desc *)
0584 cvmx_phys_to_ptr(cvmx_bootmem_desc->named_block_array_addr);
0585
0586 #ifdef DEBUG
0587 cvmx_dprintf
0588 ("cvmx_bootmem_phy_named_block_find: named_block_array_ptr: %p\n",
0589 named_block_array_ptr);
0590 #endif
0591 if (cvmx_bootmem_desc->major_version == 3) {
0592 for (i = 0;
0593 i < cvmx_bootmem_desc->named_block_num_blocks; i++) {
0594 if ((name && named_block_array_ptr[i].size
0595 && !strncmp(name, named_block_array_ptr[i].name,
0596 cvmx_bootmem_desc->named_block_name_len
0597 - 1))
0598 || (!name && !named_block_array_ptr[i].size)) {
0599 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0600 cvmx_bootmem_unlock();
0601
0602 return &(named_block_array_ptr[i]);
0603 }
0604 }
0605 } else {
0606 cvmx_dprintf("ERROR: Incompatible bootmem descriptor "
0607 "version: %d.%d at addr: %p\n",
0608 (int)cvmx_bootmem_desc->major_version,
0609 (int)cvmx_bootmem_desc->minor_version,
0610 cvmx_bootmem_desc);
0611 }
0612 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0613 cvmx_bootmem_unlock();
0614
0615 return NULL;
0616 }
0617
0618 void *cvmx_bootmem_alloc_named_range_once(uint64_t size, uint64_t min_addr,
0619 uint64_t max_addr, uint64_t align,
0620 char *name,
0621 void (*init) (void *))
0622 {
0623 int64_t addr;
0624 void *ptr;
0625 uint64_t named_block_desc_addr;
0626
0627 named_block_desc_addr = (uint64_t)
0628 cvmx_bootmem_phy_named_block_find(name,
0629 (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);
0630
0631 if (named_block_desc_addr) {
0632 addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_desc_addr,
0633 base_addr);
0634 return cvmx_phys_to_ptr(addr);
0635 }
0636
0637 addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr,
0638 align, name,
0639 (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);
0640
0641 if (addr < 0)
0642 return NULL;
0643 ptr = cvmx_phys_to_ptr(addr);
0644
0645 if (init)
0646 init(ptr);
0647 else
0648 memset(ptr, 0, size);
0649
0650 return ptr;
0651 }
0652 EXPORT_SYMBOL(cvmx_bootmem_alloc_named_range_once);
0653
0654 struct cvmx_bootmem_named_block_desc *cvmx_bootmem_find_named_block(char *name)
0655 {
0656 return cvmx_bootmem_phy_named_block_find(name, 0);
0657 }
0658 EXPORT_SYMBOL(cvmx_bootmem_find_named_block);
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669 static int cvmx_bootmem_phy_named_block_free(char *name, uint32_t flags)
0670 {
0671 struct cvmx_bootmem_named_block_desc *named_block_ptr;
0672
0673 if (cvmx_bootmem_desc->major_version != 3) {
0674 cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: "
0675 "%d.%d at addr: %p\n",
0676 (int)cvmx_bootmem_desc->major_version,
0677 (int)cvmx_bootmem_desc->minor_version,
0678 cvmx_bootmem_desc);
0679 return 0;
0680 }
0681 #ifdef DEBUG
0682 cvmx_dprintf("cvmx_bootmem_phy_named_block_free: %s\n", name);
0683 #endif
0684
0685
0686
0687
0688
0689 cvmx_bootmem_lock();
0690
0691 named_block_ptr =
0692 cvmx_bootmem_phy_named_block_find(name,
0693 CVMX_BOOTMEM_FLAG_NO_LOCKING);
0694 if (named_block_ptr) {
0695 #ifdef DEBUG
0696 cvmx_dprintf("cvmx_bootmem_phy_named_block_free: "
0697 "%s, base: 0x%llx, size: 0x%llx\n",
0698 name,
0699 (unsigned long long)named_block_ptr->base_addr,
0700 (unsigned long long)named_block_ptr->size);
0701 #endif
0702 __cvmx_bootmem_phy_free(named_block_ptr->base_addr,
0703 named_block_ptr->size,
0704 CVMX_BOOTMEM_FLAG_NO_LOCKING);
0705 named_block_ptr->size = 0;
0706
0707 }
0708
0709 cvmx_bootmem_unlock();
0710 return named_block_ptr != NULL;
0711 }
0712
0713 int cvmx_bootmem_free_named(char *name)
0714 {
0715 return cvmx_bootmem_phy_named_block_free(name, 0);
0716 }
0717
0718 int64_t cvmx_bootmem_phy_named_block_alloc(uint64_t size, uint64_t min_addr,
0719 uint64_t max_addr,
0720 uint64_t alignment,
0721 char *name,
0722 uint32_t flags)
0723 {
0724 int64_t addr_allocated;
0725 struct cvmx_bootmem_named_block_desc *named_block_desc_ptr;
0726
0727 #ifdef DEBUG
0728 cvmx_dprintf("cvmx_bootmem_phy_named_block_alloc: size: 0x%llx, min: "
0729 "0x%llx, max: 0x%llx, align: 0x%llx, name: %s\n",
0730 (unsigned long long)size,
0731 (unsigned long long)min_addr,
0732 (unsigned long long)max_addr,
0733 (unsigned long long)alignment,
0734 name);
0735 #endif
0736 if (cvmx_bootmem_desc->major_version != 3) {
0737 cvmx_dprintf("ERROR: Incompatible bootmem descriptor version: "
0738 "%d.%d at addr: %p\n",
0739 (int)cvmx_bootmem_desc->major_version,
0740 (int)cvmx_bootmem_desc->minor_version,
0741 cvmx_bootmem_desc);
0742 return -1;
0743 }
0744
0745
0746
0747
0748
0749 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0750 cvmx_spinlock_lock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
0751
0752
0753 named_block_desc_ptr =
0754 cvmx_bootmem_phy_named_block_find(NULL,
0755 flags | CVMX_BOOTMEM_FLAG_NO_LOCKING);
0756
0757
0758
0759
0760
0761 if (cvmx_bootmem_phy_named_block_find(name,
0762 flags | CVMX_BOOTMEM_FLAG_NO_LOCKING) || !named_block_desc_ptr) {
0763 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0764 cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
0765 return -1;
0766 }
0767
0768
0769
0770
0771
0772
0773
0774
0775 size = ALIGN(size, CVMX_BOOTMEM_ALIGNMENT_SIZE);
0776
0777 addr_allocated = cvmx_bootmem_phy_alloc(size, min_addr, max_addr,
0778 alignment,
0779 flags | CVMX_BOOTMEM_FLAG_NO_LOCKING);
0780 if (addr_allocated >= 0) {
0781 named_block_desc_ptr->base_addr = addr_allocated;
0782 named_block_desc_ptr->size = size;
0783 strncpy(named_block_desc_ptr->name, name,
0784 cvmx_bootmem_desc->named_block_name_len);
0785 named_block_desc_ptr->name[cvmx_bootmem_desc->named_block_name_len - 1] = 0;
0786 }
0787
0788 if (!(flags & CVMX_BOOTMEM_FLAG_NO_LOCKING))
0789 cvmx_spinlock_unlock((cvmx_spinlock_t *)&(cvmx_bootmem_desc->lock));
0790 return addr_allocated;
0791 }
0792
0793 struct cvmx_bootmem_desc *cvmx_bootmem_get_desc(void)
0794 {
0795 return cvmx_bootmem_desc;
0796 }