diff options
author | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2014-12-21 01:30:36 +0100 |
---|---|---|
committer | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2014-12-21 01:30:36 +0100 |
commit | a11fe1959db311c090c7a025d96643c7ad8b76e5 (patch) | |
tree | df2fa652b5d6c74ba9cb6c135d62fc2920c09bc6 /sys/src | |
parent | 758496ecaa42b5f6c17c0bd1e0f43189e50e0745 (diff) | |
parent | 8ac28ac11cb9e96329e4d083208b3f13ee8d2b8a (diff) |
merge
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/9/pc/archacpi.c | 58 | ||||
-rw-r--r-- | sys/src/9/pc/archmp.c | 12 | ||||
-rw-r--r-- | sys/src/9/pc/devarch.c | 3 | ||||
-rw-r--r-- | sys/src/9/pc/fns.h | 2 | ||||
-rw-r--r-- | sys/src/9/pc/main.c | 7 | ||||
-rw-r--r-- | sys/src/9/pc/mmu.c | 6 | ||||
-rw-r--r-- | sys/src/9/pc/mp.c | 23 | ||||
-rw-r--r-- | sys/src/9/pc64/fns.h | 2 | ||||
-rw-r--r-- | sys/src/9/pc64/main.c | 4 | ||||
-rw-r--r-- | sys/src/9/pc64/pc64 | 6 | ||||
-rw-r--r-- | sys/src/9/pc64/pccpu64 | 8 | ||||
-rw-r--r-- | sys/src/9/port/fault.c | 4 | ||||
-rw-r--r-- | sys/src/9/port/sdaoe.c | 34 | ||||
-rw-r--r-- | sys/src/9/port/sdloop.c | 5 | ||||
-rw-r--r-- | sys/src/9/port/xalloc.c | 6 | ||||
-rw-r--r-- | sys/src/9/xen/fns.h | 5 | ||||
-rw-r--r-- | sys/src/9/xen/l.s | 27 | ||||
-rw-r--r-- | sys/src/9/xen/main.c | 64 | ||||
-rw-r--r-- | sys/src/9/xen/mem.h | 57 | ||||
-rw-r--r-- | sys/src/9/xen/mmu.c | 64 | ||||
-rw-r--r-- | sys/src/cmd/acme/text.c | 10 | ||||
-rw-r--r-- | sys/src/cmd/disk/mkfile | 1 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/aoe.h | 70 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/mkfile | 12 | ||||
-rw-r--r-- | sys/src/cmd/disk/vblade/vblade.c | 666 | ||||
-rw-r--r-- | sys/src/libflate/inflatezlibblock.c | 2 |
26 files changed, 840 insertions, 318 deletions
diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c index 6805f5c87..644df59b9 100644 --- a/sys/src/9/pc/archacpi.c +++ b/sys/src/9/pc/archacpi.c @@ -625,12 +625,42 @@ Foundapic: mpinit(); } +static void +acpireset(void) +{ + uchar *p; + Tbl *t; + int i; + + /* stop application processors */ + mpshutdown(); + + /* locate and write platform reset register */ + for(i=0; i < ntblmap; i++){ + t = tblmap[i]; + if(memcmp(t->sig, "FACP", 4) != 0) + continue; + if(get32(t->len) <= 128) + break; + p = (uchar*)t; + if((get32(p + 112) & (1<<10)) == 0) + break; + if(p[116+0] != IoSpace) + break; + outb(get32(p+116+4), p[128]); + break; + } + + /* acpi shutdown failed, try generic reset */ + archreset(); +} + static int identify(void); PCArch archacpi = { .id= "ACPI", .ident= identify, -.reset= mpshutdown, +.reset= acpireset, .intrinit= acpiinit, .intrenable= mpintrenable, .intron= lapicintron, @@ -887,29 +917,3 @@ amldelay(int us) { microdelay(us); } - -/* - * reset machine by writing acpi reset register. - */ -void -acpireset(void) -{ - uchar *p; - Tbl *t; - int i; - - for(i=0; i < ntblmap; i++){ - t = tblmap[i]; - if(memcmp(t->sig, "FACP", 4) != 0) - continue; - if(get32(t->len) <= 128) - break; - p = (uchar*)t; - if((get32(p + 112) & (1<<10)) == 0) - break; - if(p[116+0] != IoSpace) - break; - outb(get32(p+116+4), p[128]); - break; - } -} diff --git a/sys/src/9/pc/archmp.c b/sys/src/9/pc/archmp.c index 8fb269569..723433db8 100644 --- a/sys/src/9/pc/archmp.c +++ b/sys/src/9/pc/archmp.c @@ -354,12 +354,22 @@ pcmpinit(void) mpinit(); } +static void +mpreset(void) +{ + /* stop application processors */ + mpshutdown(); + + /* do generic reset */ + archreset(); +} + static int identify(void); PCArch archmp = { .id= "_MP_", .ident= identify, -.reset= mpshutdown, +.reset= mpreset, .intrinit= pcmpinit, .intrenable= mpintrenable, .intron= lapicintron, diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index 412ca767e..24c5f0e7b 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -528,7 +528,7 @@ nop(void) { } -static void +void archreset(void) { i8042reset(); @@ -548,6 +548,7 @@ archreset(void) outb(0xcf9, 0x02); outb(0xcf9, 0x06); + print("can't reset\n"); for(;;) idle(); } diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h index ccf5ea092..77eebd2fc 100644 --- a/sys/src/9/pc/fns.h +++ b/sys/src/9/pc/fns.h @@ -1,9 +1,9 @@ #include "../port/portfns.h" void aamloop(int); -void acpireset(void); Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong)); void archinit(void); +void archreset(void); int bios32call(BIOS32ci*, u16int[3]); int bios32ci(BIOS32si*, BIOS32ci*); void bios32close(BIOS32si*); diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index 857c918cb..9d95c9f8a 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -121,7 +121,6 @@ options(void) } } -extern void mmuinit0(void); extern void (*i8237alloc)(void); extern void bootscreeninit(void); @@ -138,8 +137,6 @@ main(void) print("\nPlan 9\n"); trapinit0(); - mmuinit0(); - kbdinit(); i8253init(); cpuidentify(); @@ -908,8 +905,8 @@ shutdown(int ispanic) once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), - * which calls shutdown(0) and arch->reset(), which on mp systems is - * mpshutdown, from which there is no return: the processor is idled + * which calls shutdown(0) and arch->reset(), which on mp systems calls + * mpshutdown(), from which there is no return: the processor is idled * or initiates a reboot. clearing our bit in machs avoids calling * exit(0) from hzclock() on this processor. */ diff --git a/sys/src/9/pc/mmu.c b/sys/src/9/pc/mmu.c index 6fbc323af..0994d7be2 100644 --- a/sys/src/9/pc/mmu.c +++ b/sys/src/9/pc/mmu.c @@ -67,12 +67,6 @@ static void memglobal(void); #define vpd (vpt+VPTX(VPT)) void -mmuinit0(void) -{ - memmove(m->gdt, gdt, sizeof gdt); -} - -void mmuinit(void) { ulong x, *p; diff --git a/sys/src/9/pc/mp.c b/sys/src/9/pc/mp.c index 63fe687fa..8bfc52204 100644 --- a/sys/src/9/pc/mp.c +++ b/sys/src/9/pc/mp.c @@ -562,7 +562,6 @@ mpintrenable(Vctl* v) return -1; } - void mpshutdown(void) { @@ -572,7 +571,7 @@ mpshutdown(void) if(m->machno != 0){ splhi(); arch->introff(); - idle(); + for(;;) idle(); } print("mpshutdown: active = %#8.8ux\n", active.machs); @@ -585,24 +584,4 @@ mpshutdown(void) lapicicrw(0, 0x000C0000|ApicINIT); pcireset(); - acpireset(); - i8042reset(); - - /* - * Often the BIOS hangs during restart if a conventional 8042 - * warm-boot sequence is tried. The following is Intel specific and - * seems to perform a cold-boot, but at least it comes back. - * And sometimes there is no keyboard... - * - * The reset register (0xcf9) is usually in one of the bridge - * chips. The actual location and sequence could be extracted from - * ACPI but why bother, this is the end of the line anyway. - */ - print("no kbd; trying bios warm boot..."); - *(ushort*)KADDR(0x472) = 0x1234; /* BIOS warm-boot flag */ - outb(0xCF9, 0x02); - outb(0xCF9, 0x06); - - print("can't reset\n"); - idle(); } diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h index 652d07737..0af15138f 100644 --- a/sys/src/9/pc64/fns.h +++ b/sys/src/9/pc64/fns.h @@ -1,9 +1,9 @@ #include "../port/portfns.h" void aamloop(int); -void acpireset(void); Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,void*,long,vlong)); void archinit(void); +void archreset(void); int bios32call(BIOS32ci*, u16int[3]); int bios32ci(BIOS32si*, BIOS32ci*); void bios32close(BIOS32si*); diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index ee67d0b52..087450c55 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -537,8 +537,8 @@ shutdown(int ispanic) once = active.machs & (1<<m->machno); /* * setting exiting will make hzclock() on each processor call exit(0), - * which calls shutdown(0) and arch->reset(), which on mp systems is - * mpshutdown, from which there is no return: the processor is idled + * which calls shutdown(0) and arch->reset(), which on mp systems calls + * mpshutdown(), from which there is no return: the processor is idled * or initiates a reboot. clearing our bit in machs avoids calling * exit(0) from hzclock() on this processor. */ diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64 index 0512bec61..9270ac820 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -28,7 +28,7 @@ dev sd # floppy dma -# aoe + aoe # lpt audio dma @@ -87,7 +87,7 @@ misc archmp mp apic squidboy mtrr -# sdaoe + sdaoe sdide pci sdscsi # sd53c8xx pci sdscsi # sdmylex pci sdscsi @@ -95,7 +95,7 @@ misc # sdodin pci sdscsi led sdvirtio pci sdscsi sdmmc pci pmmc -# sdloop + sdloop uarti8250 # uartisa diff --git a/sys/src/9/pc64/pccpu64 b/sys/src/9/pc64/pccpu64 index ef82503d3..d9f556499 100644 --- a/sys/src/9/pc64/pccpu64 +++ b/sys/src/9/pc64/pccpu64 @@ -28,7 +28,7 @@ dev sd # floppy dma -# aoe + aoe # lpt audio dma @@ -87,15 +87,15 @@ misc archmp mp apic squidboy mtrr -# sdaoe + sdaoe sdide pci sdscsi # sd53c8xx pci sdscsi # sdmylex pci sdscsi sdiahci pci sdscsi led # sdodin pci sdscsi led sdvirtio pci sdscsi -# sdmmc pci pmmc -# sdloop + sdmmc pci pmmc + sdloop uarti8250 # uartisa diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index 478e29f3d..45c3959b3 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -389,7 +389,6 @@ extern void checkmmu(uintptr, uintptr); void checkpages(void) { - int checked; uintptr addr, off; Pte *p; Page *pg; @@ -398,7 +397,6 @@ checkpages(void) if(up == nil) return; - checked = 0; for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){ if((s = *sp) == nil) continue; @@ -411,9 +409,7 @@ checkpages(void) if(pagedout(pg)) continue; checkmmu(addr, pg->pa); - checked++; } qunlock(s); } - print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked); } diff --git a/sys/src/9/port/sdaoe.c b/sys/src/9/port/sdaoe.c index 90259705d..7c3c7bf67 100644 --- a/sys/src/9/port/sdaoe.c +++ b/sys/src/9/port/sdaoe.c @@ -249,19 +249,6 @@ static char *probef[32]; static char *probebuf; static int nprobe; -static int -pnpprobeid(char *s) -{ - int id; - - if(strlen(s) < 2) - return 0; - id = 'e'; - if(s[1] == '!') - id = s[0]; - return id; -} - static SDev* aoepnp(void) { @@ -275,9 +262,26 @@ aoepnp(void) nprobe = tokenize(probebuf, probef, nelem(probef)); h = t = 0; for(i = 0; i < nprobe; i++){ - id = pnpprobeid(probef[i]); - if(id == 0) + p = probef[i]; + if(strlen(p) < 2) continue; + id = 'e'; + if(p[1] == '!'){ + id = p[0]; + p += 2; + } + /* + * shorthand for: id!lun -> id!#æ/aoe/lun + * because we cannot type æ in the bootloader console. + */ + if(strchr(p, '/') == nil){ + char tmp[64]; + + snprint(tmp, sizeof(tmp), "%c!#æ/aoe/%s", (char)id, p); + + probef[i] = nil; + kstrdup(&probef[i], tmp); + } s = malloc(sizeof *s); if(s == nil) break; diff --git a/sys/src/9/port/sdloop.c b/sys/src/9/port/sdloop.c index 80118369d..49ea6886d 100644 --- a/sys/src/9/port/sdloop.c +++ b/sys/src/9/port/sdloop.c @@ -14,9 +14,6 @@ #include "../port/netif.h" extern char Echange[]; -extern char Enotup[]; - -#define uprint(...) snprint(up->genbuf, sizeof up->genbuf, __VA_ARGS__); enum { Maxpath = 256, @@ -302,7 +299,7 @@ loopbio(SDunit *u, int, int write, void *a, long count, uvlong lba) if(waserror()){ if(strcmp(up->errstr, Echange) == 0 || - strcmp(up->errstr, Enotup) == 0) + strstr(up->errstr, "device is down") != nil) u->sectors = 0; nexterror(); } diff --git a/sys/src/9/port/xalloc.c b/sys/src/9/port/xalloc.c index 15a5327e6..6db734160 100644 --- a/sys/src/9/port/xalloc.c +++ b/sys/src/9/port/xalloc.c @@ -242,7 +242,7 @@ xhole(uintptr addr, uintptr size) if(xlists.flist == nil) { iunlock(&xlists); - print("xfree: no free holes, leaked %p bytes\n", size); + print("xfree: no free holes, leaked %llud bytes\n", (uvlong)size); return; } @@ -270,8 +270,8 @@ xsummary(void) s = 0; for(h = xlists.table; h; h = h->link) { - print("%#p %#p %p\n", h->addr, h->top, h->size); + print("%#8.8p %#8.8p %llud\n", h->addr, h->top, (uvlong)h->size); s += h->size; } - print("%lld bytes free\n", (vlong)s); + print("%llud bytes free\n", (uvlong)s); } diff --git a/sys/src/9/xen/fns.h b/sys/src/9/xen/fns.h index 3659354fa..71e64ac4c 100644 --- a/sys/src/9/xen/fns.h +++ b/sys/src/9/xen/fns.h @@ -4,8 +4,6 @@ Dirtab* addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,v void archinit(void); void bootargs(ulong); ulong cankaddr(ulong); -int cistrcmp(char*, char*); -int cistrncmp(char*, char*, int); #define clearmmucache() /* x86 doesn't have one */ void clockintr(Ureg*, void*); int (*cmpswap)(long*, long, long); @@ -63,10 +61,7 @@ void ioinit(void); int isaconfig(char*, int, ISAConf*); void kbdenable(void); #define kmapinval() -void lgdt(ushort[3]); // XXX remove and in l.s -void lidt(ushort[3]); // XXX remove and in l.s void links(void); -void ltr(ulong); // XXX remove? void mach0init(void); void mathinit(void); void mb386(void); diff --git a/sys/src/9/xen/l.s b/sys/src/9/xen/l.s index ff9515c33..dbfbf248e 100644 --- a/sys/src/9/xen/l.s +++ b/sys/src/9/xen/l.s @@ -54,25 +54,6 @@ _idle: * CR4 and the 'model specific registers' should only be read/written * after it has been determined the processor supports them */ -TEXT lgdt(SB), $0 /* GDTR - global descriptor table */ - MOVL gdtptr+0(FP), AX - MOVL (AX), GDTR - RET - -TEXT lidt(SB), $0 /* IDTR - interrupt descriptor table */ - MOVL idtptr+0(FP), AX - MOVL (AX), IDTR - RET - -TEXT ltr(SB), $0 /* TR - task register */ - MOVL tptr+0(FP), AX - MOVW AX, TASK - RET - -TEXT rtsr(SB), $0 - MOVW TASK, AX - RET - TEXT _cycles(SB), $0 /* time stamp counter; cycles since power up */ RDTSC MOVL vlong+0(FP), CX /* &vlong */ @@ -88,13 +69,9 @@ TEXT rdmsr(SB), $0 /* model-specific register */ MOVL DX, 4(CX) /* hi */ RET +/* Xen doesn't let us do this */ TEXT wrmsr(SB), $0 - MOVL index+0(FP), CX - MOVL lo+4(FP), AX - MOVL hi+8(FP), DX -/* Xen doesn't let us do this - WRMSR - */ + MOVL $-1, AX RET /* diff --git a/sys/src/9/xen/main.c b/sys/src/9/xen/main.c index cc06a4306..2cc4e2ca6 100644 --- a/sys/src/9/xen/main.c +++ b/sys/src/9/xen/main.c @@ -118,9 +118,6 @@ mach0init(void) conf.nmach = 1; MACHP(0) = (Mach*)CPU0MACH; m->pdb = (ulong*)xenstart->pt_base; -#ifdef NOT - m->gdt = (Segdesc*)CPU0GDT; -#endif machinit(); @@ -133,15 +130,12 @@ machinit(void) { int machno; ulong *pdb; - Segdesc *gdt; machno = m->machno; pdb = m->pdb; - gdt = m->gdt; memset(m, 0, sizeof(Mach)); m->machno = machno; m->pdb = pdb; - m->gdt = gdt; m->perf.period = 1; /* @@ -585,16 +579,6 @@ procfork(Proc *p) p->kentry = up->kentry; p->pcycles = -p->kentry; - /* inherit user descriptors */ - memmove(p->gdt, up->gdt, sizeof(p->gdt)); - - /* copy local descriptor table */ - if(up->ldt != nil && up->nldt > 0){ - p->ldt = smalloc(sizeof(Segdesc) * up->nldt); - memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt); - p->nldt = up->nldt; - } - /* save floating point state */ s = splhi(); switch(up->fpstate & ~FPillegal){ @@ -750,51 +734,3 @@ exit(int ispanic) shutdown(ispanic); arch->reset(); } - -int -cistrcmp(char *a, char *b) -{ - int ac, bc; - - for(;;){ - ac = *a++; - bc = *b++; - - if(ac >= 'A' && ac <= 'Z') - ac = 'a' + (ac - 'A'); - if(bc >= 'A' && bc <= 'Z') - bc = 'a' + (bc - 'A'); - ac -= bc; - if(ac) - return ac; - if(bc == 0) - break; - } - return 0; -} - -int -cistrncmp(char *a, char *b, int n) -{ - unsigned ac, bc; - - while(n > 0){ - ac = *a++; - bc = *b++; - n--; - - if(ac >= 'A' && ac <= 'Z') - ac = 'a' + (ac - 'A'); - if(bc >= 'A' && bc <= 'Z') - bc = 'a' + (bc - 'A'); - - ac -= bc; - if(ac) - return ac; - if(bc == 0) - break; - } - - return 0; -} - diff --git a/sys/src/9/xen/mem.h b/sys/src/9/xen/mem.h index d0b3cc356..c4a6886ef 100644 --- a/sys/src/9/xen/mem.h +++ b/sys/src/9/xen/mem.h @@ -63,67 +63,14 @@ /* * known x86 segments (in GDT) and their selectors + * using the selectors that xen gives us. */ -#define NULLSEG 0 /* null segment */ -#define KDSEG 1 /* kernel data/stack */ -#define KESEG 2 /* kernel executable */ -#define UDSEG 3 /* user data/stack */ -#define UESEG 4 /* user executable */ -#define TSSSEG 5 /* task segment */ -#define APMCSEG 6 /* APM code segment */ -#define APMCSEG16 7 /* APM 16-bit code segment */ -#define APMDSEG 8 /* APM data segment */ -#define PROCSEG0 11 /* per process descriptor0 */ -#define NPROCSEG 3 /* number of per process descriptors */ -#define NGDT 13 /* number of GDT entries required */ -/* #define APM40SEG 8 /* APM segment 0x40 */ - -#define SELGDT (0<<2) /* selector is in gdt */ -#define SELLDT (1<<2) /* selector is in ldt */ - -#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p)) - -#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0) -/* these are replaced by XEN entries */ -#ifdef NOPE // XXX investigate more -#define KDSEL SELECTOR(KDSEG, SELGDT, 0) -#define KESEL SELECTOR(KESEG, SELGDT, 0) -#define UESEL SELECTOR(UESEG, SELGDT, 3) -#define UDSEL SELECTOR(UDSEG, SELGDT, 3) -/* comment out to make sure unused ... */ - -#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0) -#define APMCSEL SELECTOR(APMCSEG, SELGDT, 0) -#define APMCSEL16 SELECTOR(APMCSEG16, SELGDT, 0) -#define APMDSEL SELECTOR(APMDSEG, SELGDT, 0) -/* #define APM40SEL SELECTOR(APM40SEG, SELGDT, 0) */ -#else -/* use the selectors that xen gives us */ #define KESEL FLAT_KERNEL_CS #define KDSEL FLAT_KERNEL_DS #define UESEL FLAT_USER_CS #define UDSEL FLAT_USER_DS -#endif - -/* - * fields in segment descriptors - */ -#define SEGDATA (0x10<<8) /* data/stack segment */ -#define SEGEXEC (0x18<<8) /* executable segment */ -#define SEGTSS (0x9<<8) /* TSS segment */ -#define SEGCG (0x0C<<8) /* call gate */ -#define SEGIG (0x0E<<8) /* interrupt gate */ -#define SEGTG (0x0F<<8) /* trap gate */ -#define SEGTYPE (0x1F<<8) -#define SEGP (1<<15) /* segment present */ -#define SEGPL(x) ((x)<<13) /* priority level */ -#define SEGB (1<<22) /* granularity 1==4k (for expand-down) */ -#define SEGG (1<<23) /* granularity 1==4k (for other) */ -#define SEGE (1<<10) /* expand down */ -#define SEGW (1<<9) /* writable (for data/stack) */ -#define SEGR (1<<9) /* readable (for code) */ -#define SEGD (1<<22) /* default 1==32bit (for code) */ +#define NPROCSEG 1 /* number of per process descriptors */ /* * virtual MMU diff --git a/sys/src/9/xen/mmu.c b/sys/src/9/xen/mmu.c index cd51b47ff..9adc9cfea 100644 --- a/sys/src/9/xen/mmu.c +++ b/sys/src/9/xen/mmu.c @@ -13,35 +13,10 @@ uvlong *xenpdpt; /* this needs to go in Mach for multiprocessor guest */ #define MFN(pa) (patomfn[(pa)>>PGSHIFT]) #define MAPPN(x) (paemode? matopfn[*(uvlong*)(&x)>>PGSHIFT]<<PGSHIFT : matopfn[(x)>>PGSHIFT]<<PGSHIFT) -#define DATASEGM(p) { 0xFFFF, SEGG|SEGB|(0xF<<16)|SEGP|SEGPL(p)|SEGDATA|SEGW } -#define EXECSEGM(p) { 0xFFFF, SEGG|SEGD|(0xF<<16)|SEGP|SEGPL(p)|SEGEXEC|SEGR } -#define TSSSEGM(b,p) { ((b)<<16)|sizeof(Tss),\ - ((b)&0xFF000000)|(((b)>>16)&0xFF)|SEGTSS|SEGPL(p)|SEGP } - -Segdesc gdt[NGDT] = -{ -[NULLSEG] { 0, 0}, /* null descriptor */ -[KDSEG] DATASEGM(0), /* kernel data/stack */ -[KESEG] EXECSEGM(0), /* kernel code */ -[UDSEG] DATASEGM(3), /* user data/stack */ -[UESEG] EXECSEGM(3), /* user code */ -[TSSSEG] TSSSEGM(0,0), /* tss segment */ -}; - /* note: pdb must already be pinned */ static void taskswitch(Page *pdb, ulong stack) { - Tss *tss; - - tss = m->tss; - tss->ss0 = KDSEL; - tss->esp0 = stack; - tss->ss1 = KDSEL; - tss->esp1 = stack; - tss->ss2 = KDSEL; - tss->esp2 = stack; - //tss->cr3 = pdb; HYPERVISOR_stack_switch(KDSEL, stack); mmuflushtlb(pdb); } @@ -164,10 +139,7 @@ mmumapcpu0(void) void mmuinit(void) { -//XXX ulong x; -//XXX ushort ptr[3]; ulong *pte, npgs, pa; - extern int rtsr(void); if(paemode){ int i; @@ -193,39 +165,6 @@ mmuinit(void) memglobal(); - m->tss = malloc(sizeof(Tss)); - memset(m->tss, 0, sizeof(Tss)); - m->tss->iomap = 0xDFFF<<16; - - /* - * We used to keep the GDT in the Mach structure, but it - * turns out that that slows down access to the rest of the - * page. Since the Mach structure is accessed quite often, - * it pays off anywhere from a factor of 1.25 to 2 on real - * hardware to separate them (the AMDs are more sensitive - * than Intels in this regard). Under VMware it pays off - * a factor of about 10 to 100. - */ - -#ifdef we_dont_set_gdt_or_lidt - memmove(m->gdt, gdt, sizeof gdt); - x = (ulong)m->tss; - m->gdt[TSSSEG].d0 = (x<<16)|sizeof(Tss); - m->gdt[TSSSEG].d1 = (x&0xFF000000)|((x>>16)&0xFF)|SEGTSS|SEGPL(0)|SEGP; - - ptr[0] = sizeof(gdt)-1; - x = (ulong)m->gdt; - ptr[1] = x & 0xFFFF; - ptr[2] = (x>>16) & 0xFFFF; - lgdt(ptr); - - ptr[0] = sizeof(Segdesc)*256-1; - x = IDTADDR; - ptr[1] = x & 0xFFFF; - ptr[2] = (x>>16) & 0xFFFF; - lidt(ptr); -#endif - #ifdef we_may_eventually_want_this /* make kernel text unwritable */ for(x = KTZERO; x < (ulong)etext; x += BY2PG){ @@ -237,9 +176,6 @@ mmuinit(void) #endif taskswitch(0, (ulong)m + BY2PG); -#ifdef we_dont_do_this - ltr(TSSSEL); -#endif } void diff --git a/sys/src/cmd/acme/text.c b/sys/src/cmd/acme/text.c index 957bca37d..7380d0163 100644 --- a/sys/src/cmd/acme/text.c +++ b/sys/src/cmd/acme/text.c @@ -643,8 +643,6 @@ texttype(Text *t, Rune r) Rune *rp; Text *u; - if(t->what!=Body && r=='\n') - return; nr = 1; rp = &r; switch(r){ @@ -670,7 +668,8 @@ texttype(Text *t, Rune r) n = 2*t->maxlines/3; case_Down: q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); - textsetorigin(t, q0, TRUE); + if(t->what == Body) + textsetorigin(t, q0, TRUE); return; case Kup: n = t->maxlines/3; @@ -682,7 +681,8 @@ texttype(Text *t, Rune r) n = 2*t->maxlines/3; case_Up: q0 = textbacknl(t, t->org, n); - textsetorigin(t, q0, TRUE); + if(t->what == Body) + textsetorigin(t, q0, TRUE); return; case Khome: typecommit(t); @@ -776,7 +776,7 @@ texttype(Text *t, Rune r) textfill(t->file->text[i]); return; case '\n': - if(t->w->autoindent){ + if(t->what == Body && t->w->autoindent){ /* find beginning of previous line using backspace code */ nnb = textbswidth(t, 0x15); /* ^U case */ rp = runemalloc(nnb + 1); diff --git a/sys/src/cmd/disk/mkfile b/sys/src/cmd/disk/mkfile index c762df038..7acb0fcef 100644 --- a/sys/src/cmd/disk/mkfile +++ b/sys/src/cmd/disk/mkfile @@ -14,6 +14,7 @@ DIRS=\ prep\ smart\ # sacfs\ + vblade\ OFILES= diff --git a/sys/src/cmd/disk/vblade/aoe.h b/sys/src/cmd/disk/vblade/aoe.h new file mode 100644 index 000000000..1a9592a22 --- /dev/null +++ b/sys/src/cmd/disk/vblade/aoe.h @@ -0,0 +1,70 @@ +enum{ + ACata, + ACconfig, +}; + +enum{ + AQCread, + AQCtest, + AQCprefix, + AQCset, + AQCfset, +}; + +enum{ + AEcmd = 1, + AEarg, + AEdev, + AEcfg, + AEver, +}; + +enum{ + Aoetype = 0x88a2, + Aoesectsz = 512, + Aoemaxcfg = 1024, + + Aoehsz = 24, + Aoeatasz = 12, + Aoecfgsz = 8, + Aoerrsz = 2, + Aoemsz = 4, + Aoemdsz = 8, + + Aoever = 1, + + AFerr = 1<<2, + AFrsp = 1<<3, + + AAFwrite = 1, + AAFext = 1<<6, +}; + +typedef struct{ + uchar dst[Eaddrlen]; + uchar src[Eaddrlen]; + uchar type[2]; + uchar verflag; + uchar error; + uchar major[2]; + uchar minor; + uchar cmd; + uchar tag[4]; +}Aoehdr; + +typedef struct{ + uchar aflag; + uchar errfeat; + uchar scnt; + uchar cmdstat; + uchar lba[6]; + uchar res[2]; +}Aoeata; + +typedef struct{ + uchar bufcnt[2]; + uchar fwver[2]; + uchar scnt; + uchar verccmd; + uchar cslen[2]; +}Aoeqc; diff --git a/sys/src/cmd/disk/vblade/mkfile b/sys/src/cmd/disk/vblade/mkfile new file mode 100644 index 000000000..a03a7d0ef --- /dev/null +++ b/sys/src/cmd/disk/vblade/mkfile @@ -0,0 +1,12 @@ +</$objtype/mkfile + +TARG=vblade + +OFILES=\ + vblade.$O\ + +HFILES=aoe.h + +BIN=/$objtype/bin/disk + +</sys/src/cmd/mkone diff --git a/sys/src/cmd/disk/vblade/vblade.c b/sys/src/cmd/disk/vblade/vblade.c new file mode 100644 index 000000000..fac1abe33 --- /dev/null +++ b/sys/src/cmd/disk/vblade/vblade.c @@ -0,0 +1,666 @@ +/* + * vblade -- virtual aoe target + * copyright © 2007 erik quanstrom + */ + +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <ip.h> /* irony */ +#include <fis.h> + +enum { + Eaddrlen = 6, /* only defined in kernel */ +}; +#include "aoe.h" + +enum { + Fclone, + Fdata, + Flast, + + Fraw = 1<<0, + + Nether = 8, + Nvblade = 8, + Maxpkt = 10000, + Hdrlba = 128, + Conflen = 1024, +}; + +typedef struct { + int iflag; + int flag; + int shelf; + int slot; + uvlong maxlba; + char *config; +} Conf; + +typedef struct { + char magic[32]; + char size[32]; + char address[16]; + char configlen[6]; + char pad[512-32-32-16-6]; + char config[Conflen]; +} Vbhdr; + +typedef struct { + Vbhdr hdr; + vlong maxlba; + vlong hdrsz; + int shelf; + int slot; + int clen; + int flag; + int fd; +} Vblade; + +static Vblade vblade[Nvblade]; +static int nblade; + +static char *ethertab[Nether] = { + "/net/ether0", +}; +static int etheridx = 1; +static int efdtab[Nether*Flast]; +static char pkttab[Nether][Maxpkt]; +static char bctab[Nether][Maxpkt]; +static int mtutab[Nether]; +static char Magic[] = "aoe vblade\n"; + +static int +getmtu(char *p) +{ + char buf[50]; + int fd, mtu; + + snprint(buf, sizeof buf, "%s/mtu", p); + if((fd = open(buf, OREAD)) == -1) + return 2; + if(read(fd, buf, 36) < 0) + return 2; + close(fd); + buf[36] = 0; + mtu = strtoul(buf+12, 0, 0)-Aoehsz; + return mtu>>9; +} + +int +parseshelf(char *s, int *shelf, int *slot) +{ + int a, b; + + a = strtoul(s, &s, 0); + if(*s++ != '.') + return -1; + b = strtoul(s, &s, 0); + if(*s != 0) + return -1; + *shelf = a; + *slot = b; + return 0; +} + +static vlong +getsize(char *s) +{ + static char tab[] = "ptgmk"; + char *p; + vlong v; + + v = strtoull(s, &s, 0); + while((p = strchr(tab, *s++)) && *p) + while(*p++) + v *= 1024; + if(s[-1]) + return -1; + return v; +} + +vlong +sizetolba(vlong size) +{ + if(size < 512 || size & 0x1ff){ + fprint(2, "invalid size %lld\n", size); + exits("size"); + } + return size>>9; +} + +static int +savevblade(int fd, Vblade *vb) +{ + int n, r; + char *p; + + sprint(vb->hdr.size, "%lld", vb->maxlba<<9); + sprint(vb->hdr.address, "%d.%d", vb->shelf, vb->slot); + sprint(vb->hdr.configlen, "%d", vb->clen); + + if(vb->flag & Fraw) + return 0; + p = (char*)vb; + for(n = 0; n < sizeof *vb; n += r) + if((r = pwrite(fd, p+n, sizeof *vb-n, n)) <= 0) + break; + if(n != sizeof *vb) + return -1; + return 0; +} + +static char* +chkvblade(int fd, Vblade *vb) +{ + Vbhdr *h; + + h = &vb->hdr; + if(readn(fd, (char*)h, sizeof *h) != sizeof *h) + return "bad read"; + if(memcmp(h->magic, Magic, sizeof Magic)) + return "bad magic"; + h->size[sizeof h->size-1] = 0; + vb->maxlba = sizetolba(strtoull(h->size, 0, 0)); + if(parseshelf(h->address, &vb->shelf, &vb->slot) == -1) + return "bad shelf"; + h->configlen[sizeof h->configlen-1] = 0; + vb->clen = strtoul(h->configlen, 0, 0); + return 0; +} + +void +checkfile(char *s, Vblade *vb, int iflag) +{ + char *e; + + vb->fd = open(s, ORDWR); + if(vb->fd == -1) + sysfatal("can't open backing store: %r"); + if(iflag == 0 && (e = chkvblade(vb->fd, vb))) + sysfatal("invalid vblade %s", e); +} + +void +recheck(int fd, Vblade *vb) +{ + Dir *d; + vlong v; + + d = dirfstat(fd); + if(d == 0) + sysfatal("can't stat: %r"); + if((vb->flag & Fraw) == 0) + vb->hdrsz = Hdrlba; + v = sizetolba(d->length & ~0x1ff) - vb->hdrsz; + free(d); + if(vb->maxlba > v) + sysfatal("cmdline size too large (%lld sector overhead)", vb->hdrsz); + if(vb->maxlba == 0) + vb->maxlba = v; + + savevblade(fd, vb); +} + +int +aoeopen(char *e, int fds[]) +{ + char buf[128], ctl[13]; + int n; + + snprint(buf, sizeof buf, "%s/clone", e); + if((fds[Fclone] = open(buf, ORDWR)) == -1) + return -1; + memset(ctl, 0, sizeof ctl); + if(read(fds[Fclone], ctl, sizeof ctl - 1) < 0) + return -1; + n = atoi(ctl); + snprint(buf, sizeof buf, "connect %d", Aoetype); + if(write(fds[Fclone], buf, strlen(buf)) != strlen(buf)) + return -1; + snprint(buf, sizeof buf, "%s/%d/data", e, n); + fds[Fdata] = open(buf, ORDWR); + return fds[Fdata]; +} + +void +replyhdr(Aoehdr *h, Vblade *vblade) +{ + uchar ea[Eaddrlen]; + + memmove(ea, h->dst, Eaddrlen); + memmove(h->dst, h->src, Eaddrlen); + memmove(h->src, ea, Eaddrlen); + + hnputs(h->major, vblade->shelf); + h->minor = vblade->slot; + h->verflag |= AFrsp; +} + +static int +serveconfig(Aoehdr *h, Vblade *vb, int mtu) +{ + int cmd, reqlen, len; + char *cfg; + Aoeqc *q; + + if(memcmp(h->src, h->dst, Eaddrlen) == 0) + return -1; + + q = (Aoeqc*)((char*)h + Aoehsz); + reqlen = nhgets(q->cslen); + len = vb->clen; + cmd = q->verccmd&0xf; + cfg = (char*)q + Aoecfgsz; + + switch(cmd){ + case AQCtest: + if(reqlen != len) + return -1; + case AQCprefix: + if(reqlen > len) + return -1; + if(memcmp(vb->hdr.config, cfg, reqlen) != 0) + return -1; + case AQCread: + break; + case AQCset: + if(len && len != reqlen || memcmp(vb->hdr.config, cfg, reqlen) != 0){ + h->verflag |= AFerr; + h->error = AEcfg; + break; + } + case AQCfset: + if(reqlen > Conflen){ + h->verflag |= AFerr; + h->error = AEarg; + break; + } + memset(vb->hdr.config, 0, sizeof vb->hdr.config); + memmove(vb->hdr.config, cfg, reqlen); + vb->clen = len = reqlen; + savevblade(vb->fd, vb); + break; + default: + h->verflag |= AFerr; + h->error = AEarg; + } + + memmove(cfg, vb->hdr.config, len); + hnputs(q->cslen, len); + hnputs(q->bufcnt, 24); + q->scnt = mtu; + hnputs(q->fwver, 2323); + q->verccmd = Aoever<<4 | cmd; + + return Aoehsz+Aoecfgsz + len; +} + +static ushort ident[256] = { + [47] 0x8000, + [49] 0x0200, + [50] 0x4000, + [83] 0x5400, + [84] 0x4000, + [86] 0x1400, + [87] 0x4000, + [93] 0x400b, +}; + +static void +idmoveto(char *a, int idx, int len, char *s) +{ + char *p; + + p = a+idx*2; + for(; len > 0; len -= 2) { + if(*s == 0) + p[1] = ' '; + else + p[1] = *s++; + if (*s == 0) + p[0] = ' '; + else + p[0] = *s++; + p += 2; + } +} + +static void +lbamoveto(char *p, int idx, int n, vlong lba) +{ + int i; + + p += idx*2; + for(i = 0; i < n; i++) + *p++ = lba>>i*8; +} + +enum { + Crd = 0x20, + Crdext = 0x24, + Cwr = 0x30, + Cwrext = 0x34, + Cid = 0xec, +}; + +static uvlong +getlba(uchar *p) +{ + uvlong v; + + v = p[0]; + v |= p[1]<<8; + v |= p[2]<<16; + v |= p[3]<<24; + v |= (uvlong)p[4]<<32; + v |= (uvlong)p[5]<<40; + return v; +} + +static void +putlba(uchar *p, vlong lba) +{ + p[0] = lba; + p[1] = lba>>8; + p[2] = lba>>16; + p[3] = lba>>24; + p[5] = lba>>32; + p[6] = lba>>40; +} + +static int +serveata(Aoehdr *h, Vblade *vb, int mtu) +{ + Aoeata *a; + char *buf; + int rbytes, bytes, len; + vlong lba, off; + + a = (Aoeata*)((char*)h + Aoehsz); + buf = (char*)a + Aoeatasz; + lba = getlba(a->lba); + len = a->scnt<<9; + off = lba+vb->hdrsz<<9; + + rbytes = 0; + if(a->scnt > mtu || a->scnt == 0){ + h->verflag |= AFerr; + a->cmdstat = ASdrdy|ASerr; + h->error = AEarg; + goto out; + } + + if(a->cmdstat != Cid) + if(lba+a->scnt > vb->maxlba){ + a->errfeat = Eidnf; + a->cmdstat = ASdrdy|ASerr; + goto out; + } + + if(a->cmdstat&0xf0 == 0x20) + lba &= 0xfffffff; + switch(a->cmdstat){ + default: + a->errfeat = Eabrt; + a->cmdstat = ASdrdy|ASerr; + goto out; + case Cid: + memmove(buf, ident, sizeof ident); + idmoveto(buf, 27, 40, "Plan 9 Vblade"); + idmoveto(buf, 10, 20, "serial#"); + idmoveto(buf, 23, 8, "2"); + lbamoveto(buf, 60, 4, vb->maxlba); + lbamoveto(buf, 100, 8, vb->maxlba); + a->cmdstat = ASdrdy; + rbytes = 512; + goto out; + case Crd: + case Crdext: + bytes = pread(vb->fd, buf, len, off); + rbytes = bytes; + break; + case Cwr: + case Cwrext: + bytes = pwrite(vb->fd, buf, len, off); + break; + } + if(bytes != len){ + a->errfeat = Eabrt; + a->cmdstat = ASdf|ASerr; + putlba(a->lba, lba+(len-bytes)>>9); + rbytes = 0; + goto out; + } + + putlba(a->lba, lba+a->scnt); + a->scnt = 0; + a->errfeat = 0; + a->cmdstat = ASdrdy; +out: + return Aoehsz+Aoeatasz + rbytes; +} + +static int +myea(uchar ea[6], char *p) +{ + char buf[50]; + int fd; + + snprint(buf, sizeof buf, "%s/addr", p); + if((fd = open(buf, OREAD)) == -1) + return -1; + if(read(fd, buf, 12) < 12) + return -1; + close(fd); + return parseether(ea, buf); +} + +static void +bcastpkt(Aoehdr *h, uint shelf, uint slot, int i) +{ + myea(h->dst, ethertab[i]); + memset(h->src, 0xff, Eaddrlen); + hnputs(h->type, Aoetype); + hnputs(h->major, shelf); + h->minor = slot; + h->cmd = ACconfig; + h->tag[0] = h->tag[1] = h->tag[2] = h->tag[3] = 0; +} + +int +bladereply(Vblade *v, int i, int fd, char *pkt) +{ + int n; + Aoehdr *h; + + h = (Aoehdr*)pkt; + switch(h->cmd){ + case ACata: + n = serveata(h, v, mtutab[i]); + break; + case ACconfig: + n = serveconfig(h, v, mtutab[i]); + break; + default: + n = -1; + break; + } + if(n == -1) + return -1; + replyhdr(h, v); + if(n < 60){ + memset(pkt+n, 0, 60-n); + n = 60; + } + if(write(fd, h, n) != n){ + fprint(2, "write to %s failed: %r\n", ethertab[i]); + return -1; + } + return 0; +} + +void +serve(void *v) +{ + int i, j, popcnt, vec, n, s, efd; + char *pkt, *bcpkt; + Aoehdr *h; + +fmtinstall('E', eipfmt); + i = (int)(uintptr)v; + + efd = efdtab[i*Flast+Fdata]; + pkt = pkttab[i]; + bcpkt = bctab[i]; + + n = 60; + h = (Aoehdr*)pkt; + bcastpkt(h, 0xffff, 0xff, i); + goto start; + + for(;;){ + n = read(efd, pkt, Maxpkt); + start: + if(n < 60 || h->verflag & AFrsp) + continue; + s = nhgets(h->major); + popcnt = 0; + vec = 0; + for(j = 0; j < nblade; j++){ + if((vblade[j].shelf == s || s == 0xffff) + && (vblade[j].slot == h->minor || h->minor == 0xff)){ + popcnt++; + vec |= 1<<j; + } + } + for(j = 0; popcnt>0 && j < nblade; j++){ + if((vec & 1<<j) == 0) + continue; + if(popcnt>0){ + memcpy(bcpkt, pkt, n); + bladereply(vblade + j, i, efd, bcpkt); + }else + bladereply(vblade + j, i, efd, pkt); + popcnt--; + } + } +} + +void +launch(char *tab[], int fdtab[]) +{ + int i; + + for(i = 0; tab[i]; i++){ + if(aoeopen(tab[i], fdtab+Flast*i) < 0) + sysfatal("network open: %r"); + /* + * use proc not threads. otherwise we will block on read/write. + */ + proccreate(serve, (void*)i, 32*1024); + } +} + +void +usage(void) +{ + fprint(2, "vblade [-ir] [-s size] [-a shelf.slot] [-c config] [-e ether] file\n"); + exits("usage"); +} + +void +goblade(Vblade *vblade, char *file, Conf *c) +{ + char *anal; + + if(c->iflag == 1) + memcpy(vblade->hdr.magic, Magic, sizeof Magic); + checkfile(file, vblade, c->iflag); + + vblade->flag = c->flag; + if(c->shelf != -1){ + vblade->shelf = c->shelf; + vblade->slot = c->slot; + } + if(c->maxlba > 0) + vblade->maxlba = c->maxlba; + if(c->config != nil) + memmove(vblade->hdr.config, c->config, vblade->clen = strlen(c->config)); + + recheck(vblade->fd, vblade); + + anal = ""; + if(vblade->maxlba > 1) + anal = "s"; + fprint(2, "lblade %d.%d %lld sector%s\n", vblade->shelf, vblade->slot, vblade->maxlba, anal); +} + +void +threadmain(int argc, char **argv) +{ + int i, lastc, anye; + Conf c; + + anye = 0; + for(;;){ + if(nblade == nelem(vblade)) + sysfatal("too many blades"); + c = (Conf){0, 0, -1, -1, 0, nil}; + lastc = 0; + ARGBEGIN{ + case 'a': + lastc = 'a'; + if(parseshelf(EARGF(usage()), &c.shelf, &c.slot) == -1) + sysfatal("bad vblade address"); + break; + case 'c': + lastc = 'c'; + c.config = EARGF(usage()); + break; + case 'e': + lastc = 'e'; + if(anye++ == 0) + etheridx = 0; + if(etheridx == nelem(ethertab)) + sysfatal("too many interfaces"); + ethertab[etheridx++] = EARGF(usage()); + break; + case 'i': + lastc = 'i'; + c.iflag = 1; + break; + case 'r': + lastc = 'r'; + c.flag |= Fraw; + c.iflag = 1; + break; + case 's': + lastc = 's'; + c.maxlba = sizetolba(getsize(EARGF(usage()))); + break; + default: + lastc = '?'; + usage(); + }ARGEND; + + if(argc == 0 && lastc == 'e') + break; + if(argc == 0) + usage(); + goblade(vblade + nblade++, *argv, &c); + if(argc == 1) + break; + } + + if(nblade == 0) + usage(); + for(i = 0; i < etheridx; i++) + mtutab[i] = getmtu(ethertab[i]); + + launch(ethertab, efdtab); + + for(; sleep(1*1000) != -1;) + ; + threadexitsall("interrupted"); +} diff --git a/sys/src/libflate/inflatezlibblock.c b/sys/src/libflate/inflatezlibblock.c index 477bb4b01..54b2ca130 100644 --- a/sys/src/libflate/inflatezlibblock.c +++ b/sys/src/libflate/inflatezlibblock.c @@ -61,7 +61,7 @@ inflatezlibblock(uchar *dst, int dsize, uchar *src, int ssize) if(ok != FlateOk) return ok; - if(adler32(1, dst, bs.pos - dst) != ((bs.pos[0] << 24) | (bs.pos[1] << 16) | (bs.pos[2] << 8) | bs.pos[3])) + if(adler32(1, dst, bd.pos - dst) != ((bs.pos[0] << 24) | (bs.pos[1] << 16) | (bs.pos[2] << 8) | bs.pos[3])) return FlateCorrupted; return bd.pos - dst; |