1#include <uacpi/types.h>
2#include <uacpi/internal/types.h>
3#include <uacpi/internal/stdlib.h>
4#include <uacpi/internal/shareable.h>
5#include <uacpi/internal/dynamic_array.h>
6#include <uacpi/internal/log.h>
7#include <uacpi/internal/namespace.h>
8#include <uacpi/kernel_api.h>
9
10const uacpi_char *uacpi_object_type_to_string(uacpi_object_type type)
11{
12 switch (type) {
13 case UACPI_OBJECT_UNINITIALIZED:
14 return "Uninitialized";
15 case UACPI_OBJECT_INTEGER:
16 return "Integer";
17 case UACPI_OBJECT_STRING:
18 return "String";
19 case UACPI_OBJECT_BUFFER:
20 return "Buffer";
21 case UACPI_OBJECT_PACKAGE:
22 return "Package";
23 case UACPI_OBJECT_FIELD_UNIT:
24 return "Field Unit";
25 case UACPI_OBJECT_DEVICE:
26 return "Device";
27 case UACPI_OBJECT_EVENT:
28 return "Event";
29 case UACPI_OBJECT_REFERENCE:
30 return "Reference";
31 case UACPI_OBJECT_BUFFER_INDEX:
32 return "Buffer Index";
33 case UACPI_OBJECT_METHOD:
34 return "Method";
35 case UACPI_OBJECT_MUTEX:
36 return "Mutex";
37 case UACPI_OBJECT_OPERATION_REGION:
38 return "Operation Region";
39 case UACPI_OBJECT_POWER_RESOURCE:
40 return "Power Resource";
41 case UACPI_OBJECT_PROCESSOR:
42 return "Processor";
43 case UACPI_OBJECT_THERMAL_ZONE:
44 return "Thermal Zone";
45 case UACPI_OBJECT_BUFFER_FIELD:
46 return "Buffer Field";
47 case UACPI_OBJECT_DEBUG:
48 return "Debug";
49 default:
50 return "<Invalid type>";
51 }
52}
53
54const uacpi_char *uacpi_address_space_to_string(
55 enum uacpi_address_space space
56)
57{
58 switch (space) {
59 case UACPI_ADDRESS_SPACE_SYSTEM_MEMORY:
60 return "SystemMemory";
61 case UACPI_ADDRESS_SPACE_SYSTEM_IO:
62 return "SystemIO";
63 case UACPI_ADDRESS_SPACE_PCI_CONFIG:
64 return "PCI_Config";
65 case UACPI_ADDRESS_SPACE_EMBEDDED_CONTROLLER:
66 return "EmbeddedControl";
67 case UACPI_ADDRESS_SPACE_SMBUS:
68 return "SMBus";
69 case UACPI_ADDRESS_SPACE_SYSTEM_CMOS:
70 return "SystemCMOS";
71 case UACPI_ADDRESS_SPACE_PCI_BAR_TARGET:
72 return "PciBarTarget";
73 case UACPI_ADDRESS_SPACE_IPMI:
74 return "IPMI";
75 case UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO:
76 return "GeneralPurposeIO";
77 case UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS:
78 return "GenericSerialBus";
79 case UACPI_ADDRESS_SPACE_PCC:
80 return "PCC";
81 case UACPI_ADDRESS_SPACE_PRM:
82 return "PRM";
83 case UACPI_ADDRESS_SPACE_FFIXEDHW:
84 return "FFixedHW";
85 case UACPI_ADDRESS_SPACE_TABLE_DATA:
86 return "TableData";
87 default:
88 return "<vendor specific>";
89 }
90}
91
92static uacpi_bool buffer_alloc(uacpi_object *obj, uacpi_size initial_size)
93{
94 uacpi_buffer *buf;
95
96 buf = uacpi_kernel_calloc(count: 1, size: sizeof(uacpi_buffer));
97 if (uacpi_unlikely(buf == UACPI_NULL))
98 return UACPI_FALSE;
99
100 uacpi_shareable_init(buf);
101
102 if (initial_size) {
103 buf->data = uacpi_kernel_alloc(size: initial_size);
104 if (uacpi_unlikely(buf->data == UACPI_NULL)) {
105 uacpi_free(buf, sizeof(*buf));
106 return UACPI_FALSE;
107 }
108
109 buf->size = initial_size;
110 }
111
112 obj->buffer = buf;
113 return UACPI_TRUE;
114}
115
116static uacpi_bool empty_buffer_or_string_alloc(uacpi_object *object)
117{
118 return buffer_alloc(obj: object, initial_size: 0);
119}
120
121uacpi_bool uacpi_package_fill(uacpi_package *pkg, uacpi_size num_elements)
122{
123 uacpi_size i;
124
125 pkg->objects = uacpi_kernel_calloc(count: num_elements, size: sizeof(uacpi_handle));
126 if (uacpi_unlikely(pkg->objects == UACPI_NULL))
127 return UACPI_FALSE;
128
129 pkg->count = num_elements;
130 for (i = 0; i < num_elements; ++i) {
131 pkg->objects[i] = uacpi_create_object(type: UACPI_OBJECT_UNINITIALIZED);
132
133 if (uacpi_unlikely(pkg->objects[i] == UACPI_NULL))
134 return UACPI_FALSE;
135 }
136
137 return UACPI_TRUE;
138}
139
140static uacpi_bool package_alloc(uacpi_object *obj, uacpi_size initial_size)
141{
142 uacpi_package *pkg;
143
144 pkg = uacpi_kernel_calloc(count: 1, size: sizeof(uacpi_package));
145 if (uacpi_unlikely(pkg == UACPI_NULL))
146 return UACPI_FALSE;
147
148 uacpi_shareable_init(pkg);
149
150 if (initial_size) {
151 if (uacpi_unlikely(!uacpi_package_fill(pkg, initial_size))) {
152 uacpi_free(pkg, sizeof(*pkg));
153 return UACPI_FALSE;
154 }
155 }
156
157 obj->package = pkg;
158 return UACPI_TRUE;
159}
160
161static uacpi_bool empty_package_alloc(uacpi_object *object)
162{
163 return package_alloc(obj: object, initial_size: 0);
164}
165
166uacpi_mutex *uacpi_create_mutex(void)
167{
168 uacpi_mutex *mutex;
169
170 mutex = uacpi_kernel_calloc(count: 1, size: sizeof(uacpi_mutex));
171 if (uacpi_unlikely(mutex == UACPI_NULL))
172 return UACPI_NULL;
173
174 mutex->owner = UACPI_THREAD_ID_NONE;
175
176 mutex->handle = uacpi_kernel_create_mutex();
177 if (mutex->handle == UACPI_NULL) {
178 uacpi_free(mutex, sizeof(*mutex));
179 return UACPI_NULL;
180 }
181
182 uacpi_shareable_init(mutex);
183 return mutex;
184}
185
186static uacpi_bool mutex_alloc(uacpi_object *obj)
187{
188 obj->mutex = uacpi_create_mutex();
189 return obj->mutex != UACPI_NULL;
190}
191
192static uacpi_bool event_alloc(uacpi_object *obj)
193{
194 uacpi_event *event;
195
196 event = uacpi_kernel_calloc(count: 1, size: sizeof(uacpi_event));
197 if (uacpi_unlikely(event == UACPI_NULL))
198 return UACPI_FALSE;
199
200 event->handle = uacpi_kernel_create_event();
201 if (event->handle == UACPI_NULL) {
202 uacpi_free(event, sizeof(*event));
203 return UACPI_FALSE;
204 }
205
206 uacpi_shareable_init(event);
207 obj->event = event;
208
209 return UACPI_TRUE;
210}
211
212static uacpi_bool method_alloc(uacpi_object *obj)
213{
214 uacpi_control_method *method;
215
216 method = uacpi_kernel_calloc(count: 1, size: sizeof(*method));
217 if (uacpi_unlikely(method == UACPI_NULL))
218 return UACPI_FALSE;
219
220 uacpi_shareable_init(method);
221 obj->method = method;
222
223 return UACPI_TRUE;
224}
225
226static uacpi_bool op_region_alloc(uacpi_object *obj)
227{
228 uacpi_operation_region *op_region;
229
230 op_region = uacpi_kernel_calloc(count: 1, size: sizeof(*op_region));
231 if (uacpi_unlikely(op_region == UACPI_NULL))
232 return UACPI_FALSE;
233
234 uacpi_shareable_init(op_region);
235 obj->op_region = op_region;
236
237 return UACPI_TRUE;
238}
239
240static uacpi_bool field_unit_alloc(uacpi_object *obj)
241{
242 uacpi_field_unit *field_unit;
243
244 field_unit = uacpi_kernel_calloc(count: 1, size: sizeof(*field_unit));
245 if (uacpi_unlikely(field_unit == UACPI_NULL))
246 return UACPI_FALSE;
247
248 uacpi_shareable_init(field_unit);
249 obj->field_unit = field_unit;
250
251 return UACPI_TRUE;
252}
253
254static uacpi_bool processor_alloc(uacpi_object *obj)
255{
256 uacpi_processor *processor;
257
258 processor = uacpi_kernel_calloc(count: 1, size: sizeof(*processor));
259 if (uacpi_unlikely(processor == UACPI_NULL))
260 return UACPI_FALSE;
261
262 uacpi_shareable_init(processor);
263 obj->processor = processor;
264
265 return UACPI_TRUE;
266}
267
268static uacpi_bool device_alloc(uacpi_object *obj)
269{
270 uacpi_device *device;
271
272 device = uacpi_kernel_calloc(count: 1, size: sizeof(*device));
273 if (uacpi_unlikely(device == UACPI_NULL))
274 return UACPI_FALSE;
275
276 uacpi_shareable_init(device);
277 obj->device = device;
278
279 return UACPI_TRUE;
280}
281
282static uacpi_bool thermal_zone_alloc(uacpi_object *obj)
283{
284 uacpi_thermal_zone *thermal_zone;
285
286 thermal_zone = uacpi_kernel_calloc(count: 1, size: sizeof(*thermal_zone));
287 if (uacpi_unlikely(thermal_zone == UACPI_NULL))
288 return UACPI_FALSE;
289
290 uacpi_shareable_init(thermal_zone);
291 obj->thermal_zone = thermal_zone;
292
293 return UACPI_TRUE;
294}
295
296typedef uacpi_bool (*object_ctor)(uacpi_object *obj);
297
298static object_ctor object_constructor_table[UACPI_OBJECT_MAX_TYPE_VALUE + 1] = {
299 [UACPI_OBJECT_STRING] = empty_buffer_or_string_alloc,
300 [UACPI_OBJECT_BUFFER] = empty_buffer_or_string_alloc,
301 [UACPI_OBJECT_PACKAGE] = empty_package_alloc,
302 [UACPI_OBJECT_FIELD_UNIT] = field_unit_alloc,
303 [UACPI_OBJECT_MUTEX] = mutex_alloc,
304 [UACPI_OBJECT_EVENT] = event_alloc,
305 [UACPI_OBJECT_OPERATION_REGION] = op_region_alloc,
306 [UACPI_OBJECT_METHOD] = method_alloc,
307 [UACPI_OBJECT_PROCESSOR] = processor_alloc,
308 [UACPI_OBJECT_DEVICE] = device_alloc,
309 [UACPI_OBJECT_THERMAL_ZONE] = thermal_zone_alloc,
310};
311
312uacpi_object *uacpi_create_object(uacpi_object_type type)
313{
314 uacpi_object *ret;
315 object_ctor ctor;
316
317 ret = uacpi_kernel_calloc(count: 1, size: sizeof(*ret));
318 if (uacpi_unlikely(ret == UACPI_NULL))
319 return ret;
320
321 uacpi_shareable_init(ret);
322 ret->type = type;
323
324 ctor = object_constructor_table[type];
325 if (ctor == UACPI_NULL)
326 return ret;
327
328 if (uacpi_unlikely(!ctor(ret))) {
329 uacpi_free(ret, sizeof(*ret));
330 return UACPI_NULL;
331 }
332
333 return ret;
334}
335
336static void free_buffer(uacpi_handle handle)
337{
338 uacpi_buffer *buf = handle;
339
340 if (buf->data != UACPI_NULL)
341 /*
342 * If buffer has a size of 0 but a valid data pointer it's probably an
343 * "empty" buffer allocated by the interpreter in make_null_buffer
344 * and its real size is actually 1.
345 */
346 uacpi_free(buf->data, UACPI_MAX(buf->size, 1));
347
348 uacpi_free(buf, sizeof(*buf));
349}
350
351DYNAMIC_ARRAY_WITH_INLINE_STORAGE(free_queue, uacpi_package*, 4)
352DYNAMIC_ARRAY_WITH_INLINE_STORAGE_IMPL(free_queue, uacpi_package*, static)
353
354static uacpi_bool free_queue_push(struct free_queue *queue, uacpi_package *pkg)
355{
356 uacpi_package **slot;
357
358 slot = free_queue_alloc(arr: queue);
359 if (uacpi_unlikely(slot == UACPI_NULL))
360 return UACPI_FALSE;
361
362 *slot = pkg;
363 return UACPI_TRUE;
364}
365
366static void free_object(uacpi_object *obj);
367
368// No references allowed here, only plain objects
369static void free_plain_no_recurse(uacpi_object *obj, struct free_queue *queue)
370{
371 switch (obj->type) {
372 case UACPI_OBJECT_PACKAGE:
373 if (uacpi_shareable_unref(obj->package) > 1)
374 break;
375
376 if (uacpi_unlikely(!free_queue_push(queue,
377 obj->package))) {
378 uacpi_warn(
379 "unable to free nested package @%p: not enough memory\n",
380 obj->package
381 );
382 }
383
384 // Don't call free_object here as that will recurse
385 uacpi_free(obj, sizeof(*obj));
386 break;
387 default:
388 /*
389 * This call is guaranteed to not recurse further as we handle
390 * recursive cases elsewhere explicitly.
391 */
392 free_object(obj);
393 }
394}
395
396static void unref_plain_no_recurse(uacpi_object *obj, struct free_queue *queue)
397{
398 if (uacpi_shareable_unref(obj) > 1)
399 return;
400
401 free_plain_no_recurse(obj, queue);
402}
403
404static void unref_chain_no_recurse(uacpi_object *obj, struct free_queue *queue)
405{
406 uacpi_object *next_obj = UACPI_NULL;
407
408 while (obj) {
409 if (obj->type == UACPI_OBJECT_REFERENCE)
410 next_obj = obj->inner_object;
411
412 if (uacpi_shareable_unref(obj) > 1)
413 goto do_next;
414
415 if (obj->type == UACPI_OBJECT_REFERENCE) {
416 uacpi_free(obj, sizeof(*obj));
417 } else {
418 free_plain_no_recurse(obj, queue);
419 }
420
421 do_next:
422 obj = next_obj;
423 next_obj = UACPI_NULL;
424 }
425}
426
427static void unref_object_no_recurse(uacpi_object *obj, struct free_queue *queue)
428{
429 if (obj->type == UACPI_OBJECT_REFERENCE) {
430 unref_chain_no_recurse(obj, queue);
431 return;
432 }
433
434 unref_plain_no_recurse(obj, queue);
435}
436
437static void free_package(uacpi_handle handle)
438{
439 struct free_queue queue = { 0 };
440 uacpi_package *pkg = handle;
441 uacpi_object *obj;
442 uacpi_size i;
443
444 free_queue_push(queue: &queue, pkg);
445
446 while (free_queue_size(arr: &queue) != 0) {
447 pkg = *free_queue_last(arr: &queue);
448 free_queue_pop(arr: &queue);
449
450 /*
451 * 1. Unref/free every object in the package. Note that this might add
452 * even more packages into the free queue.
453 */
454 for (i = 0; i < pkg->count; ++i) {
455 obj = pkg->objects[i];
456 unref_object_no_recurse(obj, queue: &queue);
457 }
458
459 // 2. Release the object array
460 uacpi_free(pkg->objects, sizeof(*pkg->objects) * pkg->count);
461
462 // 3. Release the package itself
463 uacpi_free(pkg, sizeof(*pkg));
464 }
465
466 free_queue_clear(arr: &queue);
467}
468
469static void free_mutex(uacpi_handle handle)
470{
471 uacpi_mutex *mutex = handle;
472
473 uacpi_kernel_free_mutex(mutex->handle);
474 uacpi_free(mutex, sizeof(*mutex));
475}
476
477void uacpi_mutex_unref(uacpi_mutex *mutex)
478{
479 if (mutex == UACPI_NULL)
480 return;
481
482 uacpi_shareable_unref_and_delete_if_last(mutex, do_free: free_mutex);
483}
484
485static void free_event(uacpi_handle handle)
486{
487 uacpi_event *event = handle;
488
489 uacpi_kernel_free_event(event->handle);
490 uacpi_free(event, sizeof(*event));
491}
492
493static void free_address_space_handler(uacpi_handle handle)
494{
495 uacpi_address_space_handler *handler = handle;
496 uacpi_free(handler, sizeof(*handler));
497}
498
499static void free_address_space_handlers(
500 uacpi_address_space_handler *handler
501)
502{
503 uacpi_address_space_handler *next_handler;
504
505 while (handler) {
506 next_handler = handler->next;
507 uacpi_shareable_unref_and_delete_if_last(
508 handler, do_free: free_address_space_handler
509 );
510 handler = next_handler;
511 }
512}
513
514static void free_device_notify_handlers(uacpi_device_notify_handler *handler)
515{
516 uacpi_device_notify_handler *next_handler;
517
518 while (handler) {
519 next_handler = handler->next;
520 uacpi_free(handler, sizeof(*handler));
521 handler = next_handler;
522 }
523}
524
525static void free_handlers(uacpi_handle handle)
526{
527 uacpi_handlers *handlers = handle;
528
529 free_address_space_handlers(handler: handlers->address_space_head);
530 free_device_notify_handlers(handler: handlers->notify_head);
531}
532
533void uacpi_address_space_handler_unref(uacpi_address_space_handler *handler)
534{
535 uacpi_shareable_unref_and_delete_if_last(
536 handler, do_free: free_address_space_handler
537 );
538}
539
540static void free_op_region(uacpi_handle handle)
541{
542 uacpi_operation_region *op_region = handle;
543
544 if (uacpi_unlikely(op_region->handler != UACPI_NULL)) {
545 uacpi_warn(
546 "BUG: attempting to free an opregion@%p with a handler attached\n",
547 op_region
548 );
549 }
550
551 uacpi_free(op_region, sizeof(*op_region));
552}
553
554static void free_device(uacpi_handle handle)
555{
556 uacpi_device *device = handle;
557 free_handlers(handle: device);
558 uacpi_free(device, sizeof(*device));
559}
560
561static void free_processor(uacpi_handle handle)
562{
563 uacpi_processor *processor = handle;
564 free_handlers(handle: processor);
565 uacpi_free(processor, sizeof(*processor));
566}
567
568static void free_thermal_zone(uacpi_handle handle)
569{
570 uacpi_thermal_zone *thermal_zone = handle;
571 free_handlers(handle: thermal_zone);
572 uacpi_free(thermal_zone, sizeof(*thermal_zone));
573}
574
575static void free_field_unit(uacpi_handle handle)
576{
577 uacpi_field_unit *field_unit = handle;
578
579 switch (field_unit->kind) {
580 case UACPI_FIELD_UNIT_KIND_NORMAL:
581 uacpi_namespace_node_unref(node: field_unit->region);
582 break;
583 case UACPI_FIELD_UNIT_KIND_BANK:
584 uacpi_namespace_node_unref(node: field_unit->bank_region);
585 uacpi_shareable_unref_and_delete_if_last(
586 field_unit->bank_selection, do_free: free_field_unit
587 );
588 break;
589 case UACPI_FIELD_UNIT_KIND_INDEX:
590 uacpi_shareable_unref_and_delete_if_last(
591 field_unit->index, do_free: free_field_unit
592 );
593 uacpi_shareable_unref_and_delete_if_last(
594 field_unit->data, do_free: free_field_unit
595 );
596 break;
597 default:
598 break;
599 }
600
601 uacpi_free(field_unit, sizeof(*field_unit));
602}
603
604static void free_method(uacpi_handle handle)
605{
606 uacpi_control_method *method = handle;
607
608 uacpi_shareable_unref_and_delete_if_last(
609 method->mutex, do_free: free_mutex
610 );
611
612 uacpi_free(method, sizeof(*method));
613}
614
615static void free_object_storage(uacpi_object *obj)
616{
617 switch (obj->type) {
618 case UACPI_OBJECT_STRING:
619 case UACPI_OBJECT_BUFFER:
620 uacpi_shareable_unref_and_delete_if_last(obj->buffer, do_free: free_buffer);
621 break;
622 case UACPI_OBJECT_BUFFER_FIELD:
623 uacpi_shareable_unref_and_delete_if_last(obj->buffer_field.backing,
624 do_free: free_buffer);
625 break;
626 case UACPI_OBJECT_BUFFER_INDEX:
627 uacpi_shareable_unref_and_delete_if_last(obj->buffer_index.buffer,
628 do_free: free_buffer);
629 break;
630 case UACPI_OBJECT_METHOD:
631 uacpi_shareable_unref_and_delete_if_last(obj->method,
632 do_free: free_method);
633 break;
634 case UACPI_OBJECT_PACKAGE:
635 uacpi_shareable_unref_and_delete_if_last(obj->package,
636 do_free: free_package);
637 break;
638 case UACPI_OBJECT_FIELD_UNIT:
639 uacpi_shareable_unref_and_delete_if_last(obj->field_unit,
640 do_free: free_field_unit);
641 break;
642 case UACPI_OBJECT_MUTEX:
643 uacpi_mutex_unref(mutex: obj->mutex);
644 break;
645 case UACPI_OBJECT_EVENT:
646 uacpi_shareable_unref_and_delete_if_last(obj->event,
647 do_free: free_event);
648 break;
649 case UACPI_OBJECT_OPERATION_REGION:
650 uacpi_shareable_unref_and_delete_if_last(obj->op_region,
651 do_free: free_op_region);
652 break;
653 case UACPI_OBJECT_PROCESSOR:
654 uacpi_shareable_unref_and_delete_if_last(obj->processor,
655 do_free: free_processor);
656 break;
657 case UACPI_OBJECT_DEVICE:
658 uacpi_shareable_unref_and_delete_if_last(obj->device,
659 do_free: free_device);
660 break;
661 case UACPI_OBJECT_THERMAL_ZONE:
662 uacpi_shareable_unref_and_delete_if_last(obj->thermal_zone,
663 do_free: free_thermal_zone);
664 break;
665 default:
666 break;
667 }
668}
669
670static void free_object(uacpi_object *obj)
671{
672 free_object_storage(obj);
673 uacpi_free(obj, sizeof(*obj));
674}
675
676static void make_chain_bugged(uacpi_object *obj)
677{
678 uacpi_warn("object refcount bug, marking chain @%p as bugged\n", obj);
679
680 while (obj) {
681 uacpi_make_shareable_bugged(obj);
682
683 if (obj->type == UACPI_OBJECT_REFERENCE)
684 obj = obj->inner_object;
685 else
686 obj = UACPI_NULL;
687 }
688}
689
690void uacpi_object_ref(uacpi_object *obj)
691{
692 uacpi_object *this_obj = obj;
693
694 while (obj) {
695 if (uacpi_unlikely(uacpi_bugged_shareable(obj))) {
696 make_chain_bugged(obj: this_obj);
697 return;
698 }
699
700 uacpi_shareable_ref(obj);
701
702 if (obj->type == UACPI_OBJECT_REFERENCE)
703 obj = obj->inner_object;
704 else
705 obj = UACPI_NULL;
706 }
707}
708
709static void free_chain(uacpi_object *obj)
710{
711 uacpi_object *next_obj = UACPI_NULL;
712
713 while (obj) {
714 if (obj->type == UACPI_OBJECT_REFERENCE)
715 next_obj = obj->inner_object;
716
717 if (uacpi_shareable_refcount(obj) == 0)
718 free_object(obj);
719
720 obj = next_obj;
721 next_obj = UACPI_NULL;
722 }
723}
724
725void uacpi_object_unref(uacpi_object *obj)
726{
727 uacpi_object *this_obj = obj;
728 uacpi_u32 parent_refcount;
729
730 if (!obj)
731 return;
732
733 parent_refcount = obj->shareable.reference_count;
734
735 while (obj) {
736 if (uacpi_unlikely(uacpi_bugged_shareable(obj))) {
737 make_chain_bugged(obj: this_obj);
738 return;
739 }
740
741 if (uacpi_unlikely(uacpi_shareable_refcount(obj) < parent_refcount)) {
742 make_chain_bugged(obj: this_obj);
743 return;
744 }
745
746 parent_refcount = uacpi_shareable_unref(obj);
747
748 if (obj->type == UACPI_OBJECT_REFERENCE) {
749 obj = obj->inner_object;
750 } else {
751 obj = UACPI_NULL;
752 }
753 }
754
755 if (uacpi_shareable_refcount(this_obj) == 0)
756 free_chain(obj: this_obj);
757}
758
759static uacpi_status buffer_alloc_and_store(
760 uacpi_object *obj, uacpi_size buf_size,
761 const void *src, uacpi_size src_size
762)
763{
764 if (uacpi_unlikely(!buffer_alloc(obj, buf_size)))
765 return UACPI_STATUS_OUT_OF_MEMORY;
766
767 uacpi_memcpy_zerout(dst: obj->buffer->data, src, dst_size: buf_size, src_size);
768 return UACPI_STATUS_OK;
769}
770
771static uacpi_status assign_buffer(uacpi_object *dst, uacpi_object *src,
772 enum uacpi_assign_behavior behavior)
773{
774 if (behavior == UACPI_ASSIGN_BEHAVIOR_SHALLOW_COPY) {
775 dst->buffer = src->buffer;
776 uacpi_shareable_ref(dst->buffer);
777 return UACPI_STATUS_OK;
778 }
779
780 return buffer_alloc_and_store(obj: dst, buf_size: src->buffer->size,
781 src: src->buffer->data, src_size: src->buffer->size);
782}
783
784struct pkg_copy_req {
785 uacpi_object *dst;
786 uacpi_package *src;
787};
788
789DYNAMIC_ARRAY_WITH_INLINE_STORAGE(pkg_copy_reqs, struct pkg_copy_req, 2)
790DYNAMIC_ARRAY_WITH_INLINE_STORAGE_IMPL(
791 pkg_copy_reqs, struct pkg_copy_req, static
792)
793
794static uacpi_bool pkg_copy_reqs_push(
795 struct pkg_copy_reqs *reqs,
796 uacpi_object *dst, uacpi_package *pkg
797)
798{
799 struct pkg_copy_req *req;
800
801 req = pkg_copy_reqs_alloc(arr: reqs);
802 if (uacpi_unlikely(req == UACPI_NULL))
803 return UACPI_FALSE;
804
805 req->dst = dst;
806 req->src = pkg;
807
808 return UACPI_TRUE;
809}
810
811static uacpi_status deep_copy_package_no_recurse(
812 uacpi_object *dst, uacpi_package *src,
813 struct pkg_copy_reqs *reqs
814)
815{
816 uacpi_size i;
817 uacpi_package *dst_package;
818
819 if (uacpi_unlikely(!package_alloc(dst, src->count)))
820 return UACPI_STATUS_OUT_OF_MEMORY;
821
822 dst->type = UACPI_OBJECT_PACKAGE;
823 dst_package = dst->package;
824
825 for (i = 0; i < src->count; ++i) {
826 uacpi_status st;
827 uacpi_object *src_obj = src->objects[i];
828 uacpi_object *dst_obj = dst_package->objects[i];
829
830 // Don't copy the internal package index reference
831 if (src_obj->type == UACPI_OBJECT_REFERENCE &&
832 src_obj->flags == UACPI_REFERENCE_KIND_PKG_INDEX)
833 src_obj = src_obj->inner_object;
834
835 if (src_obj->type == UACPI_OBJECT_PACKAGE) {
836 uacpi_bool ret;
837
838 ret = pkg_copy_reqs_push(reqs, dst: dst_obj, pkg: src_obj->package);
839 if (uacpi_unlikely(!ret))
840 return UACPI_STATUS_OUT_OF_MEMORY;
841
842 continue;
843 }
844
845 st = uacpi_object_assign(dst: dst_obj, src: src_obj,
846 UACPI_ASSIGN_BEHAVIOR_DEEP_COPY);
847 if (uacpi_unlikely_error(st))
848 return st;
849 }
850
851 return UACPI_STATUS_OK;
852}
853
854static uacpi_status deep_copy_package(uacpi_object *dst, uacpi_object *src)
855{
856 uacpi_status ret = UACPI_STATUS_OK;
857 struct pkg_copy_reqs reqs = { 0 };
858
859 pkg_copy_reqs_push(reqs: &reqs, dst, pkg: src->package);
860
861 while (pkg_copy_reqs_size(arr: &reqs) != 0) {
862 struct pkg_copy_req req;
863
864 req = *pkg_copy_reqs_last(arr: &reqs);
865 pkg_copy_reqs_pop(arr: &reqs);
866
867 ret = deep_copy_package_no_recurse(dst: req.dst, src: req.src, reqs: &reqs);
868 if (uacpi_unlikely_error(ret))
869 break;
870 }
871
872 pkg_copy_reqs_clear(arr: &reqs);
873 return ret;
874}
875
876static uacpi_status assign_mutex(uacpi_object *dst, uacpi_object *src,
877 enum uacpi_assign_behavior behavior)
878{
879 if (behavior == UACPI_ASSIGN_BEHAVIOR_DEEP_COPY) {
880 if (uacpi_likely(mutex_alloc(dst))) {
881 dst->mutex->sync_level = src->mutex->sync_level;
882 return UACPI_STATUS_OK;
883 }
884
885 return UACPI_STATUS_OUT_OF_MEMORY;
886 }
887
888 dst->mutex = src->mutex;
889 uacpi_shareable_ref(dst->mutex);
890
891 return UACPI_STATUS_OK;
892}
893
894static uacpi_status assign_event(uacpi_object *dst, uacpi_object *src,
895 enum uacpi_assign_behavior behavior)
896{
897 if (behavior == UACPI_ASSIGN_BEHAVIOR_DEEP_COPY) {
898 if (uacpi_likely(event_alloc(dst)))
899 return UACPI_STATUS_OK;
900
901 return UACPI_STATUS_OUT_OF_MEMORY;
902 }
903
904 dst->event = src->event;
905 uacpi_shareable_ref(dst->event);
906
907 return UACPI_STATUS_OK;
908}
909
910static uacpi_status assign_package(uacpi_object *dst, uacpi_object *src,
911 enum uacpi_assign_behavior behavior)
912{
913 if (behavior == UACPI_ASSIGN_BEHAVIOR_SHALLOW_COPY) {
914 dst->package = src->package;
915 uacpi_shareable_ref(dst->package);
916 return UACPI_STATUS_OK;
917 }
918
919 return deep_copy_package(dst, src);
920}
921
922void uacpi_object_attach_child(uacpi_object *parent, uacpi_object *child)
923{
924 uacpi_u32 refs_to_add;
925
926 parent->inner_object = child;
927
928 if (uacpi_unlikely(uacpi_bugged_shareable(parent))) {
929 make_chain_bugged(obj: child);
930 return;
931 }
932
933 refs_to_add = uacpi_shareable_refcount(parent);
934 while (refs_to_add--)
935 uacpi_object_ref(obj: child);
936}
937
938void uacpi_object_detach_child(uacpi_object *parent)
939{
940 uacpi_u32 refs_to_remove;
941 uacpi_object *child;
942
943 child = parent->inner_object;
944 parent->inner_object = UACPI_NULL;
945
946 if (uacpi_unlikely(uacpi_bugged_shareable(parent)))
947 return;
948
949 refs_to_remove = uacpi_shareable_refcount(parent);
950 while (refs_to_remove--)
951 uacpi_object_unref(obj: child);
952}
953
954uacpi_status uacpi_object_assign(uacpi_object *dst, uacpi_object *src,
955 enum uacpi_assign_behavior behavior)
956{
957 uacpi_status ret = UACPI_STATUS_OK;
958
959 if (src == dst)
960 return ret;
961
962 switch (dst->type) {
963 case UACPI_OBJECT_REFERENCE:
964 uacpi_object_detach_child(parent: dst);
965 break;
966 case UACPI_OBJECT_STRING:
967 case UACPI_OBJECT_BUFFER:
968 case UACPI_OBJECT_METHOD:
969 case UACPI_OBJECT_PACKAGE:
970 case UACPI_OBJECT_MUTEX:
971 case UACPI_OBJECT_EVENT:
972 case UACPI_OBJECT_PROCESSOR:
973 case UACPI_OBJECT_DEVICE:
974 case UACPI_OBJECT_THERMAL_ZONE:
975 free_object_storage(obj: dst);
976 break;
977 default:
978 break;
979 }
980
981 switch (src->type) {
982 case UACPI_OBJECT_UNINITIALIZED:
983 case UACPI_OBJECT_DEBUG:
984 break;
985 case UACPI_OBJECT_BUFFER:
986 case UACPI_OBJECT_STRING:
987 dst->flags = src->flags;
988 ret = assign_buffer(dst, src, behavior);
989 break;
990 case UACPI_OBJECT_BUFFER_FIELD:
991 dst->buffer_field = src->buffer_field;
992 uacpi_shareable_ref(dst->buffer_field.backing);
993 break;
994 case UACPI_OBJECT_BUFFER_INDEX:
995 dst->buffer_index = src->buffer_index;
996 uacpi_shareable_ref(dst->buffer_index.buffer);
997 break;
998 case UACPI_OBJECT_INTEGER:
999 dst->integer = src->integer;
1000 break;
1001 case UACPI_OBJECT_METHOD:
1002 dst->method = src->method;
1003 uacpi_shareable_ref(dst->method);
1004 break;
1005 case UACPI_OBJECT_MUTEX:
1006 ret = assign_mutex(dst, src, behavior);
1007 break;
1008 case UACPI_OBJECT_EVENT:
1009 ret = assign_event(dst, src, behavior);
1010 break;
1011 case UACPI_OBJECT_OPERATION_REGION:
1012 dst->op_region = src->op_region;
1013 uacpi_shareable_ref(dst->op_region);
1014 break;
1015 case UACPI_OBJECT_PACKAGE:
1016 ret = assign_package(dst, src, behavior);
1017 break;
1018 case UACPI_OBJECT_FIELD_UNIT:
1019 dst->field_unit = src->field_unit;
1020 uacpi_shareable_ref(dst->field_unit);
1021 break;
1022 case UACPI_OBJECT_REFERENCE:
1023 uacpi_object_attach_child(parent: dst, child: src->inner_object);
1024 break;
1025 case UACPI_OBJECT_PROCESSOR:
1026 dst->processor = src->processor;
1027 uacpi_shareable_ref(dst->processor);
1028 break;
1029 case UACPI_OBJECT_DEVICE:
1030 dst->device = src->device;
1031 uacpi_shareable_ref(dst->device);
1032 break;
1033 case UACPI_OBJECT_THERMAL_ZONE:
1034 dst->thermal_zone = src->thermal_zone;
1035 uacpi_shareable_ref(dst->thermal_zone);
1036 break;
1037 default:
1038 ret = UACPI_STATUS_UNIMPLEMENTED;
1039 }
1040
1041 if (ret == UACPI_STATUS_OK)
1042 dst->type = src->type;
1043
1044 return ret;
1045}
1046
1047struct uacpi_object *uacpi_create_internal_reference(
1048 enum uacpi_reference_kind kind, uacpi_object *child
1049)
1050{
1051 uacpi_object *ret;
1052
1053 ret = uacpi_create_object(type: UACPI_OBJECT_REFERENCE);
1054 if (uacpi_unlikely(ret == UACPI_NULL))
1055 return ret;
1056
1057 ret->flags = kind;
1058 uacpi_object_attach_child(parent: ret, child);
1059 return ret;
1060}
1061
1062uacpi_object *uacpi_unwrap_internal_reference(uacpi_object *object)
1063{
1064 for (;;) {
1065 if (object->type != UACPI_OBJECT_REFERENCE ||
1066 (object->flags == UACPI_REFERENCE_KIND_REFOF ||
1067 object->flags == UACPI_REFERENCE_KIND_PKG_INDEX))
1068 return object;
1069
1070 object = object->inner_object;
1071 }
1072}
1073