Memory Map (S390)
From OSDev Wiki
The memory map on the S390 is very simple, the first 1024 (or 8192, if on z/Arch) bytes are used as PSA area. The IPL is loaded just after that said PSA.
Detecting memory
/* We are going to read in pairs of 1MiB and when we hit the memory limit we * will instantly catch the program exception and stop counting, then it's just * a matter of returning what we could count :) */ size_t s390_get_memsize( void) { const uint8_t *probe = (const uint8_t *)0x0; while(1) { int r; /* Do a "probe" read */ r = s390_address_is_valid(probe); if(r != 0) { kprintf("Done! %p\n", (uintptr_t)probe); break; } kprintf("Memory %p\n", (uintptr_t)probe); /* Go to next MiB */ probe += 1048576; } return (size_t)probe; }
Now there needs to be a function to "catch" the exceptions recognized by the processor:
/* Check if an address is valid - this only catches program exceptions to * determine if it's valid or not */ int s390_address_is_valid( volatile const void *probe) { int r = 0; S390_PSW_DEFAULT_TYPE old_pc_psw; #if (MACHINE >= M_ZARCH) struct s390x_psw pc_psw = { 0x00040000 | S390_PSW_AM64, S390_PSW_DEFAULT_AMBIT, 0, (uint32_t)&&invalid }; #else struct s390_psw pc_psw = { 0x000C0000, (uint32_t)&&invalid + S390_PSW_DEFAULT_AMBIT }; #endif #if (MACHINE >= M_ZARCH) memcpy(&old_pc_psw, (void *)S390_FLCEPNPSW, sizeof(struct s390x_psw)); memcpy((void *)S390_FLCEPNPSW, &pc_psw, sizeof(struct s390x_psw)); #else memcpy(&old_pc_psw, (void *)S390_FLCPNPSW, sizeof(struct s390_psw)); memcpy((void *)S390_FLCPNPSW, &pc_psw, sizeof(struct s390_psw)); #endif *((volatile const uint8_t *)probe); goto end; invalid: r = -1; end: #if (MACHINE >= M_ZARCH) memcpy((void *)S390_FLCEPNPSW, &old_pc_psw, sizeof(struct s390x_psw)); #else memcpy((void *)S390_FLCPNPSW, &old_pc_psw, sizeof(struct s390_psw)); #endif return r; }
Some C compilers are known to crash or even ABEND during compilation if addresses of labels are taken via the && operator, alternatively using direct high-level assembler syntax:
* HwCheckAddress * IN: * pointer to address to probe * ENTRY @ZHWCHKA @ZHWCHKA DS 0H SAVE (14,12),,@ZHWCHKA LR R12,R15 USING @ZHWCHKA,12 LR R11,R1 * CATCHPSW address on R1 L R1,=A(CATCHPSW) * Save address of TMPSAVE on R2 L R2,=A(TMPSAVE) * And FLCPNPSW on R3 L R3,FLCPNPSW * MVC 0(8,R2),0(R3) * ... use a new PSW to catch the exceptions MVC 0(8,R3),0(R1) * Probe the address, if it raises a PC exception then * we will simply catch it and return 1 L R1,0(R11) L R15,0(R1) * rc = 0 MVC 0(8,R3),0(R2) L R15,=F'0' RETURN (14,12),RC=(15) CATCHPCR DS 0H * rc = 1 MVC 0(8,R3),0(R2) L R15,=F'1' RETURN (14,12),RC=(15) LTORG DROP 12 * CATCHPSW DS 0D DC X'020E0000' DC A(AMBIT+CATCHPCR) TMPSAVE DS 1D