]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/io/server/src/acpi.cc
update
[l4.git] / l4 / pkg / io / server / src / acpi.cc
1 /*
2  * (c) 2011 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *          Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10
11 #include <cstdio>
12 #include <cstdlib>
13
14 #include "debug.h"
15 #include "pci.h"
16 #include "acpi_l4.h"
17 #include "__acpi.h"
18 #include "cfg.h"
19 #include "main.h"
20 #include "phys_space.h"
21
22 extern "C" {
23 #include "acpi.h"
24 #include "accommon.h"
25 #include "acresrc.h"
26 #include "acnamesp.h"
27 }
28
29 #include <errno.h>
30 #include <l4/cxx/list>
31
32 #define _COMPONENT              ACPI_BUS_COMPONENT
33 ACPI_MODULE_NAME("l4main");
34
35 namespace {
36
37 struct Prt_entry : public cxx::List_item
38 {
39   unsigned slot;
40   unsigned char pin;
41   acpica_pci_irq irq;
42 };
43
44 class Acpi_pci_irq_router_rs : public Resource_space
45 {
46 public:
47   Prt_entry *_prt;
48
49 public:
50   Acpi_pci_irq_router_rs() : _prt(0) {}
51
52   int add_prt_entry(ACPI_HANDLE obj, ACPI_PCI_ROUTING_TABLE *e);
53   int find(int device, int pin, struct acpica_pci_irq **irq);
54   bool request(Resource *parent, Device *, Resource *child, Device *cdev);
55   bool alloc(Resource *, Device *, Resource *, Device *, bool)
56   { return false; }
57 };
58
59
60 bool
61 Acpi_pci_irq_router_rs::request(Resource *parent, Device *,
62                                 Resource *child, Device *cdev)
63 {
64   if (dlevel(DBG_ALL))
65     {
66       printf("requesting IRQ resource: ");
67       cdev->dump(2);
68       child->dump(2);
69       printf(" at ACPI IRQ routing resource\n");
70     }
71
72   Adr_resource *cr = dynamic_cast<Adr_resource*>(child);
73
74   if (!cr)
75     {
76       child->parent(parent);
77       return true;
78     }
79
80   Hw::Device *cd = dynamic_cast<Hw::Device*>(cdev);
81
82   if (!cd)
83     return false;
84
85   struct acpica_pci_irq *irq = 0;
86
87   if (find(cd->adr() >> 16, cr->start(), &irq) < 0)
88     return false;
89
90   if (!irq)
91     return false;
92
93   cr->del_flags(Resource::F_relative);
94   cr->start(irq->irq);
95   cr->del_flags(Resource::Irq_info_base * 3);
96   unsigned flags = 0;
97   flags |= (!irq->trigger) * Resource::Irq_info_base;
98   flags |= (!!irq->polarity) * Resource::Irq_info_base * 2;
99   cr->add_flags(flags);
100
101   cr->parent(parent);
102
103   return true;
104 }
105
106 enum Acpi_irq_model_id {
107         ACPI_IRQ_MODEL_PIC = 0,
108         ACPI_IRQ_MODEL_IOAPIC,
109         ACPI_IRQ_MODEL_IOSAPIC,
110         ACPI_IRQ_MODEL_PLATFORM,
111         ACPI_IRQ_MODEL_COUNT
112 };
113
114 static ACPI_STATUS
115 get_irq_cb(ACPI_RESOURCE *res, void *ctxt)
116 {
117   acpica_pci_irq *irq = (acpica_pci_irq*)ctxt;
118   if (!res)
119     return AE_OK;
120
121   switch (res->Type)
122     {
123     case ACPI_RESOURCE_TYPE_IRQ:
124       irq->irq = res->Data.Irq.Interrupts[0];
125       irq->polarity = res->Data.Irq.Polarity;
126       irq->trigger  = res->Data.Irq.Triggering;
127       return AE_OK;
128
129     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
130       irq->irq = res->Data.ExtendedIrq.Interrupts[0];
131       irq->polarity = res->Data.ExtendedIrq.Polarity;
132       irq->trigger  = res->Data.ExtendedIrq.Triggering;
133       return AE_OK;
134
135     default:
136       return AE_OK;
137     }
138 }
139
140 int
141 Acpi_pci_irq_router_rs::add_prt_entry(ACPI_HANDLE obj,
142                                       ACPI_PCI_ROUTING_TABLE *e)
143 {
144   if (!e)
145     return -EINVAL;
146
147   Prt_entry *ne = new Prt_entry();
148   if (!ne)
149     return -ENOMEM;
150
151   ne->slot = (e->Address >> 16) & 0xffff;
152   ne->pin = e->Pin;
153
154   ne->irq.irq = e->SourceIndex;
155   ne->irq.polarity = ACPI_ACTIVE_LOW;
156   ne->irq.trigger = ACPI_LEVEL_SENSITIVE;
157   if (e->Source[0])
158     {
159       ACPI_HANDLE link;
160       d_printf(DBG_DEBUG, " (dev[%s][%d]) ", e->Source, e->SourceIndex);
161       ACPI_STATUS status;
162       status = AcpiGetHandle(obj, e->Source, &link);
163       if (ACPI_FAILURE(status))
164         {
165           d_printf(DBG_WARN, "\nWARNING: Could not find PCI IRQ Link Device...\n");
166           return -ENODEV;
167         }
168
169       status = AcpiWalkResources(link, (char*)"_CRS", get_irq_cb, &ne->irq);
170       if (ACPI_FAILURE(status))
171         {
172           d_printf(DBG_WARN, "\nWARNING: Could not evaluate _CRS of PCI IRQ Link Device\n");
173           return -ENODEV;
174         }
175     }
176
177   _prt = cxx::List_item::push_back(_prt, ne);
178   return 0;
179 }
180
181 int
182 Acpi_pci_irq_router_rs::find(int device, int pin, struct acpica_pci_irq **irq)
183 {
184   Prt_entry::T_iter<Prt_entry> c = _prt;
185   while (*c)
186     {
187       if (c->slot == (unsigned)device && c->pin == pin)
188         {
189           *irq = &c->irq;
190           return 0;
191         }
192
193       ++c;
194     }
195
196   return -ENODEV;
197 }
198
199
200 static int acpi_bus_init_irq(void)
201 {
202   ACPI_STATUS status = AE_OK;
203   ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
204   ACPI_OBJECT_LIST arg_list = { 1, &arg };
205   char const *message = NULL;
206
207
208   //int acpi_irq_model = ACPI_IRQ_MODEL_PIC;
209   int acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
210   /*
211    * Let the system know what interrupt model we are using by
212    * evaluating the \_PIC object, if exists.
213    */
214
215   switch (acpi_irq_model) {
216     case ACPI_IRQ_MODEL_PIC:
217       message = "PIC";
218       break;
219     case ACPI_IRQ_MODEL_IOAPIC:
220       message = "IOAPIC";
221       break;
222     case ACPI_IRQ_MODEL_IOSAPIC:
223       message = "IOSAPIC";
224       break;
225     case ACPI_IRQ_MODEL_PLATFORM:
226       message = "platform specific model";
227       break;
228     default:
229       d_printf(DBG_ERR, "ERROR: Unknown interrupt routing model\n");
230       return -1;
231   }
232
233   d_printf(DBG_INFO, "Using %s for interrupt routing\n", message);
234
235   arg.Integer.Value = acpi_irq_model;
236
237   status = AcpiEvaluateObject(NULL, (char*)"\\_PIC", &arg_list, NULL);
238   if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
239       ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
240       return -1;
241   }
242
243   return 0;
244 }
245
246
247 struct Discover_ctxt
248 {
249   Hw::Device *last_device;
250   Hw::Device *current_bus;
251   unsigned level;
252 };
253
254 class Acpi_res_discover : public Hw::Discover_res_if
255 {
256 public:
257   Acpi_res_discover(ACPI_HANDLE obj) : obj(obj) {}
258
259   void discover_resources(Hw::Device *host);
260   void setup_resources(Hw::Device *) {}
261
262 private:
263   void discover_prt(Hw::Device *host);
264   void discover_crs(Hw::Device *host);
265
266   ACPI_HANDLE obj;
267 };
268
269 void
270 Acpi_res_discover::discover_prt(Hw::Device *host)
271 {
272   ACPI_BUFFER buf;
273   ACPI_STATUS status;
274   ACPI_HANDLE handle;
275
276   status = AcpiGetHandle(obj, (char*)"_PRT", &handle);
277
278   // no PRT!!
279   if (ACPI_FAILURE(status))
280     {
281       Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
282       host->add_resource(r);
283       return;
284     }
285
286 #if 0
287   ret_buf.Length = sizeof (buffer);
288   ret_buf.Pointer = buffer;
289
290   status = AcpiGetName (obj, ACPI_FULL_PATHNAME, &ret_buf);
291
292   if (ACPI_FAILURE (status))
293     AcpiOsPrintf ("Could not convert name to pathname\n");
294   else
295     AcpiOsPrintf ("ACPI: PCI IRQ routing [%s._PRT]\n", buffer);
296 #endif
297
298   buf.Length = ACPI_ALLOCATE_BUFFER;
299
300   status = AcpiGetIrqRoutingTable(obj, &buf);
301
302   if (ACPI_FAILURE(status))
303     {
304       d_printf(DBG_ERR, "ERROR: while getting PRT for [%s]\n", "buffer");
305       Resource *r = new Pci_irq_router_res<Pci_pci_bridge_irq_router_rs>();
306       host->add_resource(r);
307       return;
308     }
309
310   typedef Pci_irq_router_res<Acpi_pci_irq_router_rs> Irq_res;
311   Irq_res *r = new Irq_res();
312
313   char *p = (char*)buf.Pointer;
314   char *e = (char*)buf.Pointer + buf.Length;
315   while (1)
316     {
317       ACPI_PCI_ROUTING_TABLE *prt = (ACPI_PCI_ROUTING_TABLE *)p;
318       if (prt->Length == 0)
319         break;
320
321       if (p + prt->Length > e)
322         break;
323
324       int err = r->provided()->add_prt_entry(obj, prt);
325       if (err < 0)
326         return;
327
328       p += prt->Length;
329     }
330
331   host->add_resource(r);
332 }
333
334 static unsigned acpi_adr_t_to_f(unsigned art)
335 {
336   switch (art)
337     {
338     case ACPI_MEMORY_RANGE: return Resource::Mmio_res;
339     case ACPI_IO_RANGE: return Resource::Io_res;
340     case ACPI_BUS_NUMBER_RANGE: return Resource::Bus_res;
341     default: return ~0;
342     }
343 }
344
345 static void
346 acpi_adr_res(Hw::Device *host, ACPI_RESOURCE_ADDRESS const *ar, l4_uint64_t s, l4_uint64_t l,
347              bool qw)
348 {
349   unsigned flags = acpi_adr_t_to_f(ar->ResourceType)
350                    | Resource::F_fixed_size | Resource::F_fixed_addr;
351
352   if (flags == ~0U)
353     return;
354
355   if (qw)
356     flags |= Resource::F_width_64bit;
357
358   Resource *r;
359   if (ar->ProducerConsumer == ACPI_PRODUCER)
360     r = new Adr_resource_provider(flags, s, s + l - 1);
361   else
362     r = new Adr_resource(flags, s, s + l -1);
363
364   host->add_resource(r);
365 }
366
367 void
368 Acpi_res_discover::discover_crs(Hw::Device *host)
369 {
370   ACPI_BUFFER buf;
371   buf.Length = ACPI_ALLOCATE_BUFFER;
372
373   if (ACPI_FAILURE(AcpiGetCurrentResources(obj, &buf)))
374     return;
375
376   char const *p = (char const *)buf.Pointer;
377   while (p)
378     {
379       ACPI_RESOURCE const *r = (ACPI_RESOURCE const *)p;
380       ACPI_RESOURCE_DATA const *d = &r->Data;
381       unsigned flags = 0;
382
383       switch (r->Type)
384         {
385         case ACPI_RESOURCE_TYPE_END_TAG:
386           AcpiOsFree(buf.Pointer);
387           return;
388
389         case ACPI_RESOURCE_TYPE_IRQ:
390           flags = Resource::Irq_res;
391           flags |= (!d->Irq.Triggering) * Resource::Irq_info_base;
392           flags |= (!!d->Irq.Polarity) * Resource::Irq_info_base * 2;
393           for (unsigned c = 0; c < d->Irq.InterruptCount; ++c)
394             host->add_resource(new Adr_resource(flags, d->Irq.Interrupts[c],
395                                                 d->Irq.Interrupts[c]));
396           break;
397
398         case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
399           flags = Resource::Irq_res;
400           flags |= (!d->ExtendedIrq.Triggering) * Resource::Irq_info_base;
401           flags |= (!!d->ExtendedIrq.Polarity) * Resource::Irq_info_base * 2;
402           if (d->ExtendedIrq.ResourceSource.StringPtr)
403             {
404               d_printf(DBG_DEBUG2, "hoo indirect IRQ resource found src=%s idx=%d\n",
405                       d->ExtendedIrq.ResourceSource.StringPtr,
406                       d->ExtendedIrq.ResourceSource.Index);
407             }
408           else
409             {
410               for (unsigned c = 0; c < d->ExtendedIrq.InterruptCount; ++c)
411                 host->add_resource(new Adr_resource(flags, d->ExtendedIrq.Interrupts[c],
412                       d->ExtendedIrq.Interrupts[c]));
413             }
414           break;
415
416         case ACPI_RESOURCE_TYPE_IO:
417           flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
418           host->add_resource(new Adr_resource(flags, d->Io.Minimum,
419                                               d->Io.Minimum + d->Io.AddressLength - 1));
420           break;
421
422         case ACPI_RESOURCE_TYPE_FIXED_IO:
423           flags = Resource::Io_res | Resource::F_fixed_size | Resource::F_fixed_addr;
424           host->add_resource(new Adr_resource(flags, d->FixedIo.Address,
425                                               d->FixedIo.Address + d->FixedIo.AddressLength - 1));
426           break;
427
428         case ACPI_RESOURCE_TYPE_MEMORY24:
429           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
430           host->add_resource(new Adr_resource(flags, d->Memory24.Minimum,
431                                               d->Memory24.Minimum + d->Memory24.AddressLength - 1));
432           break;
433
434         case ACPI_RESOURCE_TYPE_MEMORY32:
435           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
436           host->add_resource(new Adr_resource(flags, d->Memory32.Minimum,
437                                               d->Memory32.Minimum + d->Memory32.AddressLength - 1));
438           break;
439
440         case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
441           flags = Resource::Mmio_res | Resource::F_fixed_size | Resource::F_fixed_addr;
442           host->add_resource(new Adr_resource(flags, d->FixedMemory32.Address,
443                                d->FixedMemory32.Address + d->FixedMemory32.AddressLength - 1));
444           break;
445
446         case ACPI_RESOURCE_TYPE_ADDRESS16:
447           acpi_adr_res(host, &d->Address, d->Address16.Minimum, d->Address16.AddressLength, 0);
448           break;
449
450         case ACPI_RESOURCE_TYPE_ADDRESS32:
451           acpi_adr_res(host, &d->Address, d->Address32.Minimum, d->Address32.AddressLength, 0);
452           break;
453
454         case ACPI_RESOURCE_TYPE_ADDRESS64:
455           acpi_adr_res(host, &d->Address, d->Address64.Minimum, d->Address64.AddressLength, 1);
456           break;
457
458         default:
459           d_printf(DBG_WARN, "WARNING: ignoring ACPI recource (unkown type: %d)\n", r->Type);
460           break;
461
462
463         }
464
465       p += r->Length;
466     }
467
468   AcpiOsFree(buf.Pointer);
469 }
470
471 void
472 Acpi_res_discover::discover_resources(Hw::Device *host)
473 {
474   if (dynamic_cast<Pci_bridge*>(host->discover_bus_if()))
475     discover_prt(host);
476
477   discover_crs(host);
478 }
479
480
481 static l4_uint32_t
482 get_adr(ACPI_HANDLE dev)
483 {
484   ACPI_HANDLE adr;
485   if (ACPI_FAILURE(AcpiGetHandle(dev, const_cast<char*>("_ADR"), &adr)))
486     return ~0U;
487
488   ACPI_OBJECT adro;
489   ACPI_BUFFER ret_buf;
490   ret_buf.Pointer = &adro;
491   ret_buf.Length = sizeof(adro);
492   if (ACPI_SUCCESS(AcpiEvaluateObject(adr, NULL, NULL, &ret_buf)))
493     {
494       switch (adro.Type)
495         {
496         case ACPI_TYPE_INTEGER:
497           return adro.Integer.Value;
498         default:
499           return ~0;
500         }
501     }
502
503   return ~0;
504 }
505
506 static void
507 get_name(ACPI_HANDLE dev, Hw::Device *hd)
508 {
509   char str[5];
510   ACPI_BUFFER buf;
511   buf.Pointer = &str;
512   buf.Length = sizeof(str);
513   if (ACPI_SUCCESS(AcpiGetName(dev, ACPI_SINGLE_NAME, &buf)))
514     hd->set_name(str);
515 }
516
517
518 static ACPI_STATUS
519 discover_pre_cb(ACPI_HANDLE obj, UINT32 nl, void *ctxt, void **)
520 {
521   Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
522
523   if (nl == 1)
524     return AE_OK;
525
526   if (nl > c->level)
527     {
528       c->current_bus = c->last_device;
529       c->level = nl;
530     }
531
532   l4_uint32_t adr = get_adr(obj);
533
534   Hw::Device *nd = c->current_bus->get_child_dev_uid((l4_umword_t)obj, adr, true);
535   c->last_device = nd;
536
537   get_name(obj, nd);
538
539   ACPI_DEVICE_ID *hid = 0;
540   ACPI_DEVICE_ID_LIST *cid = 0;
541   bool pci_rb = false;
542 #if 0
543   if (ACPI_FAILURE(AcpiUtAcquireMutex(ACPI_MTX_NAMESPACE)))
544     return AE_OK;
545 #endif
546
547   ACPI_NAMESPACE_NODE *node = AcpiNsValidateHandle(obj);
548   if (!node)
549     {
550       //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
551       return AE_OK;
552     }
553
554   if (ACPI_SUCCESS(AcpiUtExecute_HID(node, &hid)))
555     {
556       nd->set_hid(hid->String);
557       pci_rb |= AcpiUtIsPciRootBridge(hid->String);
558       ACPI_FREE(hid);
559     }
560
561   if (ACPI_SUCCESS(AcpiUtExecute_CID(node, &cid)))
562     {
563       for (unsigned i = 0; i < cid->Count; ++i)
564         {
565           nd->add_cid(cid->Ids[i].String);
566           pci_rb |= AcpiUtIsPciRootBridge(cid->Ids[i].String);
567         }
568       ACPI_FREE(cid);
569     }
570
571
572   //AcpiUtReleaseMutex(ACPI_MTX_NAMESPACE);
573
574   // hm, this seems very specific for PCI
575   if (pci_rb)
576     {
577       d_printf(DBG_DEBUG, "Found PCI root bridge...\n");
578       if (Pci_root_bridge *rb = pci_root_bridge(0))
579         {
580           if (rb->host())
581             {
582               // we found a second root bridge
583               // create a new root pridge instance
584               rb = new Pci_port_root_bridge(nd);
585             }
586           else
587             rb->set_host(nd);
588
589           nd->set_discover_bus_if(rb);
590         }
591       else
592         d_printf(DBG_ERR, "ERROR: there is no PCI bus driver for this platform\n");
593     }
594
595   nd->add_resource_discoverer(new Acpi_res_discover(obj));
596
597   return AE_OK;
598 }
599
600 static ACPI_STATUS
601 discover_post_cb(ACPI_HANDLE, UINT32 nl, void *ctxt, void **)
602 {
603   Discover_ctxt *c = reinterpret_cast<Discover_ctxt*>(ctxt);
604   if (nl < c->level)
605     {
606       c->level = nl;
607       c->current_bus = c->current_bus->parent();
608     }
609   return AE_OK;
610 }
611
612 }
613
614
615 int acpica_init()
616 {
617   d_printf(DBG_INFO, "Hello from L4-ACPICA\n");
618
619   pci_register_root_bridge(0, new Pci_port_root_bridge(0));
620
621   AcpiDbgLevel =
622       ACPI_LV_INIT
623     //| ACPI_LV_INFO
624    // | ACPI_LV_FUNCTIONSkern/irq.cpp
625    //     | ACPI_LV_ALL_EXCEPTIONS 
626     //    | ACPI_LV_LOAD 
627     //    | ACPI_LV_INIT_NAMES 
628         | ACPI_LV_TABLES 
629     //    | ACPI_LV_RESOURCES 
630     //    | ACPI_LV_NAMES
631     //    | ACPI_LV_VALUES 
632     //    | ACPI_LV_OPREGION  
633         | ACPI_LV_VERBOSE_INFO 
634     //    | ACPI_LV_PARSE
635     //    | ACPI_LV_DISPATCH
636     //    | ACPI_LV_EXEC
637     //    | ACPI_LV_IO
638     ;
639
640 //0. enable workarounds, see include/acglobals.h
641   AcpiGbl_EnableInterpreterSlack = (1==1);
642   ACPI_STATUS status;
643
644   status = AcpiInitializeSubsystem();
645   if(status!=AE_OK)
646     return status;
647
648   status = AcpiInitializeTables (0, 0, TRUE);
649   if(status!=AE_OK)
650     return status;
651
652   status = AcpiReallocateRootTable ();
653 //  if(status!=AE_OK)
654 //    return status;
655
656   status = AcpiLoadTables ();
657
658   if(ACPI_FAILURE(status))
659     return status;
660
661   d_printf(DBG_DEBUG, "enable ACPI subsystem\n");
662   status = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION);
663
664   if (ACPI_FAILURE(status))
665     {
666       d_printf(DBG_ERR, "Unable to start the ACPI Interpreter\n");
667       exit(status);
668     }
669
670   d_printf(DBG_DEBUG, "initialize ACPI objects\n");
671   status = AcpiInitializeObjects(ACPI_FULL_INITIALIZATION);
672   if (ACPI_FAILURE(status)) {
673       d_printf(DBG_ERR, "Unable to initialize ACPI objects\n");
674       exit(status);
675   }
676
677   d_printf(DBG_DEBUG, "Interpreter enabled\n");
678
679   Discover_ctxt c;
680   c.last_device = system_bus();
681   c.current_bus = system_bus();
682   c.level = 1;
683
684
685   d_printf(DBG_DEBUG, "scanning for PCI root bridge\n");
686   status = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
687                              ACPI_UINT32_MAX,
688                              discover_pre_cb, discover_post_cb, &c, 0);
689
690   /*
691    * Get the system interrupt model and evaluate \_PIC.
692    */
693   int result = acpi_bus_init_irq();
694   if (result)
695     {
696       d_printf(DBG_ERR, "Could not initialize ACPI IRQ stuff\n");
697       exit(1);
698     }
699   status = AcpiSubsystemStatus();
700
701   if (ACPI_FAILURE(status))
702       exit(status);
703
704   d_printf(DBG_INFO, "ACPI subsystem initialized\n");
705
706   ACPI_BUFFER ret_buffer;
707   ret_buffer.Length = ACPI_ALLOCATE_BUFFER;
708
709   status = AcpiGetSystemInfo(&ret_buffer);
710
711   if(ACPI_FAILURE(status))
712     exit(status);
713
714   acpi_print_system_info(ret_buffer.Pointer);
715
716   AcpiOsFree(ret_buffer.Pointer);
717
718   return 0;
719 }
720