Search logs:

channel logs for 2004 - 2010 are archived at http://tunes.org/~nef/logs/old/ ·· can't be searched

#osdev2 = #osdev @ Libera from 23may2021 to present

#osdev @ OPN/FreeNode from 3apr2001 to 23may2021

all other channels are on OPN/FreeNode from 2004 to present


http://bespin.org/~qz/search/?view=1&c=osdev&y=19&m=8&d=9

Friday, 9 August 2019

00:04:41 <ybyourmom> geist: Do you have any insight into or involvement with packetdrill?
00:07:37 <geist> ybyourmom: negative
00:08:18 * ybyourmom nods, np np
00:43:23 <griddle> Does anyone have some simple example code for a simple physical memory manager?
00:43:43 <griddle> I've got the concepts down, but in my attempts to do better than a simple bitmap allocator, I have run into circular dependencies
00:43:45 <zid> page += 4096;
00:44:08 <zid> yea there's a lot of catches twenty seconds in an allocator
00:44:10 <griddle> ie: kmalloc needs a page, page allocator needs a page for data and asks kmalloc, kmalloc isnt reentrant
00:44:28 <zid> that's why I just ended up mapping all physical memory into memory at boot
00:44:30 <ybyourmom> The standard answer is to use a recursive lock
00:44:34 <ybyourmom> That
00:44:34 <Mutabah> easiest allocator - a freelist
00:44:51 <ybyourmom> That's pretty much actually the only place they're meant to be used afaict
00:44:53 <griddle> I'd like to avoid writing a linked list to physical memory
00:44:58 <zid> Mutabah: I started with a freelist then had the lovely issue of how to clear the old pointer out of the new page
00:45:38 <griddle> and I want to use the memory map that multiboot gives me to determine where usable memory is
00:45:42 <Mutabah> zid: Point - I have my pmm tied into the vmm - so allocating a page ends up mapping it (to read/clear the next pointer)
00:46:04 <zid> Mutabah: I mainly used mine for allocating page tables and dma regions so far
00:46:05 <Mutabah> Other option: bitmap
00:46:32 <ybyourmom> Buddy, butmap, stack, or a combination of those
00:46:33 <zid> so they don't have associated virtual addresses
00:47:15 <griddle> so using a bitmap, I just need to eat the cost of N/8 pages
00:47:46 <Mutabah> If you want simple - yes
00:48:01 <griddle> so I currently have a design that acts somewhat like paging
00:48:04 <zid> I have a freelist and a bitmap but I'm not settled on which I will use, or both, or what, yay for not having to care until I want to care
00:48:11 <Mutabah> zid: Use both :)
00:48:14 <griddle> where part of the ppn is one table, another part is another table, and an offset
00:48:27 <griddle> so starting out, my allocator only uses 3 or 4 pages
00:48:30 <griddle> and lazily maps the rest
00:48:35 <zid> I only added the bitmap so I could fuse 4k pages into 2MB tables by doing a single 64bit read and seeing if it's 0 or -1
00:48:57 <zid> but actually taking those 4k pages out of the freelist would be a nightmare so I m ight have to end up making the freelist doubly-linked
00:49:00 <zid> to actually use it for anything
00:50:27 <zid> I mean, that's not the end of the world
00:53:08 <griddle> hmm, I'm now thinking of having two heaps
00:53:42 <griddle> because my kmalloc uses an sbrk-like heap that starts at the end of physical memory so I can identity map physical memory if I need to.
00:53:46 <bcos> Heap is a totally different layer
00:54:39 <griddle> I know, but I need to store the datastructure for the physical page allocator somewhere
00:56:43 <zid> If you can make it fit exactly in 4kb it could bootstrap itself
00:57:00 <griddle> how do you mean?
00:57:25 <zid> like if you designed some recursive tree where each node was 4kB, you could just do page += 4096; until it was all initialized
00:57:31 <zid> then swap over to using it
00:57:52 <zid> or I guess just byte allocate out of those pages as long as they're contiguous
00:57:55 <zid> which they should be
00:58:05 <zid> basically, a bootstrap phase
00:58:14 <zid> where you initialize the 'real' allocator such that it can use itself
00:58:20 <griddle> ah I see
01:03:16 <zid> Like, a trivial implementation would be to scan the memory map (e820 if you're x86), add_memory_range(x, y); and the allocator just figures out how much space it's going to need to track 'y' bytes, does newx += that_size;
01:03:30 <zid> and allocates for itself out of x-newx to track newx to newx+y
01:03:32 <zid> if that makes sense
01:05:25 <zid> There's also the 'make all the tracking structures static so they come out of bss' if you're on a very embedded system
01:06:49 <griddle> So if I were to just go with the "big contiguous bitmap" idea, how should I get around the fact that systems like QEMU put mmio holes everywhere
01:07:42 <griddle> because with 8gb of ram, you'd need like, 260K of bitmap, and I run into a memory gap with that
01:08:08 <zid> Nothing says you have to put it at the start
01:08:09 <Mutabah> allocate a region of virtual memory, but map the parts of that you need
01:08:25 <zid> and yea you're going to need a virtual address range to track it
01:08:30 <zid> so that you can read/write to it
01:08:37 <zid> so whether the bitmap pages themselves are contiguous is sort of irrelevent
01:09:50 <zid> again, your early_alloc doing page += 4096 or whatever can supply page table pages and bitmap pages from 'wherever'
01:10:18 <zid> such that you end up with a contigous virtual range that the bitmap is mapped linearly (even with holes)
01:11:46 <zid> So say your ram is from 2GB to 4GB, and 6GB to 8GB or something, you could make 0xFFFFFFFF00000000 the 'offseted' base for your bitmap
01:12:10 <zid> 0xffffffff0010000 would be the bitmap representing the first 2GB range, ....2000 would be the second
01:12:15 <zid> and it'd be a couple of page mappings total
01:13:04 <griddle> hmm, this all has my head spinning with new ideas.
01:13:14 <zid> yea I had the same issue
01:13:26 <zid> I'd invent something great in my head ten 20 seconds later realize it wouldn't work
01:13:27 <zid> repeat for an hour
01:13:29 <griddle> I also think that I can solve my current problem by having a queue of allocated physical pages
01:13:36 <zid> yea, a freelist :P
01:13:40 <griddle> well not really
01:13:45 <bcos> Allocated?
01:13:53 <griddle> so my problem right now is the physical memory allocator needs to allocate memory to holds its data
01:13:57 <zid> where are you going to get the memory to track the memory you've.. *used*
01:14:01 <griddle> be it for virtual addresses or anything
01:14:02 <zid> that seems not very possible
01:14:15 <griddle> I could just store that in some bss array
01:14:15 <zid> you should track memory you haven't used, using memory you haven't used
01:14:23 <zid> then you never run into a catch-22
01:14:40 <zid> either you've got 0 free memory, and 0 pages tracking it, or all your memory is free and there are n pages tracking it
01:16:05 <griddle> Hmm, well the current problem flow I have is, need page for kmalloc -> ask physical allocator -> needs page for physical page allocator -> kmalloc -> [restart]
01:16:28 <Mutabah> Don't have the PMM call kmalloc
01:16:40 <Mutabah> Use a specialised allocator for whatever metadata it needs
01:17:13 <zid> griddle: The catch-22 is that you're trying to use a thing before you prime it
01:17:16 * bcos ust doesn't have a kmalloc at all.. :-)
01:17:19 <griddle> yeah
01:17:23 <zid> You need to prime it first
01:17:31 <zid> early_alloc and early_map or whatever
01:17:39 <griddle> well, it works up until a point
01:18:37 <zid> https://github.com/zid/boros/blob/master/mem.c#L45 :D
01:19:13 <zid> my OS requires consecutive pages be available to init the allocator enough to track the rest because of that I guess
01:19:34 <zid> You could check against a copy of the e820 if you really wanted I guess
01:19:44 <griddle> where does the first free_page come from?
01:19:59 <zid> griddle: first bit of free memory
01:20:26 <griddle> interesting, so I guess you arent worrying about clobbering some bios information?
01:20:34 <zid> my memory goes [1MB which I ignore][Kernel][kernel_bss][kernel_stack_page][free_page] or whatever
01:20:45 <zid> mine's kind of fast and loose at looking for places which are suitable and just trusts they are though because I'm lazy
01:20:48 <zid> this is the least robust thing ever
01:20:56 <griddle> ah
01:21:10 <zid> I just get to write "minimum specs: 10kB of free memory at 1MB"
01:21:15 <griddle> yeah, I have a boot heap allocator that just starts at the end of kernel's code, so I can start there I guess
01:21:27 <zid> my bootloader actually sets all this up for me
01:21:52 <zid> but it uses the same allocator
01:22:28 <zid> kernel_end = kernel_start + kernel_size;
01:22:31 <zid> init_mem(mb, kernel_end);
01:22:48 <zid> static void init_mem(struct multiboot *mb, unsigned long kernel_end) { free_page = kernel_end; ... }
01:23:03 <zid> I could do a check there if that's actually inside the e820 and bump it forwards, ofc
01:23:45 <griddle> so you use this to build up part of the physical page allocator, then when it is started, you swap over to the better one?
01:23:52 <zid> yea
01:24:30 <zid> https://github.com/zid/boros/blob/master/mem.c#L180 is the 'real' allocator
01:25:21 <griddle> so are you storing metadata inside the physical pages themselves?
01:25:23 <zid> there's a 4K and a 2M list and you just ask it for either size and it pulls it off the stack and gives you it
01:25:31 <zid> yea hence line 192
01:25:38 <zid> it wipes the ->next off
01:25:42 <zid> so that the page is clean again
01:25:47 <zid> not ideal but meh
01:26:02 <zid> it's simple and I can debug it
01:26:14 <zid> I don't really know what the requirements are until I get further in
01:26:18 <griddle> yeah, I am totally overthinking this
01:26:20 <zid> so no real need to make it more complicated
01:26:38 <zid> I don't even support free() yet because I'm lazy, it'll just be the inverse though
01:26:51 <zid> *p = freelist[size]; freelist[size] = p;
01:28:02 <zid> Mutabah: How should I integrate my bitmap so that it actually does something useful? :P
01:29:57 <Mutabah> Up to you
01:30:22 <Mutabah> iirc I use several structures for various usecases
01:30:57 <zid> I added it so I could merge 4k back into 2M if needed, but I'd have to search the freelis linearly 512 times to actually do that
01:31:00 <zid> which is pretty pants
01:31:38 <zid> well I guess only once, remove everything i find in the right 2M region
01:31:44 <Mutabah> I don't use 2M pages, so that's not a problem
01:31:48 <zid> but still finding 512 things in a list that might be millions long
01:31:56 <zid> my ethernet card wanted 16kB contig physical regions
01:32:07 <zid> and wanted 16 of them or whatever, so I have a 2M alloc
01:32:20 <Mutabah> That should be allocated early enough that it can just get them
01:32:23 <zid> and I chunk it inside the driver code cus I'm weird and I don't have a kalloc(4) or whatever like linux does
01:32:37 <Mutabah> Useful trick: Don't do anything at startup except register the memory map
01:32:49 <Mutabah> when the freelist is empty, start eating into the memory map
01:33:08 <zid> I considered having like, blocks
01:33:18 <zid> and it just tries to glue the blocks together when it can
01:33:26 <zid> but the tracking structure for that is super annoying
01:33:39 <zid> then I was like how about a buddy thingy and gave up caring
02:00:42 <ybyourmom> bcos: when you say you don't have kmalloc, do you mean that you have userspace controlled kernel object allocation?
02:04:50 <Mutabah> Probably means that there's no general kernel malloc - just specialise allocators for each subsystem
02:06:03 * ybyourmom nods
02:45:39 <bcos> ybyourmom: Micro-kernel where there's a small number of "things" (process info block, thread info block, message queue, ...), and each thing uses its own management (but most are "array of thing" backed by "allocate on write" pages, so you can allocate (e.g.) a threadID and immediately do "thread_info_table[threadID].foo = bar;"
02:50:48 <bcos> (can probably do a whole micro-kernel with nothing more than statically allocated arrays; as long as you don't mind doing a "free the underlying physical pages that aren't actually in use when RAM is running low" for each array of things)
03:48:35 <MarchHare> Okay, so anyone familiar with vga programming can help me answer this. I'm trying to save the values in the CRTC registers of a standard vga (dosbox, dosemu, etc). No special tricks. Various registers reads on 0x3b5 are coming back as 0xFF when I know they should be coming back with various values. Is the CRTC write-only on VGA, or is there a way to read it? No access to BIOS int 10h for this.
03:50:43 <zid> which reg?
03:52:01 <zid> note the read and write ports are different, and you have to do a register select first
03:52:07 <MarchHare> CRTC 0x00 - 0x18
03:52:27 <MarchHare> zid: YEs, I'm selecting them. Right now I'm just trying to output them.
03:53:03 <MarchHare> zid: So I do an out 0x3b4, idx, then an in 0x3b5
03:53:45 <MarchHare> No, I know it isn't proper assembler, I'm protyping in qbx right now since I want to see what these registers actually start with
03:54:47 <zid> What what's the low bit of 0x3CC?
03:54:51 <MarchHare> The code seems to output the other registers I've looked at properly.
03:55:01 <MarchHare> Let me code that one in and look!
03:56:27 <MarchHare> 0x67, expected for qbasic screen 0
03:56:33 <MarchHare> Low bit is 1.
03:56:44 <zid> change 3b to 3d then
03:56:55 <zid> 3d4 3d5
03:57:07 <MarchHare> zid: Waid, 3d4 and 3d5 are used by default?
03:57:26 <zid> that's a select bit for where those regs are
03:57:40 <zid> for MDA or CGA compatibility
03:57:53 <MarchHare> I suppose that makes sense.
03:57:54 <zid> it's set to CGA, you're writing to the MDA regs, though I expect most things just decode both
03:58:22 <zid> https://en.wikipedia.org/wiki/IBM_Monochrome_Display_Adapter
03:58:31 <MarchHare> Well, I'm trying to do cga for now :) I want my cga code to behave normally on a vga machine. It works fine with a emulated cga card, but not the vga one
03:59:37 <zid> maybe your vga card does not emulate MDA then
04:00:08 <MarchHare> It seems to do it just fine for programs written in the late 80's.
04:00:22 <zid> what is the it, in either cast
04:00:24 <zid> case*
04:00:25 <MarchHare> I assume they might be using int 10h to change mode
04:00:45 <zid> or they're assuming cga
04:00:47 <zid> or mda
04:00:56 <zid> or they're autodetecting
04:01:25 <MarchHare> Well, my code just assumed cga, too. And it worked for a cga card, but as soon as I ran it as a vga machine, it didn't even get out of text mode.
04:01:50 <MarchHare> Paperboy from mindscape 1988 didn't autodetect, you had to select CGA/EGA/Tandy
04:02:05 <MarchHare> If CGA is selected, it looks correct.
04:03:32 <MarchHare> I know that with qbasic, it works fine using screen 1, but I can't get the color select register to actually be respected (palette stays CMYK) on a vga machine, but on a cga one, my example cycles colors like I intended.
04:03:47 <MarchHare> The failure to change palettes also seems to happen on a real 486
04:04:01 <MarchHare> But it seemed to work with a "real" program
04:07:21 <MarchHare> I may have spotted it. Might be a nvm?
04:08:04 <MarchHare> I hate the way 3b4 and 3d4 look very similar
04:11:39 <MarchHare> seems to be reading properly now.
04:11:57 <zid> oh I was looking for common settings for various vga modes, and finally found it... on the osdev wiki, heh
04:12:22 <MarchHare> Yeah, I've got a bunch of info. It helps if I don't misread what I've already typed
04:12:41 <zid> I was looking at the freevga docs to answer your questions
04:12:55 <zid> I've never programmed vga directly before beyond the palette regs 20 years ago to make a fire demo
04:12:56 <MarchHare> I'm trying to essentially take my own little baremetal code into CGA mode and display a picture
04:13:13 <zid> cga is for wimps, get it into a vbe linear framebuffer 1920*1080
04:13:17 <MarchHare> The freevga docs are good, but I hate that they've got a lot of "WIP" which isn't even available
04:13:30 <zid> osdev wiki looks like a good distilation of those docs honestly
04:13:32 <zid> shame I found it last
04:13:38 <MarchHare> Programming the palette looks pretty damn easy to me. I'll get to that
04:13:51 <MarchHare> What's the link on osdev? I think I found it, but I'll look again.
04:13:52 <zid> yea it is you just feed it sequentially your new palette afaik
04:13:57 <zid> vga_hardware
04:15:50 <MarchHare> Interesting. Looks like CRTC8 doesn't get changed at all by the screen mode changes in qbx
04:16:07 <zid> oh yea that would have been a good idea
04:16:16 <zid> just ask qbasic to do SCREEN 12 or whatever and dump the regs
04:16:23 <zid> or even the bios
04:16:32 <MarchHare> zid That's pretty much what I'm trying to do is dump the regs
04:16:48 <MarchHare> zid I wanna see what qb screen 1 looks like compared to text mode screen 0
04:17:25 <zid> one day I'll get around to writing a qbasic compiler or something
04:20:02 <MarchHare> You should do a qbasic interpreter that can emulate the hardware accesses.
04:20:09 <MarchHare> <g>
04:20:47 <MarchHare> Drives me nuts that I have to emulate dos or a PC just to run qbasic so I have an environment that I can prototype in.
04:21:15 <zid> I miss qbasic as a proto environment, but I eventually just made a rig for windows
04:21:24 <zid> that makes a 640*480 window and a pset() function
04:21:33 <zid> there's always yabasic on ps2 ;)
04:23:12 <MarchHare> pset is fine, but when you wanna do port writes and writing to memory hard style, gotta have hardware access
05:19:48 <ybyourmom> bcos: Ah, makes sense, but it sounds like you statically define how many of each capability/object can exist
05:20:00 <ybyourmom> If you're using an array that is
05:21:05 <ybyourmom> That's probably reaosnable if your microkernel is meant to be used only on embedded systems or systems which use a fairly non-dynamic, known-in-advance number of each object type
05:22:17 <ybyourmom> Or maybe you have some little trick that helps you to manage the possibility of the user wanting more than MAX_PIDS processes or more than MAX_VCPUS vpu contexts, etc
05:22:41 <zid> yea, tell them to piss off :P
05:23:38 <ybyourmom> err = bcos_alloc_new_object(&handle, BCOS_OBJTYPE_IPC_ENDPOINT);
05:23:50 <ybyourmom> if (err == -EPISSOFF) { ... }
05:23:57 <ybyourmom> Gotcha xD
06:17:50 <klange> I bit the bullet and broke up my editor... themes and syntax are now in separate files. The base editor still builds with just the main file, and I did some constructor crap to make the themes and syntax highlighters bind automatically.
06:22:01 <ybyourmom> Tough choices; bit the bullet on that one
06:22:03 <ybyourmom> lol
06:22:18 <klange> It was so cute as a single (gigantic) file...
06:22:22 <klange> Feels like the end of an era.
06:22:39 <klange> Little Bimmy grew up...
06:22:51 <ybyourmom> If you'd left it that way, it would have become a time-honoured unixism tradition
06:24:15 <klange> Next step is completely redoing how the editor modes work, then breaking up the command interface so it's not just a bunch of if's.
07:39:42 <j`ey> klange: so your build system supports several files now?
07:40:12 <klange> no I wrote a tool to turn the multi-file editor source into a single file specifically for toaruos's build system
07:40:15 <klange> :D
07:43:25 <j`ey> heh
10:49:01 <j`ey> I had some accidental recursion, which was causing me to overflow the stack, woops
10:52:55 * j`ey facepalms
10:53:09 <j`ey> I also did something entirely stupid, which was the cause of my garbled output
10:56:35 <mrvn> klange: editor.c: #include "syntax.c" #include "themes.c" ...
10:56:41 <mrvn> klange: why do you need a tool?
11:08:08 <klange> mrvn: because the c preprocess doesn't have wildcard globbing
11:08:12 <klange> preprocessor*
11:54:49 <geist> j`ey: ah that explains it
11:55:09 <geist> once you overflow your stack all bets are off (assuming you dont catch it with a guard page or something)
11:55:45 <j`ey> geist: I was implementing the 'panic' function that rust has... but was panic-ing inside that function
11:55:54 <j`ey> hence infinite recursion
11:56:00 <geist> and yeah the prefetch abort you saw the other day is almost always a page fault. they look different than x86 on ARM because a page fault is basically a specific case of either a prefetch abort (instruction fetching) or a data abort
11:56:50 <j`ey> apparently there is also a -singlestep option in qemu (I didnt try it yet)
11:56:54 <geist> but it's all well recorded in the ESR (exception syndrome register) when you take one
11:56:57 <geist> so it's easy to decode
11:56:58 <mrvn> klange: you want to cat $(SRCDIR)/*.c >editor.c? Still no need for a special tool.
11:57:58 <geist> if you do, you might want to sort the names, so that it's deterministic
11:57:58 <klange> my tool puts stuff in a nice order, looks better
11:58:03 <geist> yah
11:58:06 <j`ey> geist: bcos spotted that the PC was 0x610000610000 (or something), which is 'AA' in utf8-le, which led me closer towards it being a stack issue!
11:58:12 <geist> yah
11:58:12 <mrvn> klange: My build system uses -fLTO selectively. Gives me all the optimizations of having a single source file without having to have just one.
11:59:02 <mrvn> j`ey: don't map the page above and below the stack.
11:59:40 <j`ey> mrvn: I havent yet gotten to turning on the MMU :)
12:00:00 <mrvn> well, then: DON'T PANIC!
12:15:31 <bytefire> in ARMv8, do we need data memory barrier to make sure that a write to MMIO register completes before next instruction?
12:16:20 <mrvn> maybe.
12:17:11 <ybyourmom> bytefire: it depends on data dependency and memory ordering properties on that memory
12:17:25 <ybyourmom> nGnRnE
12:17:33 <ybyourmom> And so on
12:17:41 <mrvn> On the RPi the memory bus is broken^Wbadly designed so writing to an MMIO register of a different device can swap itself with a previoues write (same for reads)
12:17:53 <mrvn> Not sure if RPi3/4 fixed that
12:18:30 <ybyourmom> Sounds crazy
12:18:45 <mrvn> basically means you have to have a barrier on ever MMIO access
12:19:02 <Nuclear_> oh yeah I remember reading about that... mad
12:19:54 <bytefire> ybyourmom: i see, thanks. i will look into that. normally MMIO is strongly ordered? or i made this up?
12:20:03 <mrvn> I can totaly see why you would need a barrier to flush out data so it doesn't linger in the cache forever or something. But having a read from the UART suddenly return the data from the SATA controller because you read that a few opcodes before that is insane.
12:20:43 <mrvn> bytefire: you probably want it uncached too.
12:20:54 <bytefire> mrvn: right
12:21:26 <mrvn> bytefire: you have to set the right bits in the page tables so the MMIO region is strongly ordered. It doesn't magically happen on it's own.
12:21:42 <bytefire> mrvn: ah okay
12:22:44 <bytefire> does strongly ordered guarantee that next read/write will only happen after pervious one completed?
12:22:58 <bytefire> or is that what it is
12:23:52 <mrvn> iirc
12:24:17 <mrvn> read might not wait for writes, check the specs
12:25:02 <bytefire> mrvn: okay
12:25:18 <bytefire> thanks for the help!
12:26:00 <mrvn> Lets put it this way: Having a barrier can't hurt. Missing one can,
12:26:11 <ybyourmom> bytefire: For the most part, you want device ordered memory
12:26:44 <mrvn> ybyourmom: iirc that was the same setting in the MMU
12:27:05 <mrvn> but ARMv8 might have more bits
12:27:05 <ybyourmom> Strongly ordered memory is only stronger than device ordered in the sense that strongly ordered memory is not reordered with respect to loads/stores to memory regions outside of the strongly ordered memory as well
12:27:22 <ybyourmom> And strongly ordered memory has no early write acknowledgment
12:28:01 <ybyourmom> Device ordered memory will not reorder within that page that has the device ordered attribute
12:28:19 <ybyourmom> Strongly ordered memory is strongly ordered with respect to memory outside that page as well
12:29:20 <mrvn> .oO(Except on the RPi)
12:29:34 <ybyourmom> Can't comment there personally
12:30:34 <mrvn> as said, if you mix read/write of different pages the data paths get crossed and you can end up with the wrong data.
12:33:06 <bytefire> ybyourmom: i see! right
12:33:42 <bytefire> mrvn: have to watch out
12:38:19 <mrvn> geist: Do you happen to know if the MMIO memory bus is still screwed up on the RPi4?
12:50:12 <geist> mrvn: no idea
13:01:07 <mrvn> geist: something to keep in mind when you port stuff to it
14:53:31 <mrvn> Keyboard stuck, press F1 to continue
14:53:37 <j`ey> F1
14:59:31 <verm1n> hi. Is there a way to check how many BARs a PCI device can use, or should i just try to map each one and ignore ones where size==0?
15:03:12 <mrvn> Wouldn't exactly that be a way to do it?
15:09:11 <verm1n> mrvn: guess so. was just wondering if im missing a num_bars or something
16:27:40 <lkurusa> verm1n: i think that's exactly how the pci spec recommends